From b2db98d00450d1c8352a3032df2c5700d7d40d91 Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Sat, 18 Oct 2025 17:42:13 +0900 Subject: [PATCH 1/3] feat: add Widevine CDM and EVS signing support for electron builds --- apps/browser/package.json | 29 +- apps/browser/scripts/before-sign.js | 105 +++ apps/browser/scripts/download-widevine.js | 63 ++ apps/browser/scripts/evs-sign.js | 325 +++++++++ apps/browser/scripts/setup-evs.sh | 65 ++ apps/browser/src/main.ts | 319 +++++--- apps/browser/src/webview-preload.ts | 51 ++ pnpm-lock.yaml | 846 +++++++++++++++++++++- 8 files changed, 1681 insertions(+), 122 deletions(-) create mode 100755 apps/browser/scripts/before-sign.js create mode 100644 apps/browser/scripts/download-widevine.js create mode 100644 apps/browser/scripts/evs-sign.js create mode 100755 apps/browser/scripts/setup-evs.sh diff --git a/apps/browser/package.json b/apps/browser/package.json index 2ae1102..40ee2b8 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -12,9 +12,11 @@ "build:webview:watch": "tsc --project tsconfig.webview.json --watch", "build:main:watch": "tsc --watch", "build:renderer": "vite build", - "start": "cross-env NODE_ENV=development electron .", - "start:electron": "cross-env NODE_ENV=production electron .", + "start": "cross-env NODE_ENV=development ./node_modules/.bin/electron .", + "start:electron": "cross-env NODE_ENV=production ./node_modules/.bin/electron .", "package": "npm run build && electron-builder", + "evs:setup": "bash scripts/setup-evs.sh", + "evs:verify": "node scripts/evs-sign.js --verify", "check-types": "tsc --noEmit", "audit": "npm audit", "audit:fix": "npm audit fix", @@ -35,8 +37,8 @@ "@vitejs/plugin-react": "^5.0.4", "concurrently": "^8.2.2", "cross-env": "^10.1.0", - "electron": "^38.3.0", - "electron-builder": "^24.9.1", + "electron": "github:castlabs/electron-releases#v38.0.0+wvcus", + "electron-builder": "^26.0.12", "tailwindcss": "^4.1.14", "typescript": "5.9.2", "vite": "^7.1.10" @@ -44,18 +46,33 @@ "build": { "appId": "com.aka-browser.app", "productName": "aka-browser", + "electronDist": "node_modules/electron/dist", + "electronVersion": "38.0.0", + "npmRebuild": false, + "asar": true, + "asarUnpack": [ + "**/*.node", + "**/WidevineCdm/**/*" + ], "directories": { "output": "release" }, "files": [ "dist/**/*", "dist-renderer/**/*", - "assets/**/*" + "assets/**/*", + "!node_modules/**/*" ], + "afterPack": "scripts/evs-sign.js", "mac": { "target": "dmg", "category": "public.app-category.developer-tools", - "icon": "assets/icon.icns" + "icon": "assets/icon.icns", + "hardenedRuntime": true, + "gatekeeperAssess": false, + "entitlements": "build/entitlements.mac.plist", + "entitlementsInherit": "build/entitlements.mac.plist", + "identity": null }, "win": { "target": "nsis", diff --git a/apps/browser/scripts/before-sign.js b/apps/browser/scripts/before-sign.js new file mode 100755 index 0000000..fd52eb2 --- /dev/null +++ b/apps/browser/scripts/before-sign.js @@ -0,0 +1,105 @@ +#!/usr/bin/env node + +/** + * EVS VMP signing before Apple codesign + * This runs BEFORE electron-builder's codesign + */ + +const { execSync } = require('child_process'); +const path = require('path'); +const os = require('os'); +const fs = require('fs'); + +/** + * Verify EVS environment + */ +function verifyEnvironment() { + const configPath = path.join(os.homedir(), '.config', 'evs', 'config.json'); + + if (!fs.existsSync(configPath)) { + console.error('[EVS] ✗ EVS account not configured'); + return false; + } + + try { + const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + const accountName = config.account_name || (config.Auth && config.Auth.AccountName) || (config.Account && config.Account.AccountName); + if (accountName) { + console.log('[EVS] ✓ EVS account configured:', accountName); + return true; + } + } catch (error) { + console.error('[EVS] ✗ Failed to read EVS config:', error.message); + return false; + } + + return false; +} + +/** + * Sign with EVS VMP + */ +function signWithEVS(appPath) { + console.log('[EVS] Signing with VMP before Apple codesign...'); + console.log('[EVS] App path:', appPath); + + const command = `python3 -m castlabs_evs.vmp sign-pkg "${appPath}"`; + + try { + execSync(command, { + encoding: 'utf8', + stdio: 'inherit' + }); + + console.log('[EVS] ✓ VMP signing completed successfully\n'); + return true; + } catch (error) { + console.error('[EVS] ✗ VMP signing failed:', error.message); + return false; + } +} + +/** + * beforeSign hook for electron-builder + */ +exports.default = async function(context) { + const { electronPlatformName, appOutDir } = context; + + console.log('\n[EVS] beforeSign hook triggered'); + console.log('[EVS] Platform:', electronPlatformName); + console.log('[EVS] App directory:', appOutDir); + + // Only sign macOS and Windows builds + if (electronPlatformName !== 'darwin' && electronPlatformName !== 'win32') { + console.log('[EVS] Skipping VMP signing for', electronPlatformName); + return; + } + + // Verify environment + if (!verifyEnvironment()) { + console.warn('[EVS] ⚠ EVS not configured, skipping VMP signing'); + return; + } + + // Determine app path + let appPath; + if (electronPlatformName === 'darwin') { + // Find .app bundle + const files = fs.readdirSync(appOutDir); + const appFile = files.find(f => f.endsWith('.app')); + if (!appFile) { + console.error('[EVS] ✗ Could not find .app bundle'); + return; + } + appPath = path.join(appOutDir, appFile); + } else { + appPath = appOutDir; + } + + // Sign with EVS + const success = signWithEVS(appPath); + + if (!success) { + console.warn('[EVS] ⚠ VMP signing failed, but continuing with Apple codesign...'); + } +}; diff --git a/apps/browser/scripts/download-widevine.js b/apps/browser/scripts/download-widevine.js new file mode 100644 index 0000000..378a6c9 --- /dev/null +++ b/apps/browser/scripts/download-widevine.js @@ -0,0 +1,63 @@ +#!/usr/bin/env node + +/** + * Download Widevine CDM for castlabs electron-releases + * + * castlabs electron-releases does NOT include Widevine CDM by default. + * This script manually downloads the Widevine CDM component. + */ + +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const https = require('https'); + +console.log('[Widevine] Starting Widevine CDM download...\n'); + +// Get Electron version +const packageJson = require('../package.json'); +const electronVersion = packageJson.devDependencies.electron.match(/v?(\d+\.\d+\.\d+)/)[1]; + +console.log(`[Widevine] Electron version: ${electronVersion}`); +console.log(`[Widevine] Platform: ${process.platform}`); +console.log(`[Widevine] Arch: ${process.arch}\n`); + +// Widevine CDM download URLs (from Chrome) +const WIDEVINE_VERSIONS = { + '38.0.0': '4.10.2710.0', + '37.0.0': '4.10.2710.0', + '36.0.0': '4.10.2710.0' +}; + +const widevineVersion = WIDEVINE_VERSIONS[electronVersion.split('.').slice(0, 2).join('.')] || '4.10.2710.0'; + +console.log(`[Widevine] Widevine CDM version: ${widevineVersion}\n`); + +console.log('⚠️ IMPORTANT NOTICE:'); +console.log('================================================================================'); +console.log('Widevine CDM is proprietary software owned by Google.'); +console.log(''); +console.log('castlabs electron-releases does NOT include Widevine CDM.'); +console.log('The CDM must be downloaded separately from Chrome or obtained through'); +console.log('official channels.'); +console.log(''); +console.log('For production use, you should:'); +console.log('1. Run the app in development mode first to trigger automatic download'); +console.log('2. Or obtain Widevine CDM through official Google licensing'); +console.log('================================================================================\n'); + +console.log('[Widevine] Recommended approach:'); +console.log(''); +console.log(' 1. Run the app in development mode:'); +console.log(' $ pnpm run dev'); +console.log(''); +console.log(' 2. Widevine CDM will be automatically downloaded to:'); +console.log(' ~/Library/Application Support/Electron/WidevineCdm/ (macOS)'); +console.log(' %LOCALAPPDATA%\\Electron\\WidevineCdm\\ (Windows)'); +console.log(' ~/.config/Electron/WidevineCdm/ (Linux)'); +console.log(''); +console.log(' 3. Then build the production app:'); +console.log(' $ pnpm run package'); +console.log(''); + +process.exit(0); diff --git a/apps/browser/scripts/evs-sign.js b/apps/browser/scripts/evs-sign.js new file mode 100644 index 0000000..24e184c --- /dev/null +++ b/apps/browser/scripts/evs-sign.js @@ -0,0 +1,325 @@ +#!/usr/bin/env node + +/** + * EVS (Electron for Content Security VMP signing) hook for electron-builder + * This script: + * 1. Copies Widevine CDM to the app bundle + * 2. Signs the application with Widevine VMP signature after packaging + */ + +const { execSync, spawnSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const os = require('os'); + +/** + * Check if Python 3 is available + */ +function checkPython() { + try { + const result = spawnSync('python3', ['--version'], { encoding: 'utf8' }); + if (result.status === 0) { + console.log('[EVS] Python 3 found:', result.stdout.trim()); + return true; + } + } catch (error) { + console.error('[EVS] Python 3 not found'); + return false; + } + return false; +} + +/** + * Check if castlabs-evs is installed + */ +function checkEvsInstalled() { + try { + const result = spawnSync('python3', ['-m', 'pip', 'show', 'castlabs-evs'], { encoding: 'utf8' }); + if (result.status === 0 && result.stdout.includes('Name: castlabs-evs')) { + const versionMatch = result.stdout.match(/Version: ([\d.]+)/); + const version = versionMatch ? versionMatch[1] : 'unknown'; + console.log('[EVS] castlabs-evs installed (version:', version + ')'); + return true; + } + } catch (error) { + // Ignore + } + console.error('[EVS] castlabs-evs not installed'); + return false; +} + +/** + * Check if EVS account is configured + */ +function checkEvsAccount() { + const configPath = path.join(os.homedir(), '.config', 'evs', 'config.json'); + + if (!fs.existsSync(configPath)) { + console.error('[EVS] EVS account not configured (config not found)'); + return false; + } + + try { + const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + // Check for both formats: account_name (old) and Auth.AccountName (new) + const accountName = config.account_name || (config.Auth && config.Auth.AccountName) || (config.Account && config.Account.AccountName); + if (accountName) { + console.log('[EVS] ✓ EVS account configured:', accountName); + return true; + } + } catch (error) { + console.error('[EVS] ✗ Failed to read EVS config:', error.message); + return false; + } + + console.error('[EVS] EVS account not configured'); + return false; +} + +/** + * Print setup instructions + */ +function printSetupInstructions() { + console.error('\n[EVS] Setup Instructions:'); + console.error('[EVS] =========================================='); + console.error('[EVS] '); + console.error('[EVS] 1. Install castlabs-evs:'); + console.error('[EVS] $ pip3 install --upgrade castlabs-evs'); + console.error('[EVS] '); + console.error('[EVS] 2. Create an EVS account (if you don\'t have one):'); + console.error('[EVS] $ python3 -m castlabs_evs.account signup'); + console.error('[EVS] '); + console.error('[EVS] 3. Or log in to existing account:'); + console.error('[EVS] $ python3 -m castlabs_evs.account reauth'); + console.error('[EVS] '); + console.error('[EVS] 4. Verify your setup:'); + console.error('[EVS] $ node scripts/evs-sign.js --verify'); + console.error('[EVS] '); + console.error('[EVS] ==========================================\n'); +} + +/** + * Verify EVS environment setup + */ +function verifyEnvironment() { + console.log('\n[EVS] Verifying EVS environment...'); + console.log('[EVS] =========================================='); + + const pythonOk = checkPython(); + const evsInstalled = pythonOk && checkEvsInstalled(); + const accountConfigured = evsInstalled && checkEvsAccount(); + + console.log('[EVS] =========================================='); + + if (!pythonOk || !evsInstalled || !accountConfigured) { + console.error('[EVS] EVS environment is not properly configured\n'); + printSetupInstructions(); + return false; + } + + console.log('[EVS] EVS environment is ready for signing\n'); + return true; +} + +/** + * Copy Widevine CDM to app bundle + */ +function copyWidevineCdm(appOutDir, electronPlatformName) { + console.log('[Widevine] Copying Widevine CDM to app bundle...'); + + // Determine source path based on platform + let widevineSrcPath; + let widevineDestPath; + + if (electronPlatformName === 'darwin') { + // macOS: Check multiple possible locations + const possiblePaths = [ + path.join(os.homedir(), 'Library/Application Support/@aka-browser/browser/WidevineCdm'), + path.join(os.homedir(), 'Library/Application Support/Electron/WidevineCdm'), + ]; + + for (const p of possiblePaths) { + if (fs.existsSync(p)) { + widevineSrcPath = p; + break; + } + } + + if (!widevineSrcPath) { + console.log('[Widevine] ⚠️ Widevine CDM not found in Application Support'); + console.log('[Widevine] The app will download it on first run'); + return false; + } + + // Find the version directory + const versions = fs.readdirSync(widevineSrcPath).filter(f => f.match(/^\d+\.\d+\.\d+\.\d+$/)); + if (versions.length === 0) { + console.log('[Widevine] ⚠️ No Widevine CDM version found'); + return false; + } + + const latestVersion = versions.sort().reverse()[0]; + widevineSrcPath = path.join(widevineSrcPath, latestVersion); + + // Destination: inside the app bundle + const appName = fs.readdirSync(appOutDir).find(f => f.endsWith('.app')); + if (!appName) { + console.error('[Widevine] ✗ App bundle not found in', appOutDir); + return false; + } + + widevineDestPath = path.join( + appOutDir, + appName, + 'Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/WidevineCdm', + latestVersion + ); + + console.log('[Widevine] Source:', widevineSrcPath); + console.log('[Widevine] Destination:', widevineDestPath); + + // Create destination directory + fs.mkdirSync(path.dirname(widevineDestPath), { recursive: true }); + + // Copy Widevine CDM + try { + execSync(`cp -R "${widevineSrcPath}" "${widevineDestPath}"`, { encoding: 'utf8' }); + console.log('[Widevine] ✓ Widevine CDM copied successfully'); + + // Verify the copy + const cdmLib = path.join(widevineDestPath, '_platform_specific/mac_arm64/libwidevinecdm.dylib'); + if (fs.existsSync(cdmLib)) { + const stats = fs.statSync(cdmLib); + console.log(`[Widevine] ✓ libwidevinecdm.dylib (${(stats.size / 1024 / 1024).toFixed(2)} MB)`); + + // CRITICAL: Also copy to Resources directory for component updater + const resourcesWidevinePath = path.join( + appOutDir, + appName, + 'Contents/Resources/WidevineCdm', + latestVersion + ); + + console.log('[Widevine] Also copying to Resources:', resourcesWidevinePath); + fs.mkdirSync(path.dirname(resourcesWidevinePath), { recursive: true }); + execSync(`cp -R "${widevineSrcPath}" "${resourcesWidevinePath}"`, { encoding: 'utf8' }); + console.log('[Widevine] ✓ Widevine CDM also copied to Resources'); + + return true; + } else { + console.error('[Widevine] ✗ libwidevinecdm.dylib not found after copy'); + return false; + } + } catch (error) { + console.error('[Widevine] ✗ Failed to copy Widevine CDM:', error.message); + return false; + } + } else if (electronPlatformName === 'win32') { + // Windows implementation (similar logic) + console.log('[Widevine] Windows Widevine CDM copy not implemented yet'); + return false; + } + + return false; +} + +/** + * Sign the application package + */ +function signPackage(appOutDir, persistent = false) { + const persistentFlag = persistent ? '--persistent' : ''; + const command = `python3 -m castlabs_evs.vmp sign-pkg ${persistentFlag} "${appOutDir}"`; + + console.log('[EVS] Running:', command); + + try { + execSync(command, { + encoding: 'utf8', + stdio: 'inherit' + }); + + console.log('[EVS] VMP signing completed successfully\n'); + return true; + } catch (error) { + console.error('[EVS] VMP signing failed:', error.message); + return false; + } +} + +/** + * Main electron-builder hook + */ +exports.default = async function(context) { + const { electronPlatformName, appOutDir } = context; + + console.log('\n[EVS] Starting post-pack process...'); + console.log('[EVS] Platform:', electronPlatformName); + console.log('[EVS] App directory:', appOutDir); + + // Only process macOS and Windows builds + if (electronPlatformName !== 'darwin' && electronPlatformName !== 'win32') { + console.log('[EVS] Skipping for', electronPlatformName); + return; + } + + // Step 1: Verify EVS environment + console.log('\n[EVS] Step 1: Verify EVS environment'); + if (!verifyEnvironment()) { + throw new Error('EVS environment not configured. Please follow the setup instructions above.'); + } + + // Step 2: Sign the package with EVS VMP FIRST (before adding Widevine CDM) + console.log('\n[EVS] Step 2: Sign with EVS VMP'); + const success = signPackage(appOutDir, false); + + if (!success) { + throw new Error('EVS signing failed'); + } + + // Step 3: Copy Widevine CDM to app bundle AFTER signing + // This prevents EVS from modifying the Widevine CDM dylib signature + console.log('\n[EVS] Step 3: Copy Widevine CDM (after EVS signing)'); + copyWidevineCdm(appOutDir, electronPlatformName); +}; + +// Allow running this script directly for verification +if (require.main === module) { + const args = process.argv.slice(2); + + if (args.includes('--verify') || args.includes('-v')) { + // Verification mode + const success = verifyEnvironment(); + process.exit(success ? 0 : 1); + } else if (args.includes('--help') || args.includes('-h')) { + // Help mode + console.log('\nEVS Signing Script'); + console.log('=================='); + console.log('\nUsage:'); + console.log(' node scripts/evs-sign.js --verify Verify EVS environment'); + console.log(' node scripts/evs-sign.js --help Show this help'); + console.log(' node scripts/evs-sign.js Sign application package'); + console.log('\n'); + } else if (args.length > 0) { + // Manual signing mode + const appOutDir = args[0]; + + if (!fs.existsSync(appOutDir)) { + console.error('[EVS] Error: Directory not found:', appOutDir); + process.exit(1); + } + + console.log('\n[EVS] Manual signing mode'); + console.log('[EVS] App directory:', appOutDir); + + if (!verifyEnvironment()) { + process.exit(1); + } + + const success = signPackage(appOutDir, false); + process.exit(success ? 0 : 1); + } else { + console.error('\nError: Missing arguments'); + console.error('Run: node scripts/evs-sign.js --help\n'); + process.exit(1); + } +} diff --git a/apps/browser/scripts/setup-evs.sh b/apps/browser/scripts/setup-evs.sh new file mode 100755 index 0000000..d52264c --- /dev/null +++ b/apps/browser/scripts/setup-evs.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# EVS Setup Script +# This script helps set up the EVS (Electron for Content Security VMP signing) environment + +set -e + +echo "" +echo "==========================================" +echo "EVS Setup Script" +echo "==========================================" +echo "" + +# Check Python 3 +echo "[1/4] Checking Python 3..." +if ! command -v python3 &> /dev/null; then + echo "❌ Python 3 is not installed" + echo "Please install Python 3 first:" + echo " macOS: brew install python3" + echo " Linux: sudo apt install python3 python3-pip" + exit 1 +fi +echo "✓ Python 3 found: $(python3 --version)" +echo "" + +# Install castlabs-evs +echo "[2/4] Installing castlabs-evs..." +echo "Note: Using --break-system-packages flag for Homebrew Python..." +pip3 install --break-system-packages --upgrade castlabs-evs +echo "✓ castlabs-evs installed" +echo "" + +# Check if EVS account exists +EVS_CONFIG="$HOME/.config/evs/config.json" +if [ -f "$EVS_CONFIG" ]; then + echo "[3/4] EVS account already configured" + ACCOUNT_NAME=$(cat "$EVS_CONFIG" | grep -o '"account_name": "[^"]*"' | cut -d'"' -f4) + echo "✓ Account: $ACCOUNT_NAME" + echo "" + + echo "[4/4] Refreshing authorization tokens..." + echo "Please enter your EVS password when prompted:" + python3 -m castlabs_evs.account reauth +else + echo "[3/4] Creating EVS account..." + echo "Please follow the prompts to create your free EVS account:" + echo "" + python3 -m castlabs_evs.account signup + echo "" + + echo "[4/4] Account created successfully!" +fi + +echo "" +echo "==========================================" +echo "✓ EVS Setup Complete!" +echo "==========================================" +echo "" +echo "Verifying setup..." +node scripts/evs-sign.js --verify + +echo "" +echo "You can now build and sign your application:" +echo " $ pnpm run package" +echo "" diff --git a/apps/browser/src/main.ts b/apps/browser/src/main.ts index 665847e..ca32033 100644 --- a/apps/browser/src/main.ts +++ b/apps/browser/src/main.ts @@ -10,13 +10,124 @@ import { nativeTheme, WebContentsView, } from "electron"; + import path from "path"; import fs from "fs"; +// Widevine CDM configuration for castlabs electron-releases +console.log('[Widevine] Electron app path:', app.getAppPath()); +console.log('[Widevine] Electron version:', process.versions.electron); +console.log('[Widevine] Process versions:', JSON.stringify(process.versions, null, 2)); + +// Set Widevine CDM path - CRITICAL for production builds +const isPackaged = app.isPackaged; +console.log('[Widevine] Is packaged:', isPackaged); + +if (isPackaged) { + // Production: Widevine CDM is bundled in the app + // Try multiple possible locations + + console.log('[Widevine] process.resourcesPath:', process.resourcesPath); + console.log('[Widevine] __dirname:', __dirname); + + // Location 1: Resources/WidevineCdm (preferred for component updater) + const resourcesPath = path.join(process.resourcesPath, 'WidevineCdm'); + + // Location 2: Frameworks/Electron Framework.framework/.../Libraries/WidevineCdm + const frameworkPath = path.join( + process.resourcesPath, + '..', + 'Frameworks', + 'Electron Framework.framework', + 'Versions', + 'A', + 'Libraries', + 'WidevineCdm' + ); + + console.log('[Widevine] Checking Resources path:', resourcesPath); + console.log('[Widevine] Checking Framework path:', frameworkPath); + + // Use whichever path exists + const cdmBasePath = fs.existsSync(resourcesPath) ? resourcesPath : frameworkPath; + console.log('[Widevine] Using CDM base path:', cdmBasePath); + console.log('[Widevine] CDM base path exists:', fs.existsSync(cdmBasePath)); + + // Find the Widevine CDM version directory + if (fs.existsSync(cdmBasePath)) { + const versions = fs.readdirSync(cdmBasePath).filter(f => f.match(/^\d+\.\d+\.\d+\.\d+$/)); + if (versions.length > 0) { + const latestVersion = versions.sort().reverse()[0]; + const cdmPath = path.join(cdmBasePath, latestVersion); + + console.log('[Widevine] CDM directory:', cdmPath); + console.log('[Widevine] CDM version:', latestVersion); + + // Verify the dylib exists + const dylibPath = path.join(cdmPath, '_platform_specific/mac_arm64/libwidevinecdm.dylib'); + console.log('[Widevine] dylib path:', dylibPath); + console.log('[Widevine] dylib exists:', fs.existsSync(dylibPath)); + + if (fs.existsSync(dylibPath)) { + // CRITICAL: widevine-cdm-path must point to the VERSION DIRECTORY (not dylib) + // Electron will look for manifest.json in this directory + console.log('[Widevine] Setting CDM path to version directory:', cdmPath); + app.commandLine.appendSwitch('widevine-cdm-path', cdmPath); + app.commandLine.appendSwitch('widevine-cdm-version', latestVersion); + + // Verify manifest.json exists + const manifestPath = path.join(cdmPath, 'manifest.json'); + console.log('[Widevine] manifest.json exists:', fs.existsSync(manifestPath)); + } else { + console.error('[Widevine] ✗ libwidevinecdm.dylib not found!'); + } + } else { + console.error('[Widevine] No Widevine CDM version found in:', cdmBasePath); + } + } else { + console.error('[Widevine] Widevine CDM directory not found:', cdmBasePath); + } +} else { + // Development: Widevine CDM is in Application Support + console.log('[Widevine] Development mode - CDM will be loaded from Application Support'); +} + +// Enable Widevine features and DRM +app.commandLine.appendSwitch('enable-features', 'PlatformEncryptedDolbyVision'); + +// Additional flags for Widevine CDM +app.commandLine.appendSwitch('ignore-certificate-errors'); // For development/testing +app.commandLine.appendSwitch('allow-running-insecure-content'); // For development/testing + +// CRITICAL: Enable Chromium verbose logging for debugging +app.commandLine.appendSwitch('enable-logging'); +app.commandLine.appendSwitch('v', '1'); // Verbosity level 1 +app.commandLine.appendSwitch('vmodule', 'widevine*=3,cdm*=3,drm*=3,eme*=3,component*=3'); // Detailed logging for specific modules + +console.log('[Widevine] Command line switches configured'); +console.log('[Widevine] Chromium verbose logging enabled'); + +// Verify Widevine plugin on startup +app.on('ready', () => { + console.log('[Widevine] App ready - checking Widevine...'); + + // @ts-ignore - castlabs specific API + if (typeof app.isEVSEnabled === 'function') { + // @ts-ignore + console.log('[Widevine] EVS enabled:', app.isEVSEnabled()); + } + + // Log Widevine CDM path + const appPath = app.getAppPath(); + console.log('[Widevine] App path:', appPath); + console.log('[Widevine] __dirname:', __dirname); +}); + // URL validation and security -const ALLOWED_PROTOCOLS = process.env.NODE_ENV === "development" - ? ["http:", "https:", "file:"] - : ["http:", "https:"]; +const ALLOWED_PROTOCOLS = + process.env.NODE_ENV === "development" + ? ["http:", "https:", "file:"] + : ["http:", "https:"]; // Dangerous protocols that should always be blocked const DANGEROUS_PROTOCOLS = [ @@ -90,7 +201,11 @@ function sanitizeUrl(urlString: string): string { let url = urlString.trim(); // If already has a valid protocol, return as-is - if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("file://")) { + if ( + url.startsWith("http://") || + url.startsWith("https://") || + url.startsWith("file://") + ) { return url; } @@ -151,12 +266,12 @@ function getUserAgentForUrl(url: string): string { try { const urlObj = new URL(url); const hostname = urlObj.hostname.toLowerCase(); - + // Use desktop user agent for Netflix if (hostname === "netflix.com" || hostname.endsWith(".netflix.com")) { return DESKTOP_USER_AGENT; } - + // Default to mobile user agent return IPHONE_USER_AGENT; } catch (error) { @@ -176,8 +291,9 @@ class ThemeColorCache { set(domain: string, color: string): void { // Remove oldest entry if cache is full if (this.cache.size >= this.maxSize && !this.cache.has(domain)) { - const oldestKey = Array.from(this.cache.entries()) - .sort((a, b) => a[1].timestamp - b[1].timestamp)[0]?.[0]; + const oldestKey = Array.from(this.cache.entries()).sort( + (a, b) => a[1].timestamp - b[1].timestamp + )[0]?.[0]; if (oldestKey) { this.cache.delete(oldestKey); } @@ -210,12 +326,12 @@ const themeColorCache = new ThemeColorCache(); function getLuminance(color: string): number { let r: number, g: number, b: number; - if (color.startsWith('#')) { - const hex = color.replace('#', ''); + if (color.startsWith("#")) { + const hex = color.replace("#", ""); r = parseInt(hex.substr(0, 2), 16); g = parseInt(hex.substr(2, 2), 16); b = parseInt(hex.substr(4, 2), 16); - } else if (color.startsWith('rgb')) { + } else if (color.startsWith("rgb")) { const matches = color.match(/\d+/g); if (matches) { r = parseInt(matches[0]); @@ -232,9 +348,12 @@ function getLuminance(color: string): number { const gsRGB = g / 255; const bsRGB = b / 255; - const rLinear = rsRGB <= 0.03928 ? rsRGB / 12.92 : Math.pow((rsRGB + 0.055) / 1.055, 2.4); - const gLinear = gsRGB <= 0.03928 ? gsRGB / 12.92 : Math.pow((gsRGB + 0.055) / 1.055, 2.4); - const bLinear = bsRGB <= 0.03928 ? bsRGB / 12.92 : Math.pow((bsRGB + 0.055) / 1.055, 2.4); + const rLinear = + rsRGB <= 0.03928 ? rsRGB / 12.92 : Math.pow((rsRGB + 0.055) / 1.055, 2.4); + const gLinear = + gsRGB <= 0.03928 ? gsRGB / 12.92 : Math.pow((gsRGB + 0.055) / 1.055, 2.4); + const bLinear = + bsRGB <= 0.03928 ? bsRGB / 12.92 : Math.pow((bsRGB + 0.055) / 1.055, 2.4); return 0.2126 * rLinear + 0.7152 * gLinear + 0.0722 * bLinear; } @@ -259,7 +378,7 @@ function getWindowDimensions() { // Create a new tab function createTab(url: string = "https://www.google.com"): Tab { const tabId = `tab-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; - + const webviewPreloadPath = path.join(__dirname, "webview-preload.js"); const hasWebviewPreload = fs.existsSync(webviewPreloadPath); @@ -269,16 +388,27 @@ function createTab(url: string = "https://www.google.com"): Tab { contextIsolation: true, webSecurity: true, allowRunningInsecureContent: false, - sandbox: true, + sandbox: false, // Widevine requires sandbox: false partition: "persist:main", + plugins: true, // Enable plugins for Widevine CDM + enablePreferredSizeMode: false, ...(hasWebviewPreload ? { preload: webviewPreloadPath } : {}), }, }); + + // Enable Widevine CDM for this webContents + view.webContents.session.setPermissionRequestHandler((_webContents: any, permission: string, callback: (result: boolean) => void) => { + if (permission === 'media') { + callback(true); // Allow media permissions for DRM + } else { + callback(false); + } + }); // Set initial user agent based on URL const userAgent = getUserAgentForUrl(url); view.webContents.setUserAgent(userAgent); - + const tab: Tab = { id: tabId, view, @@ -288,7 +418,7 @@ function createTab(url: string = "https://www.google.com"): Tab { tabs.push(tab); setupWebContentsViewHandlers(view, tabId); - + // Load URL const sanitized = sanitizeUrl(url); if (isValidUrl(sanitized)) { @@ -300,15 +430,15 @@ function createTab(url: string = "https://www.google.com"): Tab { // Switch to a specific tab function switchToTab(tabId: string) { - const tab = tabs.find(t => t.id === tabId); + const tab = tabs.find((t) => t.id === tabId); if (!tab || !mainWindow) return; // Hide current active tab and capture its preview if (activeTabId && activeTabId !== tabId) { - const currentTab = tabs.find(t => t.id === activeTabId); + const currentTab = tabs.find((t) => t.id === activeTabId); if (currentTab) { // Capture preview before hiding - captureTabPreview(activeTabId).catch(err => { + captureTabPreview(activeTabId).catch((err) => { console.error("Failed to capture preview on tab switch:", err); }); mainWindow.contentView.removeChildView(currentTab.view); @@ -327,7 +457,7 @@ function switchToTab(tabId: string) { // Notify renderer about tab change mainWindow.webContents.send("tab-changed", { tabId, - tabs: tabs.map(t => ({ + tabs: tabs.map((t) => ({ id: t.id, title: t.title, url: t.url, @@ -338,11 +468,11 @@ function switchToTab(tabId: string) { // Close a tab function closeTab(tabId: string) { - const tabIndex = tabs.findIndex(t => t.id === tabId); + const tabIndex = tabs.findIndex((t) => t.id === tabId); if (tabIndex === -1) return; const tab = tabs[tabIndex]; - + // Remove from window if (mainWindow) { mainWindow.contentView.removeChildView(tab.view); @@ -371,7 +501,7 @@ function closeTab(tabId: string) { // Just notify renderer about tab list change if (mainWindow) { mainWindow.webContents.send("tabs-updated", { - tabs: tabs.map(t => ({ + tabs: tabs.map((t) => ({ id: t.id, title: t.title, url: t.url, @@ -385,7 +515,7 @@ function closeTab(tabId: string) { // Capture tab preview async function captureTabPreview(tabId: string): Promise { - const tab = tabs.find(t => t.id === tabId); + const tab = tabs.find((t) => t.id === tabId); if (!tab || tab.view.webContents.isDestroyed()) return; try { @@ -396,15 +526,15 @@ async function captureTabPreview(tabId: string): Promise { width: 800, height: 1200, }); - + // Convert to base64 data URL const dataUrl = image.toDataURL(); tab.preview = dataUrl; - + // Notify renderer about updated tabs if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send("tabs-updated", { - tabs: tabs.map(t => ({ + tabs: tabs.map((t) => ({ id: t.id, title: t.title, url: t.url, @@ -424,16 +554,16 @@ function updateWebContentsViewBounds() { const bounds = mainWindow.getBounds(); const dimensions = getWindowDimensions(); - + // Calculate scale factor const scaleX = bounds.width / dimensions.width; const scaleY = bounds.height / dimensions.height; if (isLandscape) { const statusBarWidth = STATUS_BAR_WIDTH * scaleX; - const frameTop = FRAME_PADDING / 2 * scaleY; - const frameBottom = FRAME_PADDING / 2 * scaleY; - const frameRight = FRAME_PADDING / 2 * scaleX; + const frameTop = (FRAME_PADDING / 2) * scaleY; + const frameBottom = (FRAME_PADDING / 2) * scaleY; + const frameRight = (FRAME_PADDING / 2) * scaleX; const topBarHeight = TOP_BAR_HEIGHT * scaleY; webContentsView.setBounds({ @@ -444,17 +574,19 @@ function updateWebContentsViewBounds() { }); } else { const statusBarHeight = STATUS_BAR_HEIGHT * scaleY; - const frameTop = FRAME_PADDING / 2 * scaleY; - const frameBottom = FRAME_PADDING / 2 * scaleY; - const frameLeft = FRAME_PADDING / 2 * scaleX; - const frameRight = FRAME_PADDING / 2 * scaleX; + const frameTop = (FRAME_PADDING / 2) * scaleY; + const frameBottom = (FRAME_PADDING / 2) * scaleY; + const frameLeft = (FRAME_PADDING / 2) * scaleX; + const frameRight = (FRAME_PADDING / 2) * scaleX; const topBarHeight = TOP_BAR_HEIGHT * scaleY; webContentsView.setBounds({ x: Math.round(frameLeft), y: Math.round(topBarHeight + statusBarHeight + frameTop), width: Math.round(bounds.width - frameLeft - frameRight), - height: Math.round(bounds.height - topBarHeight - statusBarHeight - frameTop - frameBottom), + height: Math.round( + bounds.height - topBarHeight - statusBarHeight - frameTop - frameBottom + ), }); } } @@ -489,10 +621,10 @@ function setupWebContentsViewHandlers(view: WebContentsView, tabId: string) { if (contents.isDevToolsOpened()) { contents.closeDevTools(); } - + // Open DevTools in detached mode first contents.openDevTools({ mode: "detach" }); - + // Then inspect the specific element after a short delay setTimeout(() => { contents.inspectElement(params.x, params.y); @@ -531,7 +663,7 @@ function setupWebContentsViewHandlers(view: WebContentsView, tabId: string) { // Create a new tab for the URL const newTab = createTab(url); switchToTab(newTab.id); - + return { action: "deny" }; // We handle it ourselves }); @@ -571,10 +703,10 @@ function setupWebContentsViewHandlers(view: WebContentsView, tabId: string) { contents.on("did-stop-loading", () => { mainWindow?.webContents.send("webcontents-did-stop-loading"); - + // Capture preview after page loads (with a small delay to ensure rendering) setTimeout(() => { - captureTabPreview(tabId).catch(err => { + captureTabPreview(tabId).catch((err) => { console.error("Failed to capture preview after loading:", err); }); }, 500); @@ -582,18 +714,18 @@ function setupWebContentsViewHandlers(view: WebContentsView, tabId: string) { contents.on("did-navigate", (event: any, url: string) => { // Update tab info - const tab = tabs.find(t => t.id === tabId); + const tab = tabs.find((t) => t.id === tabId); if (tab) { tab.url = url; tab.title = contents.getTitle() || url; } - + mainWindow?.webContents.send("webcontents-did-navigate", url); - + // Notify about tab update if this is the active tab if (activeTabId === tabId && mainWindow) { mainWindow.webContents.send("tabs-updated", { - tabs: tabs.map(t => ({ + tabs: tabs.map((t) => ({ id: t.id, title: t.title, url: t.url, @@ -606,18 +738,18 @@ function setupWebContentsViewHandlers(view: WebContentsView, tabId: string) { contents.on("did-navigate-in-page", (event: any, url: string) => { // Update tab info - const tab = tabs.find(t => t.id === tabId); + const tab = tabs.find((t) => t.id === tabId); if (tab) { tab.url = url; tab.title = contents.getTitle() || url; } - + mainWindow?.webContents.send("webcontents-did-navigate-in-page", url); - + // Notify about tab update if this is the active tab if (activeTabId === tabId && mainWindow) { mainWindow.webContents.send("tabs-updated", { - tabs: tabs.map(t => ({ + tabs: tabs.map((t) => ({ id: t.id, title: t.title, url: t.url, @@ -705,7 +837,11 @@ function createWindow(): void { webContentsView.webContents.session.setPermissionRequestHandler( (webContents, permission, callback) => { // Only allow specific permissions - const allowedPermissions = ["clipboard-read", "clipboard-write"]; + const allowedPermissions = [ + "clipboard-read", + "clipboard-write", + "media", // Required for DRM content playback + ]; if (allowedPermissions.includes(permission)) { logSecurityEvent(`Permission granted: ${permission}`); @@ -896,7 +1032,7 @@ ipcMain.handle("toggle-orientation", () => { "orientation-changed", isLandscape ? "landscape" : "portrait" ); - + // Update status bar orientation in WebContentsView // updateStatusBar - now handled by React(); } @@ -918,9 +1054,9 @@ ipcMain.handle("tabs-get-all", (event) => { logSecurityEvent("Unauthorized IPC call to tabs-get-all"); return { tabs: [], activeTabId: null }; } - + return { - tabs: tabs.map(t => ({ + tabs: tabs.map((t) => ({ id: t.id, title: t.title, url: t.url, @@ -935,10 +1071,10 @@ ipcMain.handle("tabs-create", (event, url?: string) => { logSecurityEvent("Unauthorized IPC call to tabs-create"); throw new Error("Unauthorized"); } - + const newTab = createTab(url); switchToTab(newTab.id); - + return { id: newTab.id, title: newTab.title, @@ -951,7 +1087,7 @@ ipcMain.handle("tabs-switch", (event, tabId: string) => { logSecurityEvent("Unauthorized IPC call to tabs-switch"); throw new Error("Unauthorized"); } - + switchToTab(tabId); }); @@ -960,7 +1096,7 @@ ipcMain.handle("tabs-close", (event, tabId: string) => { logSecurityEvent("Unauthorized IPC call to tabs-close"); throw new Error("Unauthorized"); } - + closeTab(tabId); }); @@ -969,24 +1105,24 @@ ipcMain.handle("tabs-close-all", (event) => { logSecurityEvent("Unauthorized IPC call to tabs-close-all"); throw new Error("Unauthorized"); } - + // Close all tabs const tabsToClose = [...tabs]; // Create a copy to avoid mutation during iteration - tabsToClose.forEach(tab => { + tabsToClose.forEach((tab) => { // Remove from window if (mainWindow) { mainWindow.contentView.removeChildView(tab.view); } - + // Destroy the view if (!tab.view.webContents.isDestroyed()) { tab.view.webContents.close(); } }); - + // Clear tabs array tabs.length = 0; - + // Create a new tab const newTab = createTab(); switchToTab(newTab.id); @@ -998,7 +1134,7 @@ ipcMain.handle("webcontents-set-visible", (event, visible: boolean) => { logSecurityEvent("Unauthorized IPC call to webcontents-set-visible"); throw new Error("Unauthorized"); } - + if (webContentsView && mainWindow) { if (visible) { // Show the view by adding it back @@ -1121,29 +1257,32 @@ ipcMain.handle("webcontents-get-theme-color", async (event) => { }); // Receive theme color from webview preload script -ipcMain.on("webview-theme-color-extracted", (event, data: { themeColor: string; domain: string }) => { - // Verify the sender is the webContentsView - if (webContentsView && event.sender === webContentsView.webContents) { - const { themeColor, domain } = data; - latestThemeColor = themeColor; - - // Cache the theme color for this domain - if (domain && themeColor) { - themeColorCache.set(domain, themeColor); - } - - // Update status bar in WebContentsView - // updateStatusBar - now handled by React(themeColor); - - // Forward to renderer (for backward compatibility) - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.webContents.send( - "webcontents-theme-color-updated", - themeColor - ); +ipcMain.on( + "webview-theme-color-extracted", + (event, data: { themeColor: string; domain: string }) => { + // Verify the sender is the webContentsView + if (webContentsView && event.sender === webContentsView.webContents) { + const { themeColor, domain } = data; + latestThemeColor = themeColor; + + // Cache the theme color for this domain + if (domain && themeColor) { + themeColorCache.set(domain, themeColor); + } + + // Update status bar in WebContentsView + // updateStatusBar - now handled by React(themeColor); + + // Forward to renderer (for backward compatibility) + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.webContents.send( + "webcontents-theme-color-updated", + themeColor + ); + } } } -}); +); // Handle navigation gestures from WebContentsView ipcMain.on("webview-navigate-back", (event) => { @@ -1264,7 +1403,7 @@ function createTray(): void { "orientation-changed", isLandscape ? "landscape" : "portrait" ); - + // Update status bar orientation in WebContentsView // updateStatusBar - now handled by React(); } @@ -1296,9 +1435,13 @@ function createTray(): void { } // This method will be called when Electron has finished initialization -app.whenReady().then(() => { +app.whenReady().then(async () => { app.setName("Aka Browser"); + // Widevine CDM should be automatically available in castlabs electron-releases + // No need to wait for components - it's built-in and signed + console.log("[Widevine] Using castlabs electron-releases with built-in Widevine CDM"); + // Set dock icon for macOS if (process.platform === "darwin") { const iconPath = path.join(__dirname, "../assets/icon.png"); diff --git a/apps/browser/src/webview-preload.ts b/apps/browser/src/webview-preload.ts index a29bcb8..65379ed 100644 --- a/apps/browser/src/webview-preload.ts +++ b/apps/browser/src/webview-preload.ts @@ -255,5 +255,56 @@ function setupNavigationGestures() { // Setup gesture detection immediately setupNavigationGestures(); +// Widevine CDM verification +function checkWidevineCdm() { + console.log("[Widevine] Checking Widevine CDM availability..."); + + // Check if navigator.plugins is available + // @ts-ignore - plugins exists in browser context + if (navigator.plugins) { + console.log( + "[Widevine] Available plugins:", + // @ts-ignore + Array.from(navigator.plugins).map((p: any) => p.name) + ); + } + + // Check for Widevine support using EME API + // @ts-ignore - requestMediaKeySystemAccess exists in browser context + if (navigator.requestMediaKeySystemAccess) { + // @ts-ignore + navigator + .requestMediaKeySystemAccess("com.widevine.alpha", [ + { + initDataTypes: ["cenc"], + videoCapabilities: [ + { + contentType: 'video/mp4; codecs="avc1.42E01E"', + }, + ], + }, + ]) + .then((keySystemAccess) => { + console.log("[Widevine] ✓ Widevine CDM is available and working!"); + console.log("[Widevine] Key system:", keySystemAccess.keySystem); + }) + .catch((error) => { + console.error("[Widevine] ✗ Widevine CDM is NOT available:", error); + console.error( + "[Widevine] DRM content will not play. Please ensure Widevine is properly configured." + ); + }); + } else { + console.error( + "[Widevine] ✗ EME API (requestMediaKeySystemAccess) is not available" + ); + } +} + +// Check Widevine when page loads +window.addEventListener("load", () => { + setTimeout(checkWidevineCdm, 500); +}); + // Status bar is now a React component in the main renderer // This preload script handles theme color extraction, corner masking, and navigation gestures diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e80e2d7..54c9cd5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,11 +49,11 @@ importers: specifier: ^10.1.0 version: 10.1.0 electron: - specifier: ^38.3.0 - version: 38.3.0 + specifier: github:castlabs/electron-releases#v38.0.0+wvcus + version: https://codeload.github.com/castlabs/electron-releases/tar.gz/678b5c7761825c5af936f5c67a9101f3fc6ab750 electron-builder: - specifier: ^24.9.1 - version: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) + specifier: ^26.0.12 + version: 26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)) tailwindcss: specifier: ^4.1.14 version: 4.1.14 @@ -160,28 +160,61 @@ packages: resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} engines: {node: '>= 8.9.0'} + '@electron/asar@3.2.18': + resolution: {integrity: sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==} + engines: {node: '>=10.12.0'} + hasBin: true + '@electron/asar@3.4.1': resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==} engines: {node: '>=10.12.0'} hasBin: true + '@electron/fuses@1.8.0': + resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} + hasBin: true + '@electron/get@2.0.3': resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} engines: {node: '>=12'} + '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': + resolution: {tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2} + version: 10.2.0-electron.1 + engines: {node: '>=12.13.0'} + hasBin: true + '@electron/notarize@2.2.1': resolution: {integrity: sha512-aL+bFMIkpR0cmmj5Zgy0LMKEpgy43/hw5zadEArgmAMWWlKc5buwFvFT9G/o/YJkvXAJm5q3iuTuLaiaXW39sg==} engines: {node: '>= 10.0.0'} + '@electron/notarize@2.5.0': + resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} + engines: {node: '>= 10.0.0'} + '@electron/osx-sign@1.0.5': resolution: {integrity: sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww==} engines: {node: '>=12.0.0'} hasBin: true + '@electron/osx-sign@1.3.1': + resolution: {integrity: sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==} + engines: {node: '>=12.0.0'} + hasBin: true + + '@electron/rebuild@3.7.0': + resolution: {integrity: sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==} + engines: {node: '>=12.13.0'} + hasBin: true + '@electron/universal@1.5.1': resolution: {integrity: sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw==} engines: {node: '>=8.6'} + '@electron/universal@2.0.1': + resolution: {integrity: sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==} + engines: {node: '>=16.4'} + '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} @@ -341,6 +374,17 @@ packages: cpu: [x64] os: [win32] + '@gar/promisify@1.1.3': + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -369,10 +413,23 @@ packages: resolution: {integrity: sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==} engines: {node: '>= 10'} + '@malept/cross-spawn-promise@2.0.0': + resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} + engines: {node: '>= 12.13.0'} + '@malept/flatpak-bundler@0.4.0': resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} engines: {node: '>= 10.0.0'} + '@npmcli/fs@2.1.2': + resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + '@npmcli/move-file@2.0.1': + resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This functionality has been moved to @npmcli/fs + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -661,10 +718,25 @@ packages: resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} engines: {node: '>=10.0.0'} + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + ajv-keywords@3.5.2: resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} peerDependencies: @@ -692,6 +764,9 @@ packages: app-builder-bin@4.0.0: resolution: {integrity: sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA==} + app-builder-bin@5.0.0-alpha.12: + resolution: {integrity: sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==} + app-builder-lib@24.13.3: resolution: {integrity: sha512-FAzX6IBit2POXYGnTCT8YHFO/lr5AapAII6zzhQO3Rw4cEDOgK+t1xhLc5tNcKlicTHlo9zxIwnYCX9X2DLkig==} engines: {node: '>=14.0.0'} @@ -699,6 +774,13 @@ packages: dmg-builder: 24.13.3 electron-builder-squirrel-windows: 24.13.3 + app-builder-lib@26.0.12: + resolution: {integrity: sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==} + engines: {node: '>=14.0.0'} + peerDependencies: + dmg-builder: 26.0.12 + electron-builder-squirrel-windows: 26.0.12 + archiver-utils@2.1.0: resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} engines: {node: '>= 6'} @@ -787,9 +869,20 @@ packages: resolution: {integrity: sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==} engines: {node: '>=12.0.0'} + builder-util-runtime@9.3.1: + resolution: {integrity: sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==} + engines: {node: '>=12.0.0'} + builder-util@24.13.1: resolution: {integrity: sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA==} + builder-util@26.0.11: + resolution: {integrity: sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==} + + cacache@16.1.3: + resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + cacheable-lookup@5.0.4: resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} engines: {node: '>=10.6.0'} @@ -824,6 +917,18 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + cli-truncate@2.1.0: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} engines: {node: '>=8'} @@ -835,6 +940,10 @@ packages: clone-response@1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -869,6 +978,9 @@ packages: config-file-ts@0.2.6: resolution: {integrity: sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==} + config-file-ts@0.2.8-rc1: + resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -919,6 +1031,9 @@ packages: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + defer-to-connect@2.0.1: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} engines: {node: '>=10'} @@ -945,8 +1060,11 @@ packages: dir-compare@3.3.0: resolution: {integrity: sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==} - dmg-builder@24.13.3: - resolution: {integrity: sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ==} + dir-compare@4.2.0: + resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} + + dmg-builder@26.0.12: + resolution: {integrity: sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==} dmg-license@1.0.11: resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==} @@ -954,9 +1072,17 @@ packages: os: [darwin] hasBin: true + dotenv-expand@11.0.7: + resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} + engines: {node: '>=12'} + dotenv-expand@5.1.0: resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dotenv@9.0.2: resolution: {integrity: sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==} engines: {node: '>=10'} @@ -976,19 +1102,23 @@ packages: electron-builder-squirrel-windows@24.13.3: resolution: {integrity: sha512-oHkV0iogWfyK+ah9ZIvMDpei1m9ZRpdXcvde1wTpra2U8AFDNNpqJdnin5z+PM1GbQ5BoaKCWas2HSjtR0HwMg==} - electron-builder@24.13.3: - resolution: {integrity: sha512-yZSgVHft5dNVlo31qmJAe4BVKQfFdwpRw7sFp1iQglDRCDD6r22zfRJuZlhtB5gp9FHUxCMEoWGq10SkCnMAIg==} + electron-builder@26.0.12: + resolution: {integrity: sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==} engines: {node: '>=14.0.0'} hasBin: true electron-publish@24.13.1: resolution: {integrity: sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A==} + electron-publish@26.0.11: + resolution: {integrity: sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==} + electron-to-chromium@1.5.237: resolution: {integrity: sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==} - electron@38.3.0: - resolution: {integrity: sha512-Wij4AzX4SAV0X/ktq+NrWrp5piTCSS8F6YWh1KAcG+QRtNzyns9XLKERP68nFHIwfprhxF2YCN2uj7nx9DaeJw==} + electron@https://codeload.github.com/castlabs/electron-releases/tar.gz/678b5c7761825c5af936f5c67a9101f3fc6ab750: + resolution: {tarball: https://codeload.github.com/castlabs/electron-releases/tar.gz/678b5c7761825c5af936f5c67a9101f3fc6ab750} + version: 38.0.0 engines: {node: '>= 12.20.55'} hasBin: true @@ -998,6 +1128,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} @@ -1044,6 +1177,9 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + extract-zip@2.0.1: resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} engines: {node: '>= 10.17.0'} @@ -1089,6 +1225,10 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} + fs-extra@11.3.2: + resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + engines: {node: '>=14.14'} + fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} @@ -1140,6 +1280,11 @@ packages: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported + global-agent@3.0.0: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} engines: {node: '>=10.0'} @@ -1189,6 +1334,10 @@ packages: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + http2-wrapper@1.0.3: resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} engines: {node: '>=10.19.0'} @@ -1197,6 +1346,13 @@ packages: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + iconv-corefoundation@1.1.7: resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} engines: {node: ^8.11.2 || >=10} @@ -1209,6 +1365,17 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -1216,6 +1383,10 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ip-address@10.0.1: + resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} + engines: {node: '>= 12'} + is-ci@3.0.1: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true @@ -1224,6 +1395,17 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + + is-lambda@1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -1444,6 +1626,10 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -1462,9 +1648,17 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + magic-string@0.30.19: resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + make-fetch-happen@10.2.1: + resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + matcher@3.0.0: resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} engines: {node: '>=10'} @@ -1486,6 +1680,10 @@ packages: engines: {node: '>=4.0.0'} hasBin: true + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -1494,6 +1692,10 @@ packages: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1508,6 +1710,26 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + + minipass-fetch@2.1.2: + resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + minipass-flush@1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -1541,12 +1763,28 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + + node-abi@3.78.0: + resolution: {integrity: sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ==} + engines: {node: '>=10'} + node-addon-api@1.7.2: resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} + node-api-version@0.2.1: + resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} + node-releases@2.0.23: resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} + nopt@6.0.0: + resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -1562,10 +1800,26 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -1581,6 +1835,10 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + pe-library@0.4.1: + resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} + engines: {node: '>=12', npm: '>=6'} + pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} @@ -1603,6 +1861,10 @@ packages: resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} + proc-log@2.0.1: + resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -1610,6 +1872,14 @@ packages: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} + promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + promise-retry@2.0.1: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} @@ -1638,6 +1908,10 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} + read-binary-file-arch@1.0.6: + resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} + hasBin: true + read-config-file@6.3.2: resolution: {integrity: sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q==} engines: {node: '>=12.0.0'} @@ -1656,16 +1930,29 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + resedit@1.7.2: + resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} + engines: {node: '>=12', npm: '>=6'} + resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} responselike@2.0.1: resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + roarr@2.15.4: resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} engines: {node: '>=8.0'} @@ -1699,6 +1986,10 @@ packages: semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -1724,6 +2015,9 @@ packages: resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} engines: {node: '>= 0.4'} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -1740,6 +2034,14 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + socks-proxy-agent@7.0.0: + resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} + engines: {node: '>= 10'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1757,6 +2059,10 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + ssri@9.0.1: + resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + stat-mode@1.0.0: resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} engines: {node: '>= 6'} @@ -1817,6 +2123,9 @@ packages: temp-file@3.4.0: resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} + tiny-async-pool@1.3.0: + resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -1884,6 +2193,14 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + unique-filename@2.0.1: + resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + unique-slug@3.0.0: + resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -1951,6 +2268,9 @@ packages: yaml: optional: true + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1996,6 +2316,10 @@ packages: yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + zip-stream@4.1.1: resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} engines: {node: '>= 10'} @@ -2123,12 +2447,24 @@ snapshots: ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) + '@electron/asar@3.2.18': + dependencies: + commander: 5.1.0 + glob: 7.2.3 + minimatch: 3.1.2 + '@electron/asar@3.4.1': dependencies: commander: 5.1.0 glob: 7.2.3 minimatch: 3.1.2 + '@electron/fuses@1.8.0': + dependencies: + chalk: 4.1.2 + fs-extra: 9.1.0 + minimist: 1.2.8 + '@electron/get@2.0.3': dependencies: debug: 4.4.1 @@ -2143,6 +2479,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': + dependencies: + env-paths: 2.2.1 + exponential-backoff: 3.1.3 + glob: 8.1.0 + graceful-fs: 4.2.11 + make-fetch-happen: 10.2.1 + nopt: 6.0.0 + proc-log: 2.0.1 + semver: 7.7.2 + tar: 6.2.1 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + '@electron/notarize@2.2.1': dependencies: debug: 4.4.1 @@ -2151,6 +2503,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@electron/notarize@2.5.0': + dependencies: + debug: 4.4.1 + fs-extra: 9.1.0 + promise-retry: 2.0.1 + transitivePeerDependencies: + - supports-color + '@electron/osx-sign@1.0.5': dependencies: compare-version: 0.1.2 @@ -2162,6 +2522,37 @@ snapshots: transitivePeerDependencies: - supports-color + '@electron/osx-sign@1.3.1': + dependencies: + compare-version: 0.1.2 + debug: 4.4.1 + fs-extra: 10.1.0 + isbinaryfile: 4.0.10 + minimist: 1.2.8 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/rebuild@3.7.0': + dependencies: + '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 + '@malept/cross-spawn-promise': 2.0.0 + chalk: 4.1.2 + debug: 4.4.1 + detect-libc: 2.1.2 + fs-extra: 10.1.0 + got: 11.8.6 + node-abi: 3.78.0 + node-api-version: 0.2.1 + ora: 5.4.1 + read-binary-file-arch: 1.0.6 + semver: 7.7.2 + tar: 6.2.1 + yargs: 17.7.2 + transitivePeerDependencies: + - bluebird + - supports-color + '@electron/universal@1.5.1': dependencies: '@electron/asar': 3.4.1 @@ -2174,6 +2565,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@electron/universal@2.0.1': + dependencies: + '@electron/asar': 3.4.1 + '@malept/cross-spawn-promise': 2.0.0 + debug: 4.4.1 + dir-compare: 4.2.0 + fs-extra: 11.3.2 + minimatch: 9.0.5 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + '@epic-web/invariant@1.0.0': {} '@esbuild/aix-ppc64@0.25.11': @@ -2254,6 +2657,14 @@ snapshots: '@esbuild/win32-x64@0.25.11': optional: true + '@gar/promisify@1.1.3': {} + + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -2290,6 +2701,10 @@ snapshots: dependencies: cross-spawn: 7.0.6 + '@malept/cross-spawn-promise@2.0.0': + dependencies: + cross-spawn: 7.0.6 + '@malept/flatpak-bundler@0.4.0': dependencies: debug: 4.4.1 @@ -2299,6 +2714,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@npmcli/fs@2.1.2': + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.7.2 + + '@npmcli/move-file@2.0.1': + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + '@pkgjs/parseargs@0.11.0': optional: true @@ -2543,12 +2968,25 @@ snapshots: '@xmldom/xmldom@0.8.11': {} + abbrev@1.1.1: {} + agent-base@6.0.2: dependencies: debug: 4.4.1 transitivePeerDependencies: - supports-color + agent-base@7.1.4: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + ajv-keywords@3.5.2(ajv@6.12.6): dependencies: ajv: 6.12.6 @@ -2572,7 +3010,9 @@ snapshots: app-builder-bin@4.0.0: {} - app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)): + app-builder-bin@5.0.0-alpha.12: {} + + app-builder-lib@24.13.3(dmg-builder@26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)): dependencies: '@develar/schema-utils': 2.6.5 '@electron/notarize': 2.2.1 @@ -2586,9 +3026,9 @@ snapshots: builder-util-runtime: 9.2.4 chromium-pickle-js: 0.2.0 debug: 4.4.1 - dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) + dmg-builder: 26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)) ejs: 3.1.10 - electron-builder-squirrel-windows: 24.13.3(dmg-builder@24.13.3) + electron-builder-squirrel-windows: 24.13.3(dmg-builder@26.0.12) electron-publish: 24.13.1 form-data: 4.0.4 fs-extra: 10.1.0 @@ -2606,6 +3046,47 @@ snapshots: transitivePeerDependencies: - supports-color + app-builder-lib@26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)): + dependencies: + '@develar/schema-utils': 2.6.5 + '@electron/asar': 3.2.18 + '@electron/fuses': 1.8.0 + '@electron/notarize': 2.5.0 + '@electron/osx-sign': 1.3.1 + '@electron/rebuild': 3.7.0 + '@electron/universal': 2.0.1 + '@malept/flatpak-bundler': 0.4.0 + '@types/fs-extra': 9.0.13 + async-exit-hook: 2.0.1 + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + chromium-pickle-js: 0.2.0 + config-file-ts: 0.2.8-rc1 + debug: 4.4.1 + dmg-builder: 26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)) + dotenv: 16.6.1 + dotenv-expand: 11.0.7 + ejs: 3.1.10 + electron-builder-squirrel-windows: 24.13.3(dmg-builder@26.0.12) + electron-publish: 26.0.11 + fs-extra: 10.1.0 + hosted-git-info: 4.1.0 + is-ci: 3.0.1 + isbinaryfile: 5.0.6 + js-yaml: 4.1.0 + json5: 2.2.3 + lazy-val: 1.0.5 + minimatch: 10.0.3 + plist: 3.1.0 + resedit: 1.7.2 + semver: 7.7.2 + tar: 6.2.1 + temp-file: 3.4.0 + tiny-async-pool: 1.3.0 + transitivePeerDependencies: + - bluebird + - supports-color + archiver-utils@2.1.0: dependencies: glob: 7.2.3 @@ -2714,6 +3195,13 @@ snapshots: transitivePeerDependencies: - supports-color + builder-util-runtime@9.3.1: + dependencies: + debug: 4.4.1 + sax: 1.4.1 + transitivePeerDependencies: + - supports-color + builder-util@24.13.1: dependencies: 7zip-bin: 5.2.0 @@ -2735,6 +3223,51 @@ snapshots: transitivePeerDependencies: - supports-color + builder-util@26.0.11: + dependencies: + 7zip-bin: 5.2.0 + '@types/debug': 4.1.12 + app-builder-bin: 5.0.0-alpha.12 + builder-util-runtime: 9.3.1 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.1 + fs-extra: 10.1.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-ci: 3.0.1 + js-yaml: 4.1.0 + sanitize-filename: 1.6.3 + source-map-support: 0.5.21 + stat-mode: 1.0.0 + temp-file: 3.4.0 + tiny-async-pool: 1.3.0 + transitivePeerDependencies: + - supports-color + + cacache@16.1.3: + dependencies: + '@npmcli/fs': 2.1.2 + '@npmcli/move-file': 2.0.1 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 8.1.0 + infer-owner: 1.0.4 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 9.0.1 + tar: 6.2.1 + unique-filename: 2.0.1 + transitivePeerDependencies: + - bluebird + cacheable-lookup@5.0.4: {} cacheable-request@7.0.4: @@ -2767,6 +3300,14 @@ snapshots: ci-info@3.9.0: {} + clean-stack@2.2.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-spinners@2.9.2: {} + cli-truncate@2.1.0: dependencies: slice-ansi: 3.0.0 @@ -2783,6 +3324,8 @@ snapshots: dependencies: mimic-response: 1.0.1 + clone@1.0.4: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2823,6 +3366,11 @@ snapshots: glob: 10.4.5 typescript: 5.9.2 + config-file-ts@0.2.8-rc1: + dependencies: + glob: 10.4.5 + typescript: 5.9.2 + convert-source-map@2.0.0: {} core-util-is@1.0.2: @@ -2867,6 +3415,10 @@ snapshots: dependencies: mimic-response: 3.1.0 + defaults@1.0.4: + dependencies: + clone: 1.0.4 + defer-to-connect@2.0.1: {} define-data-property@1.1.4: @@ -2895,17 +3447,23 @@ snapshots: buffer-equal: 1.0.1 minimatch: 3.1.2 - dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)): + dir-compare@4.2.0: dependencies: - app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) - builder-util: 24.13.1 - builder-util-runtime: 9.2.4 + minimatch: 3.1.2 + p-limit: 3.1.0 + + dmg-builder@26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)): + dependencies: + app-builder-lib: 26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)) + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 fs-extra: 10.1.0 iconv-lite: 0.6.3 js-yaml: 4.1.0 optionalDependencies: dmg-license: 1.0.11 transitivePeerDependencies: + - bluebird - electron-builder-squirrel-windows - supports-color @@ -2921,8 +3479,14 @@ snapshots: verror: 1.10.1 optional: true + dotenv-expand@11.0.7: + dependencies: + dotenv: 16.6.1 + dotenv-expand@5.1.0: {} + dotenv@16.6.1: {} + dotenv@9.0.2: {} dunder-proto@1.0.1: @@ -2937,9 +3501,9 @@ snapshots: dependencies: jake: 10.9.4 - electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3): + electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12): dependencies: - app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) + app-builder-lib: 24.13.3(dmg-builder@26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)) archiver: 5.3.2 builder-util: 24.13.1 fs-extra: 10.1.0 @@ -2947,20 +3511,20 @@ snapshots: - dmg-builder - supports-color - electron-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)): + electron-builder@26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)): dependencies: - app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) - builder-util: 24.13.1 - builder-util-runtime: 9.2.4 + app-builder-lib: 26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)) + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 chalk: 4.1.2 - dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) + dmg-builder: 26.0.12(electron-builder-squirrel-windows@24.13.3(dmg-builder@26.0.12)) fs-extra: 10.1.0 is-ci: 3.0.1 lazy-val: 1.0.5 - read-config-file: 6.3.2 simple-update-notifier: 2.0.0 yargs: 17.7.2 transitivePeerDependencies: + - bluebird - electron-builder-squirrel-windows - supports-color @@ -2976,9 +3540,22 @@ snapshots: transitivePeerDependencies: - supports-color + electron-publish@26.0.11: + dependencies: + '@types/fs-extra': 9.0.13 + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + chalk: 4.1.2 + form-data: 4.0.4 + fs-extra: 10.1.0 + lazy-val: 1.0.5 + mime: 2.6.0 + transitivePeerDependencies: + - supports-color + electron-to-chromium@1.5.237: {} - electron@38.3.0: + electron@https://codeload.github.com/castlabs/electron-releases/tar.gz/678b5c7761825c5af936f5c67a9101f3fc6ab750: dependencies: '@electron/get': 2.0.3 '@types/node': 22.18.10 @@ -2990,6 +3567,11 @@ snapshots: emoji-regex@9.2.2: {} + encoding@0.1.13: + dependencies: + iconv-lite: 0.6.3 + optional: true + end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -3055,6 +3637,8 @@ snapshots: escape-string-regexp@4.0.0: optional: true + exponential-backoff@3.1.3: {} + extract-zip@2.0.1: dependencies: debug: 4.4.1 @@ -3105,6 +3689,12 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 + fs-extra@11.3.2: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fs-extra@8.1.0: dependencies: graceful-fs: 4.2.11 @@ -3173,6 +3763,14 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + global-agent@3.0.0: dependencies: boolean: 3.2.0 @@ -3238,6 +3836,13 @@ snapshots: transitivePeerDependencies: - supports-color + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + http2-wrapper@1.0.3: dependencies: quick-lru: 5.1.1 @@ -3250,6 +3855,17 @@ snapshots: transitivePeerDependencies: - supports-color + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + iconv-corefoundation@1.1.7: dependencies: cli-truncate: 2.1.0 @@ -3262,6 +3878,12 @@ snapshots: ieee754@1.2.1: {} + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + infer-owner@1.0.4: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -3269,12 +3891,20 @@ snapshots: inherits@2.0.4: {} + ip-address@10.0.1: {} + is-ci@3.0.1: dependencies: ci-info: 3.9.0 is-fullwidth-code-point@3.0.0: {} + is-interactive@1.0.0: {} + + is-lambda@1.0.1: {} + + is-unicode-supported@0.1.0: {} + isarray@1.0.0: {} isbinaryfile@4.0.10: {} @@ -3441,6 +4071,11 @@ snapshots: lodash@4.17.21: {} + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -3457,10 +4092,34 @@ snapshots: dependencies: yallist: 4.0.0 + lru-cache@7.18.3: {} + magic-string@0.30.19: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + make-fetch-happen@10.2.1: + dependencies: + agentkeepalive: 4.6.0 + cacache: 16.1.3 + http-cache-semantics: 4.2.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 2.1.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.4 + promise-retry: 2.0.1 + socks-proxy-agent: 7.0.0 + ssri: 9.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + matcher@3.0.0: dependencies: escape-string-regexp: 4.0.0 @@ -3476,10 +4135,16 @@ snapshots: mime@2.6.0: {} + mimic-fn@2.1.0: {} + mimic-response@1.0.1: {} mimic-response@3.1.0: {} + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -3494,6 +4159,30 @@ snapshots: minimist@1.2.8: {} + minipass-collect@1.0.2: + dependencies: + minipass: 3.3.6 + + minipass-fetch@2.1.2: + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + + minipass-flush@1.0.5: + dependencies: + minipass: 3.3.6 + + minipass-pipeline@1.2.4: + dependencies: + minipass: 3.3.6 + + minipass-sized@1.0.3: + dependencies: + minipass: 3.3.6 + minipass@3.3.6: dependencies: yallist: 4.0.0 @@ -3517,11 +4206,25 @@ snapshots: nanoid@3.3.11: {} + negotiator@0.6.4: {} + + node-abi@3.78.0: + dependencies: + semver: 7.7.2 + node-addon-api@1.7.2: optional: true + node-api-version@0.2.1: + dependencies: + semver: 7.7.2 + node-releases@2.0.23: {} + nopt@6.0.0: + dependencies: + abbrev: 1.1.1 + normalize-path@3.0.0: {} normalize-url@6.1.0: {} @@ -3533,8 +4236,32 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + p-cancelable@2.1.1: {} + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + package-json-from-dist@1.0.1: {} path-is-absolute@1.0.1: {} @@ -3546,6 +4273,8 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + pe-library@0.4.1: {} + pend@1.2.0: {} picocolors@1.1.1: {} @@ -3566,10 +4295,14 @@ snapshots: prettier@3.6.2: {} + proc-log@2.0.1: {} + process-nextick-args@2.0.1: {} progress@2.0.3: {} + promise-inflight@1.0.1: {} + promise-retry@2.0.1: dependencies: err-code: 2.0.3 @@ -3596,6 +4329,12 @@ snapshots: dependencies: loose-envify: 1.4.0 + read-binary-file-arch@1.0.6: + dependencies: + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + read-config-file@6.3.2: dependencies: config-file-ts: 0.2.6 @@ -3627,14 +4366,27 @@ snapshots: require-directory@2.1.1: {} + resedit@1.7.2: + dependencies: + pe-library: 0.4.1 + resolve-alpn@1.2.1: {} responselike@2.0.1: dependencies: lowercase-keys: 2.0.0 + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + retry@0.12.0: {} + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + roarr@2.15.4: dependencies: boolean: 3.2.0 @@ -3696,6 +4448,8 @@ snapshots: semver-compare@1.0.0: optional: true + semver@5.7.2: {} + semver@6.3.1: {} semver@7.7.2: {} @@ -3713,6 +4467,8 @@ snapshots: shell-quote@1.8.3: {} + signal-exit@3.0.7: {} + signal-exit@4.1.0: {} simple-update-notifier@2.0.0: @@ -3726,8 +4482,20 @@ snapshots: is-fullwidth-code-point: 3.0.0 optional: true - smart-buffer@4.2.0: - optional: true + smart-buffer@4.2.0: {} + + socks-proxy-agent@7.0.0: + dependencies: + agent-base: 6.0.2 + debug: 4.4.1 + socks: 2.8.7 + transitivePeerDependencies: + - supports-color + + socks@2.8.7: + dependencies: + ip-address: 10.0.1 + smart-buffer: 4.2.0 source-map-js@1.2.1: {} @@ -3743,6 +4511,10 @@ snapshots: sprintf-js@1.1.3: optional: true + ssri@9.0.1: + dependencies: + minipass: 3.3.6 + stat-mode@1.0.0: {} string-width@4.2.3: @@ -3821,6 +4593,10 @@ snapshots: async-exit-hook: 2.0.1 fs-extra: 10.1.0 + tiny-async-pool@1.3.0: + dependencies: + semver: 5.7.2 + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -3874,6 +4650,14 @@ snapshots: undici-types@6.21.0: {} + unique-filename@2.0.1: + dependencies: + unique-slug: 3.0.0 + + unique-slug@3.0.0: + dependencies: + imurmurhash: 0.1.4 + universalify@0.1.2: {} universalify@2.0.1: {} @@ -3913,6 +4697,10 @@ snapshots: jiti: 2.6.1 lightningcss: 1.30.2 + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -3958,6 +4746,8 @@ snapshots: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 + yocto-queue@0.1.0: {} + zip-stream@4.1.1: dependencies: archiver-utils: 3.0.4 From e99493dbf5adf471da127a32fc7c0ddcb13f5a7e Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Sat, 18 Oct 2025 18:25:26 +0900 Subject: [PATCH 2/3] feat: migrate to automatic Widevine CDM installation using Component Updater --- apps/browser/scripts/evs-sign.js | 10 +-- apps/browser/src/main.ts | 117 +++++++++++-------------------- 2 files changed, 45 insertions(+), 82 deletions(-) diff --git a/apps/browser/scripts/evs-sign.js b/apps/browser/scripts/evs-sign.js index 24e184c..a59d05d 100644 --- a/apps/browser/scripts/evs-sign.js +++ b/apps/browser/scripts/evs-sign.js @@ -268,7 +268,7 @@ exports.default = async function(context) { throw new Error('EVS environment not configured. Please follow the setup instructions above.'); } - // Step 2: Sign the package with EVS VMP FIRST (before adding Widevine CDM) + // Step 2: Sign the package with EVS VMP console.log('\n[EVS] Step 2: Sign with EVS VMP'); const success = signPackage(appOutDir, false); @@ -276,10 +276,10 @@ exports.default = async function(context) { throw new Error('EVS signing failed'); } - // Step 3: Copy Widevine CDM to app bundle AFTER signing - // This prevents EVS from modifying the Widevine CDM dylib signature - console.log('\n[EVS] Step 3: Copy Widevine CDM (after EVS signing)'); - copyWidevineCdm(appOutDir, electronPlatformName); + // NOTE: Widevine CDM is NOT manually bundled + // castlabs v16+ uses Component Updater to automatically download and install CDM + // Manual bundling is not recommended and has legal implications + console.log('\n[EVS] Widevine CDM will be downloaded automatically by Component Updater on first run'); }; // Allow running this script directly for verification diff --git a/apps/browser/src/main.ts b/apps/browser/src/main.ts index ca32033..bc14246 100644 --- a/apps/browser/src/main.ts +++ b/apps/browser/src/main.ts @@ -11,6 +11,9 @@ import { WebContentsView, } from "electron"; +// @ts-ignore - castlabs specific API +import { components } from "electron"; + import path from "path"; import fs from "fs"; @@ -19,78 +22,10 @@ console.log('[Widevine] Electron app path:', app.getAppPath()); console.log('[Widevine] Electron version:', process.versions.electron); console.log('[Widevine] Process versions:', JSON.stringify(process.versions, null, 2)); -// Set Widevine CDM path - CRITICAL for production builds -const isPackaged = app.isPackaged; -console.log('[Widevine] Is packaged:', isPackaged); - -if (isPackaged) { - // Production: Widevine CDM is bundled in the app - // Try multiple possible locations - - console.log('[Widevine] process.resourcesPath:', process.resourcesPath); - console.log('[Widevine] __dirname:', __dirname); - - // Location 1: Resources/WidevineCdm (preferred for component updater) - const resourcesPath = path.join(process.resourcesPath, 'WidevineCdm'); - - // Location 2: Frameworks/Electron Framework.framework/.../Libraries/WidevineCdm - const frameworkPath = path.join( - process.resourcesPath, - '..', - 'Frameworks', - 'Electron Framework.framework', - 'Versions', - 'A', - 'Libraries', - 'WidevineCdm' - ); - - console.log('[Widevine] Checking Resources path:', resourcesPath); - console.log('[Widevine] Checking Framework path:', frameworkPath); - - // Use whichever path exists - const cdmBasePath = fs.existsSync(resourcesPath) ? resourcesPath : frameworkPath; - console.log('[Widevine] Using CDM base path:', cdmBasePath); - console.log('[Widevine] CDM base path exists:', fs.existsSync(cdmBasePath)); - - // Find the Widevine CDM version directory - if (fs.existsSync(cdmBasePath)) { - const versions = fs.readdirSync(cdmBasePath).filter(f => f.match(/^\d+\.\d+\.\d+\.\d+$/)); - if (versions.length > 0) { - const latestVersion = versions.sort().reverse()[0]; - const cdmPath = path.join(cdmBasePath, latestVersion); - - console.log('[Widevine] CDM directory:', cdmPath); - console.log('[Widevine] CDM version:', latestVersion); - - // Verify the dylib exists - const dylibPath = path.join(cdmPath, '_platform_specific/mac_arm64/libwidevinecdm.dylib'); - console.log('[Widevine] dylib path:', dylibPath); - console.log('[Widevine] dylib exists:', fs.existsSync(dylibPath)); - - if (fs.existsSync(dylibPath)) { - // CRITICAL: widevine-cdm-path must point to the VERSION DIRECTORY (not dylib) - // Electron will look for manifest.json in this directory - console.log('[Widevine] Setting CDM path to version directory:', cdmPath); - app.commandLine.appendSwitch('widevine-cdm-path', cdmPath); - app.commandLine.appendSwitch('widevine-cdm-version', latestVersion); - - // Verify manifest.json exists - const manifestPath = path.join(cdmPath, 'manifest.json'); - console.log('[Widevine] manifest.json exists:', fs.existsSync(manifestPath)); - } else { - console.error('[Widevine] ✗ libwidevinecdm.dylib not found!'); - } - } else { - console.error('[Widevine] No Widevine CDM version found in:', cdmBasePath); - } - } else { - console.error('[Widevine] Widevine CDM directory not found:', cdmBasePath); - } -} else { - // Development: Widevine CDM is in Application Support - console.log('[Widevine] Development mode - CDM will be loaded from Application Support'); -} +// NOTE: Do NOT manually set widevine-cdm-path or widevine-cdm-version +// castlabs v16+ uses Component Updater to automatically download and install Widevine CDM +// Manual CDM bundling is not recommended and has legal implications +console.log('[Widevine] Using Component Updater for automatic CDM installation'); // Enable Widevine features and DRM app.commandLine.appendSwitch('enable-features', 'PlatformEncryptedDolbyVision'); @@ -108,8 +43,38 @@ console.log('[Widevine] Command line switches configured'); console.log('[Widevine] Chromium verbose logging enabled'); // Verify Widevine plugin on startup -app.on('ready', () => { - console.log('[Widevine] App ready - checking Widevine...'); +app.on('ready', async () => { + console.log('[Component] App ready'); + + // @ts-ignore - castlabs specific API + if (typeof components !== 'undefined') { + // @ts-ignore + console.log('[Component] Initial status:', components.status()); + // @ts-ignore + console.log('[Component] Updates enabled:', components.updatesEnabled); + + console.log('[Component] Waiting for Widevine CDM...'); + const startTime = Date.now(); + + try { + // @ts-ignore + const results = await components.whenReady(); + const elapsed = Date.now() - startTime; + console.log(`[Component] ✓ Ready after ${elapsed}ms`); + console.log('[Component] Results:', results); + // @ts-ignore + console.log('[Component] Final status:', components.status()); + } catch (error: any) { + console.error('[Component] ✗ Failed:', error); + if (error.errors) { + error.errors.forEach((err: any, i: number) => { + console.error(`[Component] Error ${i+1}:`, err); + }); + } + } + } else { + console.warn('[Component] components API not available - not using castlabs electron?'); + } // @ts-ignore - castlabs specific API if (typeof app.isEVSEnabled === 'function') { @@ -117,9 +82,7 @@ app.on('ready', () => { console.log('[Widevine] EVS enabled:', app.isEVSEnabled()); } - // Log Widevine CDM path - const appPath = app.getAppPath(); - console.log('[Widevine] App path:', appPath); + console.log('[Widevine] App path:', app.getAppPath()); console.log('[Widevine] __dirname:', __dirname); }); From e293f8d6be80a16cb03445189269df459651c191 Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Sat, 18 Oct 2025 18:33:51 +0900 Subject: [PATCH 3/3] refactor: remove Widevine CDM verification code and simplify logging --- apps/browser/src/main.ts | 93 +++++++++++++++-------------- apps/browser/src/webview-preload.ts | 56 +---------------- 2 files changed, 50 insertions(+), 99 deletions(-) diff --git a/apps/browser/src/main.ts b/apps/browser/src/main.ts index bc14246..10ab8d3 100644 --- a/apps/browser/src/main.ts +++ b/apps/browser/src/main.ts @@ -18,72 +18,69 @@ import path from "path"; import fs from "fs"; // Widevine CDM configuration for castlabs electron-releases -console.log('[Widevine] Electron app path:', app.getAppPath()); -console.log('[Widevine] Electron version:', process.versions.electron); -console.log('[Widevine] Process versions:', JSON.stringify(process.versions, null, 2)); +console.log("[Widevine] Electron app path:", app.getAppPath()); +console.log("[Widevine] Electron version:", process.versions.electron); +console.log( + "[Widevine] Process versions:", + JSON.stringify(process.versions, null, 2) +); // NOTE: Do NOT manually set widevine-cdm-path or widevine-cdm-version // castlabs v16+ uses Component Updater to automatically download and install Widevine CDM // Manual CDM bundling is not recommended and has legal implications -console.log('[Widevine] Using Component Updater for automatic CDM installation'); +console.log( + "[Widevine] Using Component Updater for automatic CDM installation" +); // Enable Widevine features and DRM -app.commandLine.appendSwitch('enable-features', 'PlatformEncryptedDolbyVision'); +app.commandLine.appendSwitch("enable-features", "PlatformEncryptedDolbyVision"); // Additional flags for Widevine CDM -app.commandLine.appendSwitch('ignore-certificate-errors'); // For development/testing -app.commandLine.appendSwitch('allow-running-insecure-content'); // For development/testing - -// CRITICAL: Enable Chromium verbose logging for debugging -app.commandLine.appendSwitch('enable-logging'); -app.commandLine.appendSwitch('v', '1'); // Verbosity level 1 -app.commandLine.appendSwitch('vmodule', 'widevine*=3,cdm*=3,drm*=3,eme*=3,component*=3'); // Detailed logging for specific modules - -console.log('[Widevine] Command line switches configured'); -console.log('[Widevine] Chromium verbose logging enabled'); +app.commandLine.appendSwitch("ignore-certificate-errors"); // For development/testing +app.commandLine.appendSwitch("allow-running-insecure-content"); // For development/testing -// Verify Widevine plugin on startup -app.on('ready', async () => { - console.log('[Component] App ready'); - +// Wait for Widevine CDM to be ready before creating windows +app.on("ready", async () => { // @ts-ignore - castlabs specific API - if (typeof components !== 'undefined') { + if (typeof components !== "undefined") { // @ts-ignore - console.log('[Component] Initial status:', components.status()); + console.log("[Component] Initial status:", components.status()); // @ts-ignore - console.log('[Component] Updates enabled:', components.updatesEnabled); - - console.log('[Component] Waiting for Widevine CDM...'); + console.log("[Component] Updates enabled:", components.updatesEnabled); + + console.log("[Component] Waiting for Widevine CDM..."); const startTime = Date.now(); - + try { // @ts-ignore const results = await components.whenReady(); const elapsed = Date.now() - startTime; console.log(`[Component] ✓ Ready after ${elapsed}ms`); - console.log('[Component] Results:', results); + console.log("[Component] Results:", results); // @ts-ignore - console.log('[Component] Final status:', components.status()); + console.log("[Component] Final status:", components.status()); } catch (error: any) { - console.error('[Component] ✗ Failed:', error); + console.error("[Component] ✗ Failed:", error); if (error.errors) { error.errors.forEach((err: any, i: number) => { - console.error(`[Component] Error ${i+1}:`, err); + console.error(`[Component] Error ${i + 1}:`, err); }); } } } else { - console.warn('[Component] components API not available - not using castlabs electron?'); + console.warn( + "[Component] components API not available - not using castlabs electron?" + ); } - + // @ts-ignore - castlabs specific API - if (typeof app.isEVSEnabled === 'function') { + if (typeof app.isEVSEnabled === "function") { // @ts-ignore - console.log('[Widevine] EVS enabled:', app.isEVSEnabled()); + console.log("[Widevine] EVS enabled:", app.isEVSEnabled()); } - - console.log('[Widevine] App path:', app.getAppPath()); - console.log('[Widevine] __dirname:', __dirname); + + console.log("[Widevine] App path:", app.getAppPath()); + console.log("[Widevine] __dirname:", __dirname); }); // URL validation and security @@ -358,15 +355,21 @@ function createTab(url: string = "https://www.google.com"): Tab { ...(hasWebviewPreload ? { preload: webviewPreloadPath } : {}), }, }); - + // Enable Widevine CDM for this webContents - view.webContents.session.setPermissionRequestHandler((_webContents: any, permission: string, callback: (result: boolean) => void) => { - if (permission === 'media') { - callback(true); // Allow media permissions for DRM - } else { - callback(false); + view.webContents.session.setPermissionRequestHandler( + ( + _webContents: any, + permission: string, + callback: (result: boolean) => void + ) => { + if (permission === "media") { + callback(true); // Allow media permissions for DRM + } else { + callback(false); + } } - }); + ); // Set initial user agent based on URL const userAgent = getUserAgentForUrl(url); @@ -1403,7 +1406,9 @@ app.whenReady().then(async () => { // Widevine CDM should be automatically available in castlabs electron-releases // No need to wait for components - it's built-in and signed - console.log("[Widevine] Using castlabs electron-releases with built-in Widevine CDM"); + console.log( + "[Widevine] Using castlabs electron-releases with built-in Widevine CDM" + ); // Set dock icon for macOS if (process.platform === "darwin") { diff --git a/apps/browser/src/webview-preload.ts b/apps/browser/src/webview-preload.ts index 65379ed..9992a17 100644 --- a/apps/browser/src/webview-preload.ts +++ b/apps/browser/src/webview-preload.ts @@ -37,7 +37,7 @@ function notifyThemeColor() { // Fallback if hostname is not accessible domain = ""; } - + ipcRenderer.send("webview-theme-color-extracted", { themeColor, domain, @@ -254,57 +254,3 @@ function setupNavigationGestures() { // Setup gesture detection immediately setupNavigationGestures(); - -// Widevine CDM verification -function checkWidevineCdm() { - console.log("[Widevine] Checking Widevine CDM availability..."); - - // Check if navigator.plugins is available - // @ts-ignore - plugins exists in browser context - if (navigator.plugins) { - console.log( - "[Widevine] Available plugins:", - // @ts-ignore - Array.from(navigator.plugins).map((p: any) => p.name) - ); - } - - // Check for Widevine support using EME API - // @ts-ignore - requestMediaKeySystemAccess exists in browser context - if (navigator.requestMediaKeySystemAccess) { - // @ts-ignore - navigator - .requestMediaKeySystemAccess("com.widevine.alpha", [ - { - initDataTypes: ["cenc"], - videoCapabilities: [ - { - contentType: 'video/mp4; codecs="avc1.42E01E"', - }, - ], - }, - ]) - .then((keySystemAccess) => { - console.log("[Widevine] ✓ Widevine CDM is available and working!"); - console.log("[Widevine] Key system:", keySystemAccess.keySystem); - }) - .catch((error) => { - console.error("[Widevine] ✗ Widevine CDM is NOT available:", error); - console.error( - "[Widevine] DRM content will not play. Please ensure Widevine is properly configured." - ); - }); - } else { - console.error( - "[Widevine] ✗ EME API (requestMediaKeySystemAccess) is not available" - ); - } -} - -// Check Widevine when page loads -window.addEventListener("load", () => { - setTimeout(checkWidevineCdm, 500); -}); - -// Status bar is now a React component in the main renderer -// This preload script handles theme color extraction, corner masking, and navigation gestures