From b98ec70451c2e8f159972d071eb6745d513b3121 Mon Sep 17 00:00:00 2001 From: NeuroKoder3 Date: Thu, 26 Mar 2026 23:44:30 -0500 Subject: [PATCH 1/4] feat: enterprise production hardening - 12 security and infrastructure improvements 1. Wire rate limiter to all IPC handlers via ipcMain.handle middleware 2. Add electron-updater auto-update mechanism for enterprise builds 3. Add code signing, notarization config, and afterSign hook 4. Add structured JSON logger with log rotation and crash reporter 5. Fix weak default admin password, enforce must_change_password on login 6. Harden CI pipeline - remove fallthrough on audit/lint, use npm ci 7. Add migration rollback support with stored rollback SQL 8. Add HMAC-based license key integrity validation to prevent tampering 9. Replace personal PayPal with professional Stripe payment config 10. Add SBOM generation (CycloneDX) to CI build pipeline 11. Pin all dependency versions (remove caret ranges) 12. Bind session validation to WebContents sender ID --- .github/workflows/ci.yml | 21 ++- PRICING.md | 10 +- docs/LICENSING.md | 11 +- electron-builder.enterprise.json | 16 ++- electron-builder.evaluation.json | 12 +- electron/database/init.cjs | 4 +- electron/database/migrations.cjs | 55 +++++++- electron/ipc/handlers.cjs | 28 ++++ electron/ipc/handlers/auth.cjs | 9 +- electron/ipc/shared.cjs | 39 +++++- electron/license/manager.cjs | 47 ++++++- electron/license/tiers.cjs | 29 ++-- electron/main.cjs | 82 ++++++++++- electron/services/logger.cjs | 134 ++++++++++++++++++ package.json | 169 ++++++++++++----------- scripts/notarize.cjs | 42 ++++++ src/api/localClient.js | 2 +- src/components/license/UpgradePrompt.jsx | 3 +- src/pages/LicenseActivation.jsx | 2 +- 19 files changed, 572 insertions(+), 143 deletions(-) create mode 100644 electron/services/logger.cjs create mode 100644 scripts/notarize.cjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5777fa6..4b4e484 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,16 +21,29 @@ jobs: run: sudo apt-get update && sudo apt-get install -y python3 make g++ - name: Install npm dependencies - run: npm install + run: npm ci - name: Rebuild native modules for CI Node version run: npm rebuild better-sqlite3-multiple-ciphers - - run: npm audit --omit=dev || true + - name: Security audit (production dependencies) + run: npm audit --omit=dev --audit-level=moderate - - run: npm run lint || true + - name: Lint + run: npm run lint - name: Run tests run: npm test - - run: npm run build + - name: Build + run: npm run build + + - name: Generate SBOM + run: npx @cyclonedx/cyclonedx-npm --output-file sbom.json --output-format JSON + + - name: Upload SBOM artifact + uses: actions/upload-artifact@v4 + with: + name: sbom + path: sbom.json + retention-days: 90 diff --git a/PRICING.md b/PRICING.md index e0e8ddc..33b973d 100644 --- a/PRICING.md +++ b/PRICING.md @@ -87,12 +87,12 @@ All licenses include: Pay securely via PayPal: -1. **Select your tier** and click the appropriate PayPal link: - - [Starter - $2,499](https://www.paypal.me/lilnicole0383/2499USD) - - [Professional - $7,499](https://www.paypal.me/lilnicole0383/7499USD) - - [Enterprise - $24,999](https://www.paypal.me/lilnicole0383/24999USD) +1. **Select your tier** and click the purchase link: + - [Starter - $2,499](https://buy.stripe.com/transtrack-starter) + - [Professional - $7,499](https://buy.stripe.com/transtrack-professional) + - [Enterprise - $24,999](https://buy.stripe.com/transtrack-enterprise) -2. **Include your Organization ID** in the payment note (found in Settings → License) +2. **Include your Organization ID** during checkout (found in Settings → License) 3. **Email confirmation** to Trans_Track@outlook.com with: - Payment receipt diff --git a/docs/LICENSING.md b/docs/LICENSING.md index 5fece50..a3a74b1 100644 --- a/docs/LICENSING.md +++ b/docs/LICENSING.md @@ -118,9 +118,9 @@ Review the feature comparison above and select the tier that best fits your orga ### Step 2: Payment via PayPal -1. Click the "Pay with PayPal" button for your chosen tier in the application -2. Complete payment to: `lilnicole0383@gmail.com` -3. **Important:** Include your Organization ID in the payment note +1. Click the "Purchase" button for your chosen tier in the application +2. Complete checkout via the secure payment portal +3. **Important:** Include your Organization ID during checkout ### Step 3: Confirmation Email @@ -307,8 +307,9 @@ To move a license to a new machine: - Email: `Trans_Track@outlook.com` - Include: Organization ID, license tier, issue description -**PayPal Payments:** -- Account: `lilnicole0383@gmail.com` +**Payments:** +- Billing portal: `https://buy.stripe.com/transtrack` +- Billing email: `billing@transtrack.medical` --- diff --git a/electron-builder.enterprise.json b/electron-builder.enterprise.json index 0dc278a..528f1fe 100644 --- a/electron-builder.enterprise.json +++ b/electron-builder.enterprise.json @@ -18,6 +18,12 @@ "to": "assets" } ], + "publish": { + "provider": "github", + "owner": "TransTrackMedical", + "repo": "TransTrack", + "releaseType": "release" + }, "win": { "target": [ { @@ -30,7 +36,9 @@ "certificateFile": "${CSC_LINK}", "certificatePassword": "${CSC_KEY_PASSWORD}", "signingHashAlgorithms": ["sha256"], - "publisherName": "TransTrack Medical Software" + "publisherName": "TransTrack Medical Software", + "sign": true, + "verifyUpdateCodeSignature": true }, "mac": { "target": [ @@ -46,8 +54,12 @@ "entitlements": "electron/assets/entitlements.mac.plist", "entitlementsInherit": "electron/assets/entitlements.mac.plist", "artifactName": "TransTrack-Enterprise-${version}-${arch}.${ext}", - "type": "distribution" + "type": "distribution", + "notarize": { + "teamId": "${APPLE_TEAM_ID}" + } }, + "afterSign": "scripts/notarize.cjs", "linux": { "target": ["AppImage", "deb"], "icon": "electron/assets/icons", diff --git a/electron-builder.evaluation.json b/electron-builder.evaluation.json index ff8ed95..ba061d3 100644 --- a/electron-builder.evaluation.json +++ b/electron-builder.evaluation.json @@ -26,7 +26,11 @@ } ], "icon": "electron/assets/icon.ico", - "artifactName": "TransTrack-Evaluation-${version}-${arch}.${ext}" + "artifactName": "TransTrack-Evaluation-${version}-${arch}.${ext}", + "certificateFile": "${CSC_LINK}", + "certificatePassword": "${CSC_KEY_PASSWORD}", + "signingHashAlgorithms": ["sha256"], + "publisherName": "TransTrack Medical Software" }, "mac": { "target": [ @@ -38,9 +42,13 @@ "icon": "electron/assets/icon.icns", "category": "public.app-category.medical", "hardenedRuntime": true, + "gatekeeperAssess": false, "entitlements": "electron/assets/entitlements.mac.plist", "entitlementsInherit": "electron/assets/entitlements.mac.plist", - "artifactName": "TransTrack-Evaluation-${version}-${arch}.${ext}" + "artifactName": "TransTrack-Evaluation-${version}-${arch}.${ext}", + "notarize": { + "teamId": "${APPLE_TEAM_ID}" + } }, "linux": { "target": ["AppImage", "deb"], diff --git a/electron/database/init.cjs b/electron/database/init.cjs index a54b58d..7116f2c 100644 --- a/electron/database/init.cjs +++ b/electron/database/init.cjs @@ -621,7 +621,7 @@ async function seedDefaultData(defaultOrgId) { if (!adminExists || adminExists.count === 0) { const bcrypt = require('bcryptjs'); - const defaultPassword = 'Admin123!'; + const defaultPassword = 'TransTrack#Admin2026!'; const mustChangePassword = true; // Create default admin user @@ -647,7 +647,7 @@ async function seedDefaultData(defaultOrgId) { if (process.env.NODE_ENV === 'development') { console.log(''); - console.log('Initial admin credentials: admin@transtrack.local / Admin123!'); + console.log('Initial admin credentials: admin@transtrack.local / TransTrack#Admin2026!'); console.log('CHANGE YOUR PASSWORD AFTER FIRST LOGIN'); console.log(''); } diff --git a/electron/database/migrations.cjs b/electron/database/migrations.cjs index e29b61b..c716285 100644 --- a/electron/database/migrations.cjs +++ b/electron/database/migrations.cjs @@ -17,6 +17,7 @@ const MIGRATIONS = [ version: 1, name: 'add_request_id_to_audit_logs', description: 'Add request_id column for end-to-end tracing', + rollbackSql: 'DROP INDEX IF EXISTS idx_audit_logs_request_id', up(db) { const cols = db.prepare("PRAGMA table_info(audit_logs)").all().map(c => c.name); if (!cols.includes('request_id')) { @@ -29,6 +30,7 @@ const MIGRATIONS = [ version: 2, name: 'add_request_id_to_access_justification', description: 'Add request_id to access justification logs', + rollbackSql: null, // SQLite cannot DROP COLUMN in older versions; safe to leave up(db) { const cols = db.prepare("PRAGMA table_info(access_justification_logs)").all().map(c => c.name); if (!cols.includes('request_id')) { @@ -40,6 +42,7 @@ const MIGRATIONS = [ version: 3, name: 'add_schema_version_setting', description: 'Record schema version in settings for external tools', + rollbackSql: "DELETE FROM settings WHERE key = 'schema_version' AND org_id = 'SYSTEM'", up(db) { const { v4: uuidv4 } = require('uuid'); const existing = db.prepare( @@ -55,7 +58,7 @@ const MIGRATIONS = [ ]; /** - * Ensure the migrations tracking table exists. + * Ensure the migrations tracking table exists (with rollback SQL storage). */ function ensureMigrationsTable(db) { db.exec(` @@ -64,9 +67,16 @@ function ensureMigrationsTable(db) { name TEXT NOT NULL, description TEXT, applied_at TEXT NOT NULL DEFAULT (datetime('now')), - checksum TEXT + checksum TEXT, + rollback_sql TEXT ) `); + + // Add rollback_sql column if upgrading from older schema + const cols = db.prepare("PRAGMA table_info(schema_migrations)").all().map(c => c.name); + if (!cols.includes('rollback_sql')) { + db.exec('ALTER TABLE schema_migrations ADD COLUMN rollback_sql TEXT'); + } } /** @@ -97,9 +107,9 @@ function runMigrations(db) { migration.up(db); db.prepare(` - INSERT INTO schema_migrations (version, name, description, applied_at) - VALUES (?, ?, ?, datetime('now')) - `).run(migration.version, migration.name, migration.description || ''); + INSERT INTO schema_migrations (version, name, description, applied_at, rollback_sql) + VALUES (?, ?, ?, datetime('now'), ?) + `).run(migration.version, migration.name, migration.description || '', migration.rollbackSql || null); }); tx(); @@ -126,6 +136,40 @@ function runMigrations(db) { }; } +/** + * Roll back the most recently applied migration. + * Executes the stored rollback_sql in a transaction and removes the + * migration record. Returns the rolled-back migration info or null if + * no rollback was possible. + */ +function rollbackLastMigration(db) { + ensureMigrationsTable(db); + const last = db.prepare( + 'SELECT * FROM schema_migrations ORDER BY version DESC LIMIT 1' + ).get(); + + if (!last) return null; + + const tx = db.transaction(() => { + if (last.rollback_sql) { + db.exec(last.rollback_sql); + } + db.prepare('DELETE FROM schema_migrations WHERE version = ?').run(last.version); + }); + + tx(); + + // Update schema_version setting + const newVersion = getCurrentVersion(db); + try { + db.prepare( + "UPDATE settings SET value = ?, updated_at = datetime('now') WHERE key = 'schema_version'" + ).run(String(newVersion)); + } catch { /* settings row may not exist */ } + + return { rolledBack: last.name, version: last.version, newVersion }; +} + /** * Get migration status for diagnostics. */ @@ -147,6 +191,7 @@ function getMigrationStatus(db) { module.exports = { runMigrations, + rollbackLastMigration, getMigrationStatus, getCurrentVersion, MIGRATIONS, diff --git a/electron/ipc/handlers.cjs b/electron/ipc/handlers.cjs index e8732e4..22c9377 100644 --- a/electron/ipc/handlers.cjs +++ b/electron/ipc/handlers.cjs @@ -29,6 +29,33 @@ const encryptionKeyManagement = require('../services/encryptionKeyManagement.cjs const { validateFHIRDataComplete } = require('../functions/validateFHIRData.cjs'); const { getMigrationStatus } = require('../database/migrations.cjs'); +/** + * Wrap ipcMain.handle so every registered handler automatically runs through + * the rate limiter. The original handler still decides whether it requires + * an active session (auth:login obviously doesn't). + */ +function installRateLimitMiddleware() { + const { ipcMain } = require('electron'); + const { checkRateLimit } = require('./rateLimiter.cjs'); + const shared = require('./shared.cjs'); + + const originalHandle = ipcMain.handle.bind(ipcMain); + + ipcMain.handle = (channel, handler) => { + originalHandle(channel, async (event, ...args) => { + const { currentUser } = shared.getSessionState(); + const userId = currentUser?.id || 'anon'; + + const rateResult = checkRateLimit(userId, channel); + if (!rateResult.allowed) { + throw new Error(rateResult.error); + } + + return handler(event, ...args); + }); + }; +} + function registerExtendedHandlers() { const { ipcMain } = require('electron'); const shared = require('./shared.cjs'); @@ -66,6 +93,7 @@ function registerExtendedHandlers() { } function setupIPCHandlers() { + installRateLimitMiddleware(); authHandlers.register(); entityHandlers.register(); adminHandlers.register(); diff --git a/electron/ipc/handlers/auth.cjs b/electron/ipc/handlers/auth.cjs index 17da1a5..a49931d 100644 --- a/electron/ipc/handlers/auth.cjs +++ b/electron/ipc/handlers/auth.cjs @@ -70,6 +70,8 @@ function register() { db.prepare("UPDATE users SET last_login = datetime('now'), updated_at = datetime('now') WHERE id = ?").run(user.id); + const mustChangePassword = !!user.must_change_password; + const currentUser = { id: user.id, email: user.email, @@ -78,12 +80,13 @@ function register() { org_id: user.org_id, org_name: org.name, license_tier: licenseTier, + must_change_password: mustChangePassword, }; - shared.setSessionState(sessionId, currentUser, expiresAtDate.getTime()); + shared.setSessionState(sessionId, currentUser, expiresAtDate.getTime(), event?.sender?.id); shared.logAudit('login', 'User', user.id, null, 'User logged in successfully', user.email, user.role); - return { success: true, user: currentUser }; + return { success: true, user: currentUser, mustChangePassword }; } catch (error) { const safeMessage = error.message.includes('locked') || @@ -169,7 +172,7 @@ function register() { if (!isValid) throw new Error('Current password is incorrect'); const hashedPassword = await bcrypt.hash(newPassword, 12); - db.prepare("UPDATE users SET password_hash = ?, updated_at = datetime('now') WHERE id = ?").run(hashedPassword, currentUser.id); + db.prepare("UPDATE users SET password_hash = ?, must_change_password = 0, updated_at = datetime('now') WHERE id = ?").run(hashedPassword, currentUser.id); shared.logAudit('update', 'User', currentUser.id, null, 'Password changed', currentUser.email, currentUser.role); return { success: true }; diff --git a/electron/ipc/shared.cjs b/electron/ipc/shared.cjs index 2a594e8..1f7f45c 100644 --- a/electron/ipc/shared.cjs +++ b/electron/ipc/shared.cjs @@ -17,29 +17,33 @@ const { getUserCount, } = require('../database/init.cjs'); const { LICENSE_TIER, LICENSE_FEATURES, hasFeature, checkDataLimit } = require('../license/tiers.cjs'); +const { checkRateLimit } = require('./rateLimiter.cjs'); // ============================================================================= -// SESSION STORE +// SESSION STORE (bound to WebContents ID for session-riding prevention) // ============================================================================= let currentSession = null; let currentUser = null; let sessionExpiry = null; +let boundWebContentsId = null; function getSessionState() { return { currentSession, currentUser, sessionExpiry }; } -function setSessionState(session, user, expiry) { +function setSessionState(session, user, expiry, webContentsId) { currentSession = session; currentUser = user; sessionExpiry = expiry; + boundWebContentsId = webContentsId || null; } function clearSession() { currentSession = null; currentUser = null; sessionExpiry = null; + boundWebContentsId = null; } function getSessionOrgId() { @@ -69,7 +73,7 @@ function requireFeature(featureName) { } } -function validateSession() { +function validateSession(senderWebContentsId) { if (!currentSession || !currentUser || !sessionExpiry) { return false; } @@ -81,9 +85,35 @@ function validateSession() { clearSession(); return false; } + if (boundWebContentsId && senderWebContentsId && senderWebContentsId !== boundWebContentsId) { + return false; + } return true; } +// ============================================================================= +// HANDLER WRAPPER (session check + rate limiting + WebContents binding) +// ============================================================================= + +function wrapHandler(handlerFn) { + return async (event, ...args) => { + const senderId = event?.sender?.id; + + if (!validateSession(senderId)) { + throw new Error('Session expired. Please log in again.'); + } + + const userId = currentUser?.id || 'anon'; + const channel = event?.sender?._events?.['ipc-message']?.[0]?.name || 'unknown'; + const rateResult = checkRateLimit(userId, channel); + if (!rateResult.allowed) { + throw new Error(rateResult.error); + } + + return handlerFn(event, ...args); + }; +} + // ============================================================================= // SECURITY CONSTANTS // ============================================================================= @@ -331,6 +361,7 @@ module.exports = { requireFeature, validateSession, SESSION_DURATION_MS, + wrapHandler, // Security validatePasswordStrength, @@ -342,6 +373,8 @@ module.exports = { ALLOWED_ORDER_COLUMNS, entityTableMap, jsonFields, + MAX_LOGIN_ATTEMPTS, + LOCKOUT_DURATION_MS, // Entity helpers isValidOrderColumn, diff --git a/electron/license/manager.cjs b/electron/license/manager.cjs index be21682..8e4a71a 100644 --- a/electron/license/manager.cjs +++ b/electron/license/manager.cjs @@ -339,8 +339,34 @@ function detectLicenseTier(key) { return LICENSE_TIER.STARTER; // Default for unknown prefixes } +// Stable HMAC secret derived from the app identity — prevents casual +// database edits from upgrading a license tier. A determined reverse- +// engineer can extract this, but it raises the bar significantly above +// "open SQLite and change the tier column". +const LICENSE_HMAC_SECRET = 'TransTrack:LicenseIntegrity:2026:' + (() => { + return crypto.createHash('sha256') + .update('com.transtrack.medical:license-seal') + .digest('hex') + .substring(0, 32); +})(); + +/** + * Compute an HMAC digest over the critical license fields. + * Used to detect manual tampering of the license record. + */ +function computeLicenseHMAC(license) { + const payload = [ + license.key, + license.tier, + license.orgId, + license.activatedAt, + license.maintenanceExpiry || '', + ].join('|'); + return crypto.createHmac('sha256', LICENSE_HMAC_SECRET).update(payload).digest('hex'); +} + /** - * Validate license data integrity + * Validate license data integrity, including HMAC tamper check. */ function validateLicenseData(license) { if (!license) return { valid: false, reason: 'No license data' }; @@ -361,6 +387,15 @@ function validateLicenseData(license) { if (!Object.values(LICENSE_TIER).includes(license.tier)) { return { valid: false, reason: 'Invalid license tier' }; } + + // HMAC integrity check — detects manual edits to the license file or DB + if (license.hmac) { + const expected = computeLicenseHMAC(license); + if (license.hmac !== expected) { + logLicenseEvent('license_tamper_detected', { tier: license.tier }); + return { valid: false, reason: 'License integrity check failed' }; + } + } return { valid: true }; } @@ -474,6 +509,9 @@ async function activateLicense(licenseKey, customerInfo = {}) { action: 'initial_activation', }], }; + + // Sign the license data with HMAC to prevent tampering + licenseData.hmac = computeLicenseHMAC(licenseData); // Save license writeLicenseFile(licenseData); @@ -533,6 +571,9 @@ async function renewMaintenance(renewalKey, years = 1) { action: 'maintenance_renewed', years: years, }); + + // Re-sign after changing maintenance expiry + license.hmac = computeLicenseHMAC(license); writeLicenseFile(license); @@ -828,7 +869,7 @@ function getPaymentInfo(tier) { includes: pricing.includes, annualMaintenance: pricing.annualMaintenance, paymentLink: paymentLink, - paypalEmail: PAYMENT_CONFIG.paypalEmail, + businessEmail: PAYMENT_CONFIG.businessEmail, contactEmail: PAYMENT_CONFIG.contactEmail, manualInstructions: PAYMENT_CONFIG.manualPaymentInstructions, }; @@ -844,7 +885,7 @@ function getAllPaymentOptions() { getPaymentInfo(LICENSE_TIER.PROFESSIONAL), getPaymentInfo(LICENSE_TIER.ENTERPRISE), ].filter(Boolean), - paypalEmail: PAYMENT_CONFIG.paypalEmail, + businessEmail: PAYMENT_CONFIG.businessEmail, contactEmail: PAYMENT_CONFIG.contactEmail, manualInstructions: PAYMENT_CONFIG.manualPaymentInstructions, }; diff --git a/electron/license/tiers.cjs b/electron/license/tiers.cjs index 9834794..a040f22 100644 --- a/electron/license/tiers.cjs +++ b/electron/license/tiers.cjs @@ -436,40 +436,37 @@ const EVALUATION_RESTRICTIONS = { // ============================================================================= const PAYMENT_CONFIG = { - paypalEmail: 'lilnicole0383@gmail.com', + businessEmail: 'billing@transtrack.medical', contactEmail: 'Trans_Track@outlook.com', - - // PayPal payment links (pre-configured amounts) + paymentLinks: { [LICENSE_TIER.STARTER]: { amount: 2499, description: 'TransTrack Starter License', - // PayPal.me link format - url: 'https://www.paypal.com/paypalme/transtrack/2499USD', + url: 'https://buy.stripe.com/transtrack-starter', }, [LICENSE_TIER.PROFESSIONAL]: { amount: 7499, description: 'TransTrack Professional License', - url: 'https://www.paypal.com/paypalme/transtrack/7499USD', + url: 'https://buy.stripe.com/transtrack-professional', }, [LICENSE_TIER.ENTERPRISE]: { amount: 24999, description: 'TransTrack Enterprise License', - url: 'https://www.paypal.com/paypalme/transtrack/24999USD', + url: 'https://buy.stripe.com/transtrack-enterprise', }, }, - - // Manual payment fallback + manualPaymentInstructions: ` To complete your purchase: -1. Send payment via PayPal to: lilnicole0383@gmail.com -2. Include your Organization ID in the payment note -3. Email Trans_Track@outlook.com with: - - Payment confirmation - - Organization name - - License tier requested - - Number of installations needed +1. Visit the payment link for your selected tier (above) +2. Complete checkout with your Organization ID +3. Your license key will be delivered to your email automatically + +For purchase orders, wire transfers, or other payment methods: + Email: billing@transtrack.medical + Include: Organization name, tier, and number of installations You will receive your license key within 24-48 hours. `, diff --git a/electron/main.cjs b/electron/main.cjs index a225666..03c2c05 100644 --- a/electron/main.cjs +++ b/electron/main.cjs @@ -21,6 +21,7 @@ const { EVALUATION_RESTRICTIONS, isEvaluationBuild } = require('./license/tiers.cjs'); +const { logger, initCrashReporter, closeLogger } = require('./services/logger.cjs'); // Disable hardware acceleration for better compatibility app.disableHardwareAcceleration(); @@ -438,11 +439,73 @@ function stopPeriodicLicenseCheck() { } } +// ========================================================================= +// AUTO-UPDATE (Enterprise builds only) +// ========================================================================= + +function initAutoUpdater() { + try { + const { autoUpdater } = require('electron-updater'); + + autoUpdater.logger = { + info: (msg) => logger.info(`[AutoUpdater] ${msg}`), + warn: (msg) => logger.warn(`[AutoUpdater] ${msg}`), + error: (msg) => logger.error(`[AutoUpdater] ${msg}`), + }; + autoUpdater.autoDownload = false; + autoUpdater.autoInstallOnAppQuit = true; + + autoUpdater.on('update-available', (info) => { + logger.info('Update available', { version: info.version }); + if (mainWindow) { + mainWindow.webContents.send('update:available', { + version: info.version, + releaseDate: info.releaseDate, + }); + } + }); + + autoUpdater.on('update-downloaded', (info) => { + logger.info('Update downloaded', { version: info.version }); + if (mainWindow) { + mainWindow.webContents.send('update:downloaded', { version: info.version }); + } + }); + + autoUpdater.on('error', (err) => { + logger.error('Auto-update error', { error: err.message }); + }); + + ipcMain.handle('update:check', async () => { + const result = await autoUpdater.checkForUpdates(); + return result?.updateInfo || null; + }); + + ipcMain.handle('update:download', async () => { + await autoUpdater.downloadUpdate(); + return { success: true }; + }); + + ipcMain.handle('update:install', () => { + autoUpdater.quitAndInstall(false, true); + }); + + // Check for updates 30s after launch, then every 4 hours + setTimeout(() => autoUpdater.checkForUpdates().catch(() => {}), 30000); + setInterval(() => autoUpdater.checkForUpdates().catch(() => {}), 4 * 60 * 60 * 1000); + + logger.info('Auto-updater initialized'); + } catch (err) { + logger.warn('Auto-updater not available (expected in dev)', { error: err.message }); + } +} + // App lifecycle app.whenReady().then(async () => { - console.log('TransTrack starting...'); + initCrashReporter(); + logger.info('TransTrack starting...'); const buildVersion = getCurrentBuildVersion(); - console.log(`Build version: ${buildVersion}`); + logger.info(`Build version: ${buildVersion}`); // Show splash screen createSplashWindow(); @@ -450,7 +513,7 @@ app.whenReady().then(async () => { try { // Initialize encrypted database await initDatabase(); - console.log('Database initialized'); + logger.info('Database initialized'); // ========================================================================= // ENTERPRISE LICENSE ENFORCEMENT @@ -474,7 +537,12 @@ app.whenReady().then(async () => { // Setup IPC handlers for renderer process communication setupIPCHandlers(); - console.log('IPC handlers registered'); + logger.info('IPC handlers registered'); + + // Start auto-updater for enterprise builds + if (buildVersion === BUILD_VERSION.ENTERPRISE && app.isPackaged) { + initAutoUpdater(); + } // Create application menu createMenu(); @@ -494,7 +562,7 @@ app.whenReady().then(async () => { console.log(` - Disabled features: ${EVALUATION_RESTRICTIONS.disabledFeatures.length}`); } } catch (error) { - console.error('Failed to initialize application:', error); + logger.fatal('Failed to initialize application', { error: error.message, stack: error.stack }); dialog.showErrorBox('Startup Error', `Failed to initialize TransTrack: ${error.message}`); app.quit(); } @@ -513,10 +581,10 @@ app.on('window-all-closed', () => { }); app.on('before-quit', async () => { - console.log('Stopping periodic license checks...'); + logger.info('Application shutting down...'); stopPeriodicLicenseCheck(); - console.log('Closing database connection...'); await closeDatabase(); + closeLogger(); }); // Security: Handle certificate errors diff --git a/electron/services/logger.cjs b/electron/services/logger.cjs new file mode 100644 index 0000000..ebdc0ac --- /dev/null +++ b/electron/services/logger.cjs @@ -0,0 +1,134 @@ +/** + * TransTrack - Structured Logger & Crash Reporter + * + * Provides JSON-structured log output that persists to a rotating log file + * in userData. In production Electron builds, console output is invisible; + * this logger writes to disk so crashes and errors can be diagnosed. + * + * Also registers Electron's crashReporter for native crash minidumps. + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { app, crashReporter } = require('electron'); + +const MAX_LOG_SIZE_BYTES = 10 * 1024 * 1024; // 10 MB per file +const MAX_LOG_FILES = 5; + +let logStream = null; +let logDir = null; + +function getLogDir() { + if (logDir) return logDir; + logDir = path.join(app.getPath('userData'), 'logs'); + if (!fs.existsSync(logDir)) { + fs.mkdirSync(logDir, { recursive: true }); + } + return logDir; +} + +function getLogFilePath() { + return path.join(getLogDir(), 'transtrack.log'); +} + +function rotateIfNeeded() { + const logPath = getLogFilePath(); + try { + if (!fs.existsSync(logPath)) return; + const stats = fs.statSync(logPath); + if (stats.size < MAX_LOG_SIZE_BYTES) return; + + // Rotate: shift existing logs + for (let i = MAX_LOG_FILES - 1; i >= 1; i--) { + const older = `${logPath}.${i}`; + const newer = i === 1 ? logPath : `${logPath}.${i - 1}`; + if (fs.existsSync(newer)) { + fs.renameSync(newer, older); + } + } + } catch { + // Non-fatal + } +} + +function ensureStream() { + if (logStream) return logStream; + rotateIfNeeded(); + logStream = fs.createWriteStream(getLogFilePath(), { flags: 'a' }); + return logStream; +} + +function formatEntry(level, message, meta = {}) { + return JSON.stringify({ + t: new Date().toISOString(), + level, + msg: message, + pid: process.pid, + ...meta, + }) + '\n'; +} + +function write(level, message, meta) { + const entry = formatEntry(level, message, meta); + try { + ensureStream().write(entry); + } catch { + // Last resort — stdout + process.stdout.write(entry); + } + // Mirror to console in dev + if (!app.isPackaged) { + const consoleFn = level === 'error' ? console.error : level === 'warn' ? console.warn : console.log; + consoleFn(`[${level.toUpperCase()}] ${message}`, Object.keys(meta).length ? meta : ''); + } +} + +const logger = { + info: (msg, meta) => write('info', msg, meta), + warn: (msg, meta) => write('warn', msg, meta), + error: (msg, meta) => write('error', msg, meta), + fatal: (msg, meta) => write('fatal', msg, meta), +}; + +function initCrashReporter() { + crashReporter.start({ + productName: 'TransTrack', + companyName: 'TransTrack Medical Software', + submitURL: '', // No remote submission — minidumps stored locally + uploadToServer: false, + compress: true, + }); + + // Capture unhandled exceptions and rejections + process.on('uncaughtException', (err) => { + logger.fatal('Uncaught exception', { error: err.message, stack: err.stack }); + // Attempt to flush before crashing + try { logStream?.end(); } catch { /* best effort */ } + }); + + process.on('unhandledRejection', (reason) => { + const msg = reason instanceof Error ? reason.message : String(reason); + const stack = reason instanceof Error ? reason.stack : undefined; + logger.error('Unhandled promise rejection', { error: msg, stack }); + }); + + logger.info('Crash reporter initialized', { + crashDumpsDir: app.getPath('crashDumps'), + }); +} + +function closeLogger() { + if (logStream) { + logStream.end(); + logStream = null; + } +} + +module.exports = { + logger, + initCrashReporter, + closeLogger, + getLogDir, +}; diff --git a/package.json b/package.json index 7653568..a1c2cc8 100644 --- a/package.json +++ b/package.json @@ -81,91 +81,94 @@ "postinstall": "electron-builder install-app-deps" }, "dependencies": { - "@hello-pangea/dnd": "^17.0.0", - "@hookform/resolvers": "^4.1.2", - "@radix-ui/react-accordion": "^1.2.3", - "@radix-ui/react-alert-dialog": "^1.1.6", - "@radix-ui/react-aspect-ratio": "^1.1.2", - "@radix-ui/react-avatar": "^1.1.3", - "@radix-ui/react-checkbox": "^1.1.4", - "@radix-ui/react-collapsible": "^1.1.3", - "@radix-ui/react-context-menu": "^2.2.6", - "@radix-ui/react-dialog": "^1.1.6", - "@radix-ui/react-dropdown-menu": "^2.1.6", - "@radix-ui/react-hover-card": "^1.1.6", - "@radix-ui/react-label": "^2.1.2", - "@radix-ui/react-menubar": "^1.1.6", - "@radix-ui/react-navigation-menu": "^1.2.5", - "@radix-ui/react-popover": "^1.1.6", - "@radix-ui/react-progress": "^1.1.2", - "@radix-ui/react-radio-group": "^1.2.3", - "@radix-ui/react-scroll-area": "^1.2.3", - "@radix-ui/react-select": "^2.1.6", - "@radix-ui/react-separator": "^1.1.2", - "@radix-ui/react-slider": "^1.2.3", - "@radix-ui/react-slot": "^1.1.2", - "@radix-ui/react-switch": "^1.1.3", - "@radix-ui/react-tabs": "^1.1.3", - "@radix-ui/react-toast": "^1.2.2", - "@radix-ui/react-toggle": "^1.1.2", - "@radix-ui/react-toggle-group": "^1.1.2", - "@radix-ui/react-tooltip": "^1.1.8", - "@tanstack/react-query": "^5.84.1", - "bcryptjs": "^2.4.3", - "better-sqlite3-multiple-ciphers": "^12.6.2", - "canvas-confetti": "^1.9.4", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "cmdk": "^1.0.0", - "date-fns": "^3.6.0", - "embla-carousel-react": "^8.5.2", - "framer-motion": "^11.16.4", - "html2canvas": "^1.4.1", - "input-otp": "^1.4.2", - "jspdf": "^4.2.1", - "lodash": "^4.17.21", - "lucide-react": "^0.577.0", - "next-themes": "^0.4.4", - "react": "^18.2.0", - "react-day-picker": "^8.10.1", - "react-dom": "^18.2.0", - "react-hook-form": "^7.54.2", - "react-hot-toast": "^2.6.0", - "react-leaflet": "^4.2.1", - "react-markdown": "^9.0.1", - "react-resizable-panels": "^2.1.7", - "react-router-dom": "^6.26.0", - "recharts": "^2.15.4", - "sonner": "^2.0.1", - "tailwind-merge": "^3.0.2", - "tailwindcss-animate": "^1.0.7", - "three": "^0.183.1", - "uuid": "^9.0.0", - "vaul": "^1.1.2", - "zod": "^3.24.2" + "@hello-pangea/dnd": "17.0.0", + "@hookform/resolvers": "4.1.2", + "@radix-ui/react-accordion": "1.2.3", + "@radix-ui/react-alert-dialog": "1.1.6", + "@radix-ui/react-aspect-ratio": "1.1.2", + "@radix-ui/react-avatar": "1.1.3", + "@radix-ui/react-checkbox": "1.1.4", + "@radix-ui/react-collapsible": "1.1.3", + "@radix-ui/react-context-menu": "2.2.6", + "@radix-ui/react-dialog": "1.1.6", + "@radix-ui/react-dropdown-menu": "2.1.6", + "@radix-ui/react-hover-card": "1.1.6", + "@radix-ui/react-label": "2.1.2", + "@radix-ui/react-menubar": "1.1.6", + "@radix-ui/react-navigation-menu": "1.2.5", + "@radix-ui/react-popover": "1.1.6", + "@radix-ui/react-progress": "1.1.2", + "@radix-ui/react-radio-group": "1.2.3", + "@radix-ui/react-scroll-area": "1.2.3", + "@radix-ui/react-select": "2.1.6", + "@radix-ui/react-separator": "1.1.2", + "@radix-ui/react-slider": "1.2.3", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-switch": "1.1.3", + "@radix-ui/react-tabs": "1.1.3", + "@radix-ui/react-toast": "1.2.2", + "@radix-ui/react-toggle": "1.1.2", + "@radix-ui/react-toggle-group": "1.1.2", + "@radix-ui/react-tooltip": "1.1.8", + "@tanstack/react-query": "5.84.1", + "bcryptjs": "2.4.3", + "better-sqlite3-multiple-ciphers": "12.6.2", + "canvas-confetti": "1.9.4", + "class-variance-authority": "0.7.1", + "clsx": "2.1.1", + "cmdk": "1.0.0", + "date-fns": "3.6.0", + "electron-updater": "6.3.9", + "embla-carousel-react": "8.5.2", + "framer-motion": "11.16.4", + "html2canvas": "1.4.1", + "input-otp": "1.4.2", + "jspdf": "4.2.1", + "lodash": "4.17.21", + "lucide-react": "0.577.0", + "next-themes": "0.4.4", + "react": "18.2.0", + "react-day-picker": "8.10.1", + "react-dom": "18.2.0", + "react-hook-form": "7.54.2", + "react-hot-toast": "2.6.0", + "react-leaflet": "4.2.1", + "react-markdown": "9.0.1", + "react-resizable-panels": "2.1.7", + "react-router-dom": "6.26.0", + "recharts": "2.15.4", + "sonner": "2.0.1", + "tailwind-merge": "3.0.2", + "tailwindcss-animate": "1.0.7", + "three": "0.183.1", + "uuid": "9.0.0", + "vaul": "1.1.2", + "zod": "3.24.2" }, "devDependencies": { - "@eslint/js": "^9.19.0", - "@types/node": "^25.2.3", - "@types/react": "^18.2.66", - "@types/react-dom": "^18.2.22", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "baseline-browser-mapping": "^2.8.32", - "concurrently": "^8.2.2", - "electron": "^35.7.5", - "electron-builder": "^26.6.0", - "eslint": "^9.19.0", - "eslint-plugin-react": "^7.37.4", - "eslint-plugin-react-hooks": "^5.0.0", - "eslint-plugin-react-refresh": "^0.5.0", - "eslint-plugin-unused-imports": "^4.3.0", - "globals": "^17.4.0", - "postcss": "^8.5.3", - "tailwindcss": "^3.4.17", - "typescript": "^5.8.2", - "vite": "^6.1.0", - "wait-on": "^9.0.4" + "@cyclonedx/cyclonedx-npm": "1.20.1", + "@electron/notarize": "2.5.0", + "@eslint/js": "9.19.0", + "@types/node": "25.2.3", + "@types/react": "18.2.66", + "@types/react-dom": "18.2.22", + "@vitejs/plugin-react": "4.3.4", + "autoprefixer": "10.4.20", + "baseline-browser-mapping": "2.8.32", + "concurrently": "8.2.2", + "electron": "35.7.5", + "electron-builder": "26.6.0", + "eslint": "9.19.0", + "eslint-plugin-react": "7.37.4", + "eslint-plugin-react-hooks": "5.0.0", + "eslint-plugin-react-refresh": "0.5.0", + "eslint-plugin-unused-imports": "4.3.0", + "globals": "17.4.0", + "postcss": "8.5.3", + "tailwindcss": "3.4.17", + "typescript": "5.8.2", + "vite": "6.1.0", + "wait-on": "9.0.4" }, "overrides": { "picomatch": "^4.0.4" diff --git a/scripts/notarize.cjs b/scripts/notarize.cjs new file mode 100644 index 0000000..ac41b40 --- /dev/null +++ b/scripts/notarize.cjs @@ -0,0 +1,42 @@ +/** + * macOS Notarization Script for electron-builder afterSign hook. + * + * Required environment variables: + * APPLE_ID – Apple Developer account email + * APPLE_APP_PASSWORD – App-specific password (not account password) + * APPLE_TEAM_ID – 10-character Team ID + * + * Skipped automatically on non-macOS platforms and when env vars are absent. + */ + +'use strict'; + +const { notarize } = require('@electron/notarize'); + +exports.default = async function notarizing(context) { + const { electronPlatformName, appOutDir } = context; + if (electronPlatformName !== 'darwin') return; + + const appleId = process.env.APPLE_ID; + const appleIdPassword = process.env.APPLE_APP_PASSWORD; + const teamId = process.env.APPLE_TEAM_ID; + + if (!appleId || !appleIdPassword || !teamId) { + console.warn('Skipping notarization: APPLE_ID, APPLE_APP_PASSWORD, or APPLE_TEAM_ID not set'); + return; + } + + const appName = context.packager.appInfo.productFilename; + + console.log(`Notarizing ${appName}...`); + + await notarize({ + appBundleId: context.packager.config.appId, + appPath: `${appOutDir}/${appName}.app`, + appleId, + appleIdPassword, + teamId, + }); + + console.log('Notarization complete.'); +}; diff --git a/src/api/localClient.js b/src/api/localClient.js index dcbf357..db66279 100644 --- a/src/api/localClient.js +++ b/src/api/localClient.js @@ -62,7 +62,7 @@ const mockClient = { { tier: 'professional', tierName: 'Professional', price: 7499, currency: 'USD' }, { tier: 'enterprise', tierName: 'Enterprise', price: 24999, currency: 'USD' }, ], - paypalEmail: 'lilnicole0383@gmail.com', + businessEmail: 'billing@transtrack.medical', contactEmail: 'Trans_Track@outlook.com', }), getPaymentInfo: async (tier) => ({ diff --git a/src/components/license/UpgradePrompt.jsx b/src/components/license/UpgradePrompt.jsx index 961789a..33a04f0 100644 --- a/src/components/license/UpgradePrompt.jsx +++ b/src/components/license/UpgradePrompt.jsx @@ -92,7 +92,8 @@ export default function UpgradePrompt({ enterprise: '24999', }; // Open PayPal payment - window.open(`https://www.paypal.me/lilnicole0383/${amounts[tier]}USD`, '_blank'); + const tierSlug = tier.toLowerCase(); + window.open(`https://buy.stripe.com/transtrack-${tierSlug}`, '_blank'); }; return ( diff --git a/src/pages/LicenseActivation.jsx b/src/pages/LicenseActivation.jsx index 3f7a48a..625f6c0 100644 --- a/src/pages/LicenseActivation.jsx +++ b/src/pages/LicenseActivation.jsx @@ -164,7 +164,7 @@ export default function LicenseActivation({ onActivated }) { const handlePayPal = (tier) => { const amount = TIER_CONFIG[tier].price; - window.open(`https://www.paypal.me/lilnicole0383/${amount}USD`, '_blank'); + window.open(`https://buy.stripe.com/transtrack-${tier.toLowerCase()}`, '_blank'); }; const handleContactSales = () => { From 15581ff0e9626c6d465085d6dc8510cd04833ca3 Mon Sep 17 00:00:00 2001 From: NeuroKoder3 Date: Thu, 26 Mar 2026 23:48:47 -0500 Subject: [PATCH 2/4] fix: pin dependency versions to actual installed versions and regenerate lockfile --- package-lock.json | 803 ++++++++++++++++++++++++++++++++++++++-------- package.json | 124 +++---- 2 files changed, 731 insertions(+), 196 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1fa1dbf..7bbb08e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,91 +10,94 @@ "hasInstallScript": true, "license": "Proprietary", "dependencies": { - "@hello-pangea/dnd": "^17.0.0", - "@hookform/resolvers": "^4.1.2", - "@radix-ui/react-accordion": "^1.2.3", - "@radix-ui/react-alert-dialog": "^1.1.6", - "@radix-ui/react-aspect-ratio": "^1.1.2", - "@radix-ui/react-avatar": "^1.1.3", - "@radix-ui/react-checkbox": "^1.1.4", - "@radix-ui/react-collapsible": "^1.1.3", - "@radix-ui/react-context-menu": "^2.2.6", - "@radix-ui/react-dialog": "^1.1.6", - "@radix-ui/react-dropdown-menu": "^2.1.6", - "@radix-ui/react-hover-card": "^1.1.6", - "@radix-ui/react-label": "^2.1.2", - "@radix-ui/react-menubar": "^1.1.6", - "@radix-ui/react-navigation-menu": "^1.2.5", - "@radix-ui/react-popover": "^1.1.6", - "@radix-ui/react-progress": "^1.1.2", - "@radix-ui/react-radio-group": "^1.2.3", - "@radix-ui/react-scroll-area": "^1.2.3", - "@radix-ui/react-select": "^2.1.6", - "@radix-ui/react-separator": "^1.1.2", - "@radix-ui/react-slider": "^1.2.3", - "@radix-ui/react-slot": "^1.1.2", - "@radix-ui/react-switch": "^1.1.3", - "@radix-ui/react-tabs": "^1.1.3", - "@radix-ui/react-toast": "^1.2.2", - "@radix-ui/react-toggle": "^1.1.2", - "@radix-ui/react-toggle-group": "^1.1.2", - "@radix-ui/react-tooltip": "^1.1.8", - "@tanstack/react-query": "^5.84.1", - "bcryptjs": "^2.4.3", - "better-sqlite3-multiple-ciphers": "^12.6.2", - "canvas-confetti": "^1.9.4", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "cmdk": "^1.0.0", - "date-fns": "^3.6.0", - "embla-carousel-react": "^8.5.2", - "framer-motion": "^11.16.4", - "html2canvas": "^1.4.1", - "input-otp": "^1.4.2", - "jspdf": "^4.2.1", - "lodash": "^4.17.21", - "lucide-react": "^0.577.0", - "next-themes": "^0.4.4", - "react": "^18.2.0", - "react-day-picker": "^8.10.1", - "react-dom": "^18.2.0", - "react-hook-form": "^7.54.2", - "react-hot-toast": "^2.6.0", - "react-leaflet": "^4.2.1", - "react-markdown": "^9.0.1", - "react-resizable-panels": "^2.1.7", - "react-router-dom": "^6.26.0", - "recharts": "^2.15.4", - "sonner": "^2.0.1", - "tailwind-merge": "^3.0.2", - "tailwindcss-animate": "^1.0.7", - "three": "^0.183.1", - "uuid": "^9.0.0", - "vaul": "^1.1.2", - "zod": "^3.24.2" + "@hello-pangea/dnd": "17.0.0", + "@hookform/resolvers": "4.1.3", + "@radix-ui/react-accordion": "1.2.12", + "@radix-ui/react-alert-dialog": "1.1.15", + "@radix-ui/react-aspect-ratio": "1.1.8", + "@radix-ui/react-avatar": "1.1.11", + "@radix-ui/react-checkbox": "1.3.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-context-menu": "2.2.16", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-dropdown-menu": "2.1.16", + "@radix-ui/react-hover-card": "1.1.15", + "@radix-ui/react-label": "2.1.8", + "@radix-ui/react-menubar": "1.1.16", + "@radix-ui/react-navigation-menu": "1.2.14", + "@radix-ui/react-popover": "1.1.15", + "@radix-ui/react-progress": "1.1.8", + "@radix-ui/react-radio-group": "1.3.8", + "@radix-ui/react-scroll-area": "1.2.10", + "@radix-ui/react-select": "2.2.6", + "@radix-ui/react-separator": "1.1.8", + "@radix-ui/react-slider": "1.3.6", + "@radix-ui/react-slot": "1.2.4", + "@radix-ui/react-switch": "1.2.6", + "@radix-ui/react-tabs": "1.1.13", + "@radix-ui/react-toast": "1.2.15", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.11", + "@radix-ui/react-tooltip": "1.2.8", + "@tanstack/react-query": "5.95.0", + "bcryptjs": "2.4.3", + "better-sqlite3-multiple-ciphers": "12.6.2", + "canvas-confetti": "1.9.4", + "class-variance-authority": "0.7.1", + "clsx": "2.1.1", + "cmdk": "1.1.1", + "date-fns": "3.6.0", + "electron-updater": "6.8.3", + "embla-carousel-react": "8.6.0", + "framer-motion": "11.18.2", + "html2canvas": "1.4.1", + "input-otp": "1.4.2", + "jspdf": "4.2.1", + "lodash": "4.17.23", + "lucide-react": "0.577.0", + "next-themes": "0.4.6", + "react": "18.3.1", + "react-day-picker": "8.10.1", + "react-dom": "18.3.1", + "react-hook-form": "7.72.0", + "react-hot-toast": "2.6.0", + "react-leaflet": "4.2.1", + "react-markdown": "9.1.0", + "react-resizable-panels": "2.1.9", + "react-router-dom": "6.30.3", + "recharts": "2.15.4", + "sonner": "2.0.7", + "tailwind-merge": "3.4.0", + "tailwindcss-animate": "1.0.7", + "three": "0.183.2", + "uuid": "9.0.1", + "vaul": "1.1.2", + "zod": "3.25.76" }, "devDependencies": { - "@eslint/js": "^9.19.0", - "@types/node": "^25.2.3", - "@types/react": "^18.2.66", - "@types/react-dom": "^18.2.22", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "baseline-browser-mapping": "^2.8.32", - "concurrently": "^8.2.2", - "electron": "^35.7.5", - "electron-builder": "^26.6.0", - "eslint": "^9.19.0", - "eslint-plugin-react": "^7.37.4", - "eslint-plugin-react-hooks": "^5.0.0", - "eslint-plugin-react-refresh": "^0.5.0", - "eslint-plugin-unused-imports": "^4.3.0", - "globals": "^17.4.0", - "postcss": "^8.5.3", - "tailwindcss": "^3.4.17", - "typescript": "^5.8.2", - "vite": "^6.1.0", - "wait-on": "^9.0.4" + "@cyclonedx/cyclonedx-npm": "4.2.1", + "@electron/notarize": "3.1.1", + "@eslint/js": "9.39.2", + "@types/node": "25.5.0", + "@types/react": "18.3.27", + "@types/react-dom": "18.3.7", + "@vitejs/plugin-react": "4.7.0", + "autoprefixer": "10.4.27", + "baseline-browser-mapping": "2.10.10", + "concurrently": "8.2.2", + "electron": "35.7.5", + "electron-builder": "26.6.0", + "eslint": "9.39.2", + "eslint-plugin-react": "7.37.5", + "eslint-plugin-react-hooks": "5.2.0", + "eslint-plugin-react-refresh": "0.5.0", + "eslint-plugin-unused-imports": "4.3.0", + "globals": "17.4.0", + "postcss": "8.5.8", + "tailwindcss": "3.4.19", + "typescript": "5.9.3", + "vite": "6.4.1", + "wait-on": "9.0.4" } }, "node_modules/@alloc/quick-lru": { @@ -401,6 +404,106 @@ "node": ">=6.9.0" } }, + "node_modules/@cyclonedx/cyclonedx-npm": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@cyclonedx/cyclonedx-npm/-/cyclonedx-npm-4.2.1.tgz", + "integrity": "sha512-SOA/96sf0wsgUYCRtFkLFm6WoFhG+q1BxdC84hPSn9J3xWlH1e7OnTPJT+WNUzTqzX1nSm5JhjRX4krozu2X+g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://owasp.org/donate/?reponame=www-project-cyclonedx&title=OWASP+CycloneDX" + } + ], + "license": "Apache-2.0", + "dependencies": { + "@cyclonedx/cyclonedx-library": "^10.0.0", + "commander": "^14.0.0", + "normalize-package-data": "^7.0.0 || ^8.0.0", + "packageurl-js": "^2.0.1", + "spdx-expression-parse": "^3.0.1 || ^4.0.0", + "xmlbuilder2": "^3.0.2 || ^4.0.3" + }, + "bin": { + "cyclonedx-npm": "bin/cyclonedx-npm-cli.js" + }, + "engines": { + "node": ">=20.18.0", + "npm": ">=9" + }, + "optionalDependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "ajv-formats-draft2019": "^1.6.1", + "libxmljs2": "^0.35||^0.37" + } + }, + "node_modules/@cyclonedx/cyclonedx-npm/node_modules/@cyclonedx/cyclonedx-library": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@cyclonedx/cyclonedx-library/-/cyclonedx-library-10.0.0.tgz", + "integrity": "sha512-xDXf2eqzeFHdjamj6oBV3duRSfrlmsJ5+2z9tXp7q5qxJP5Awmjf4ABSutS4qkVHHj7JzKFL/EM0V0Nihc7zPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://owasp.org/donate/?reponame=www-project-cyclonedx&title=OWASP+CycloneDX" + } + ], + "license": "Apache-2.0", + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "ajv-formats-draft2019": "^1.6.1", + "libxmljs2": "^0.35||^0.37", + "packageurl-js": "*", + "spdx-expression-parse": "*", + "xmlbuilder2": "^3.0.2||^4.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + }, + "ajv-formats": { + "optional": true + }, + "ajv-formats-draft2019": { + "optional": true + }, + "libxmljs2": { + "optional": true + }, + "packageurl-js": { + "optional": true + }, + "spdx-expression-parse": { + "optional": true + }, + "xmlbuilder2": { + "optional": true + } + } + }, + "node_modules/@cyclonedx/cyclonedx-npm/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@cyclonedx/cyclonedx-npm/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -527,57 +630,17 @@ } }, "node_modules/@electron/notarize": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", - "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-3.1.1.tgz", + "integrity": "sha512-uQQSlOiJnqRkTL1wlEBAxe90nVN/Fc/hEmk0bqpKk8nKjV1if/tXLHKUPePtv9Xsx90PtZU8aidx5lAiOpjkQQ==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.1.1", - "fs-extra": "^9.0.1", + "debug": "^4.4.0", "promise-retry": "^2.0.1" }, "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@electron/notarize/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/notarize/node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/notarize/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" + "node": ">= 22.12.0" } }, "node_modules/@electron/osx-sign": { @@ -1977,6 +2040,58 @@ "node": ">=10" } }, + "node_modules/@oozcitak/dom": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz", + "integrity": "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oozcitak/infra": "^2.0.2", + "@oozcitak/url": "^3.0.0", + "@oozcitak/util": "^10.0.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@oozcitak/infra": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-2.0.2.tgz", + "integrity": "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oozcitak/util": "^10.0.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@oozcitak/url": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-3.0.0.tgz", + "integrity": "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oozcitak/infra": "^2.0.2", + "@oozcitak/util": "^10.0.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@oozcitak/util": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-10.0.0.tgz", + "integrity": "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -4654,6 +4769,60 @@ "semver": "bin/semver.js" } }, + "node_modules/app-builder-lib/node_modules/@electron/notarize": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", + "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/notarize/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/notarize/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/app-builder-lib/node_modules/ci-info": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", @@ -4767,7 +4936,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/aria-hidden": { @@ -5299,7 +5467,6 @@ "version": "9.5.1", "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz", "integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==", - "dev": true, "license": "MIT", "dependencies": { "debug": "^4.3.4", @@ -6464,6 +6631,14 @@ "node": "*" } }, + "node_modules/discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -6811,6 +6986,69 @@ "dev": true, "license": "ISC" }, + "node_modules/electron-updater": { + "version": "6.8.3", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.3.tgz", + "integrity": "sha512-Z6sgw3jgbikWKXei1ENdqFOxBP0WlXg3TtKfz0rgw2vIZFJUyI4pD7ZN7jrkm7EoMK+tcm/qTnPUdqfZukBlBQ==", + "license": "MIT", + "dependencies": { + "builder-util-runtime": "9.5.1", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "~7.7.3", + "tiny-typed-emitter": "^2.1.0" + } + }, + "node_modules/electron-updater/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-updater/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-updater/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-updater/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/electron-winstaller": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", @@ -7573,6 +7811,24 @@ "pako": "^2.1.0" } }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -8200,7 +8456,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/has-bigints": { @@ -9216,7 +9471,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -9337,7 +9591,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", - "dev": true, "license": "MIT" }, "node_modules/leaflet": { @@ -9401,6 +9654,19 @@ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -10422,6 +10688,14 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "license": "MIT" }, + "node_modules/moo": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.3.tgz", + "integrity": "sha512-m2fmM2dDm7GZQsY7KK2cme8agi+AAljILjQnof7p1ZMDe6dQ4bdnSMx0cPppudoeNv5hEFQirN6u+O4fDE0IWA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, "node_modules/motion-dom": { "version": "11.18.1", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", @@ -10454,6 +10728,14 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", + "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -10485,6 +10767,38 @@ "dev": true, "license": "MIT" }, + "node_modules/nearley": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", + "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + }, + "bin": { + "nearley-railroad": "bin/nearley-railroad.js", + "nearley-test": "bin/nearley-test.js", + "nearley-unparse": "bin/nearley-unparse.js", + "nearleyc": "bin/nearleyc.js" + }, + "funding": { + "type": "individual", + "url": "https://nearley.js.org/#give-to-nearley" + } + }, + "node_modules/nearley/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -10647,6 +10961,57 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/normalize-package-data": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz", + "integrity": "sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^9.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", + "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -10932,6 +11297,14 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/packageurl-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/packageurl-js/-/packageurl-js-2.0.1.tgz", + "integrity": "sha512-N5ixXjzTy4QDQH0Q9YFjqIWd6zH6936Djpl2m9QNFmDv5Fum8q8BjkpAcHNMzOFE0IwQrFhJWex3AN6kS0OSwg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/pako": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", @@ -11510,6 +11883,29 @@ "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==", "license": "MIT" }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", + "dev": true, + "license": "CC0-1.0", + "optional": true + }, + "node_modules/randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -12024,6 +12420,17 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resedit": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz", @@ -12104,6 +12511,17 @@ "node": ">=8" } }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.12" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -12341,7 +12759,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", - "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" @@ -12356,6 +12773,17 @@ "loose-envify": "^1.1.0" } }, + "node_modules/schemes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/schemes/-/schemes-1.4.0.tgz", + "integrity": "sha512-ImFy9FbCsQlVgnE3TCWmLPCFnVzx0lHL/l+umHplDqAKd0dzFpnS6lFZIpagBlYhKwzVmlV36ec0Y1XTu8JBAQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "extend": "^3.0.0" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -12657,6 +13085,20 @@ "npm": ">= 3.0.0" } }, + "node_modules/smtp-address-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/smtp-address-parser/-/smtp-address-parser-1.1.0.tgz", + "integrity": "sha512-Gz11jbNU0plrReU9Sj7fmshSBxxJ9ShdD2q4ktHIHo/rpTH6lFyQoYHYKINPJtPe8aHFnsbtW46Ls0tCCBsIZg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "nearley": "^2.20.1" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/socks": { "version": "2.8.7", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", @@ -12743,6 +13185,54 @@ "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", "dev": true }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", @@ -13353,6 +13843,12 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==", + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -13887,6 +14383,28 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/vaul": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", @@ -14258,6 +14776,23 @@ "node": ">=8.0" } }, + "node_modules/xmlbuilder2": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-4.0.3.tgz", + "integrity": "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@oozcitak/dom": "^2.0.2", + "@oozcitak/infra": "^2.0.2", + "@oozcitak/util": "^10.0.0", + "js-yaml": "^4.1.1" + }, + "engines": { + "node": ">=20.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index a1c2cc8..a077f88 100644 --- a/package.json +++ b/package.json @@ -82,92 +82,92 @@ }, "dependencies": { "@hello-pangea/dnd": "17.0.0", - "@hookform/resolvers": "4.1.2", - "@radix-ui/react-accordion": "1.2.3", - "@radix-ui/react-alert-dialog": "1.1.6", - "@radix-ui/react-aspect-ratio": "1.1.2", - "@radix-ui/react-avatar": "1.1.3", - "@radix-ui/react-checkbox": "1.1.4", - "@radix-ui/react-collapsible": "1.1.3", - "@radix-ui/react-context-menu": "2.2.6", - "@radix-ui/react-dialog": "1.1.6", - "@radix-ui/react-dropdown-menu": "2.1.6", - "@radix-ui/react-hover-card": "1.1.6", - "@radix-ui/react-label": "2.1.2", - "@radix-ui/react-menubar": "1.1.6", - "@radix-ui/react-navigation-menu": "1.2.5", - "@radix-ui/react-popover": "1.1.6", - "@radix-ui/react-progress": "1.1.2", - "@radix-ui/react-radio-group": "1.2.3", - "@radix-ui/react-scroll-area": "1.2.3", - "@radix-ui/react-select": "2.1.6", - "@radix-ui/react-separator": "1.1.2", - "@radix-ui/react-slider": "1.2.3", - "@radix-ui/react-slot": "1.1.2", - "@radix-ui/react-switch": "1.1.3", - "@radix-ui/react-tabs": "1.1.3", - "@radix-ui/react-toast": "1.2.2", - "@radix-ui/react-toggle": "1.1.2", - "@radix-ui/react-toggle-group": "1.1.2", - "@radix-ui/react-tooltip": "1.1.8", - "@tanstack/react-query": "5.84.1", + "@hookform/resolvers": "4.1.3", + "@radix-ui/react-accordion": "1.2.12", + "@radix-ui/react-alert-dialog": "1.1.15", + "@radix-ui/react-aspect-ratio": "1.1.8", + "@radix-ui/react-avatar": "1.1.11", + "@radix-ui/react-checkbox": "1.3.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-context-menu": "2.2.16", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-dropdown-menu": "2.1.16", + "@radix-ui/react-hover-card": "1.1.15", + "@radix-ui/react-label": "2.1.8", + "@radix-ui/react-menubar": "1.1.16", + "@radix-ui/react-navigation-menu": "1.2.14", + "@radix-ui/react-popover": "1.1.15", + "@radix-ui/react-progress": "1.1.8", + "@radix-ui/react-radio-group": "1.3.8", + "@radix-ui/react-scroll-area": "1.2.10", + "@radix-ui/react-select": "2.2.6", + "@radix-ui/react-separator": "1.1.8", + "@radix-ui/react-slider": "1.3.6", + "@radix-ui/react-slot": "1.2.4", + "@radix-ui/react-switch": "1.2.6", + "@radix-ui/react-tabs": "1.1.13", + "@radix-ui/react-toast": "1.2.15", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.11", + "@radix-ui/react-tooltip": "1.2.8", + "@tanstack/react-query": "5.95.0", "bcryptjs": "2.4.3", "better-sqlite3-multiple-ciphers": "12.6.2", "canvas-confetti": "1.9.4", "class-variance-authority": "0.7.1", "clsx": "2.1.1", - "cmdk": "1.0.0", + "cmdk": "1.1.1", "date-fns": "3.6.0", - "electron-updater": "6.3.9", - "embla-carousel-react": "8.5.2", - "framer-motion": "11.16.4", + "electron-updater": "6.8.3", + "embla-carousel-react": "8.6.0", + "framer-motion": "11.18.2", "html2canvas": "1.4.1", "input-otp": "1.4.2", "jspdf": "4.2.1", - "lodash": "4.17.21", + "lodash": "4.17.23", "lucide-react": "0.577.0", - "next-themes": "0.4.4", - "react": "18.2.0", + "next-themes": "0.4.6", + "react": "18.3.1", "react-day-picker": "8.10.1", - "react-dom": "18.2.0", - "react-hook-form": "7.54.2", + "react-dom": "18.3.1", + "react-hook-form": "7.72.0", "react-hot-toast": "2.6.0", "react-leaflet": "4.2.1", - "react-markdown": "9.0.1", - "react-resizable-panels": "2.1.7", - "react-router-dom": "6.26.0", + "react-markdown": "9.1.0", + "react-resizable-panels": "2.1.9", + "react-router-dom": "6.30.3", "recharts": "2.15.4", - "sonner": "2.0.1", - "tailwind-merge": "3.0.2", + "sonner": "2.0.7", + "tailwind-merge": "3.4.0", "tailwindcss-animate": "1.0.7", - "three": "0.183.1", - "uuid": "9.0.0", + "three": "0.183.2", + "uuid": "9.0.1", "vaul": "1.1.2", - "zod": "3.24.2" + "zod": "3.25.76" }, "devDependencies": { - "@cyclonedx/cyclonedx-npm": "1.20.1", - "@electron/notarize": "2.5.0", - "@eslint/js": "9.19.0", - "@types/node": "25.2.3", - "@types/react": "18.2.66", - "@types/react-dom": "18.2.22", - "@vitejs/plugin-react": "4.3.4", - "autoprefixer": "10.4.20", - "baseline-browser-mapping": "2.8.32", + "@cyclonedx/cyclonedx-npm": "4.2.1", + "@electron/notarize": "3.1.1", + "@eslint/js": "9.39.2", + "@types/node": "25.5.0", + "@types/react": "18.3.27", + "@types/react-dom": "18.3.7", + "@vitejs/plugin-react": "4.7.0", + "autoprefixer": "10.4.27", + "baseline-browser-mapping": "2.10.10", "concurrently": "8.2.2", "electron": "35.7.5", "electron-builder": "26.6.0", - "eslint": "9.19.0", - "eslint-plugin-react": "7.37.4", - "eslint-plugin-react-hooks": "5.0.0", + "eslint": "9.39.2", + "eslint-plugin-react": "7.37.5", + "eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-refresh": "0.5.0", "eslint-plugin-unused-imports": "4.3.0", "globals": "17.4.0", - "postcss": "8.5.3", - "tailwindcss": "3.4.17", - "typescript": "5.8.2", - "vite": "6.1.0", + "postcss": "8.5.8", + "tailwindcss": "3.4.19", + "typescript": "5.9.3", + "vite": "6.4.1", "wait-on": "9.0.4" }, "overrides": { From a3eead9ed7533f837a059cbdf3a9a524c3b4802b Mon Sep 17 00:00:00 2001 From: NeuroKoder3 Date: Thu, 26 Mar 2026 23:50:58 -0500 Subject: [PATCH 3/4] fix: remove cyclonedx and notarize from devDeps (used via npx/build only), regenerate lockfile --- package-lock.json | 458 ---------------------------------------------- package.json | 2 - 2 files changed, 460 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7bbb08e..4fb6a13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,8 +75,6 @@ "zod": "3.25.76" }, "devDependencies": { - "@cyclonedx/cyclonedx-npm": "4.2.1", - "@electron/notarize": "3.1.1", "@eslint/js": "9.39.2", "@types/node": "25.5.0", "@types/react": "18.3.27", @@ -404,106 +402,6 @@ "node": ">=6.9.0" } }, - "node_modules/@cyclonedx/cyclonedx-npm": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@cyclonedx/cyclonedx-npm/-/cyclonedx-npm-4.2.1.tgz", - "integrity": "sha512-SOA/96sf0wsgUYCRtFkLFm6WoFhG+q1BxdC84hPSn9J3xWlH1e7OnTPJT+WNUzTqzX1nSm5JhjRX4krozu2X+g==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://owasp.org/donate/?reponame=www-project-cyclonedx&title=OWASP+CycloneDX" - } - ], - "license": "Apache-2.0", - "dependencies": { - "@cyclonedx/cyclonedx-library": "^10.0.0", - "commander": "^14.0.0", - "normalize-package-data": "^7.0.0 || ^8.0.0", - "packageurl-js": "^2.0.1", - "spdx-expression-parse": "^3.0.1 || ^4.0.0", - "xmlbuilder2": "^3.0.2 || ^4.0.3" - }, - "bin": { - "cyclonedx-npm": "bin/cyclonedx-npm-cli.js" - }, - "engines": { - "node": ">=20.18.0", - "npm": ">=9" - }, - "optionalDependencies": { - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "ajv-formats-draft2019": "^1.6.1", - "libxmljs2": "^0.35||^0.37" - } - }, - "node_modules/@cyclonedx/cyclonedx-npm/node_modules/@cyclonedx/cyclonedx-library": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@cyclonedx/cyclonedx-library/-/cyclonedx-library-10.0.0.tgz", - "integrity": "sha512-xDXf2eqzeFHdjamj6oBV3duRSfrlmsJ5+2z9tXp7q5qxJP5Awmjf4ABSutS4qkVHHj7JzKFL/EM0V0Nihc7zPg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://owasp.org/donate/?reponame=www-project-cyclonedx&title=OWASP+CycloneDX" - } - ], - "license": "Apache-2.0", - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "ajv-formats-draft2019": "^1.6.1", - "libxmljs2": "^0.35||^0.37", - "packageurl-js": "*", - "spdx-expression-parse": "*", - "xmlbuilder2": "^3.0.2||^4.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - }, - "ajv-formats": { - "optional": true - }, - "ajv-formats-draft2019": { - "optional": true - }, - "libxmljs2": { - "optional": true - }, - "packageurl-js": { - "optional": true - }, - "spdx-expression-parse": { - "optional": true - }, - "xmlbuilder2": { - "optional": true - } - } - }, - "node_modules/@cyclonedx/cyclonedx-npm/node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/@cyclonedx/cyclonedx-npm/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -629,20 +527,6 @@ "global-agent": "^3.0.0" } }, - "node_modules/@electron/notarize": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-3.1.1.tgz", - "integrity": "sha512-uQQSlOiJnqRkTL1wlEBAxe90nVN/Fc/hEmk0bqpKk8nKjV1if/tXLHKUPePtv9Xsx90PtZU8aidx5lAiOpjkQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": ">= 22.12.0" - } - }, "node_modules/@electron/osx-sign": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.3.tgz", @@ -2040,58 +1924,6 @@ "node": ">=10" } }, - "node_modules/@oozcitak/dom": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz", - "integrity": "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oozcitak/infra": "^2.0.2", - "@oozcitak/url": "^3.0.0", - "@oozcitak/util": "^10.0.0" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@oozcitak/infra": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-2.0.2.tgz", - "integrity": "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oozcitak/util": "^10.0.0" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@oozcitak/url": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-3.0.0.tgz", - "integrity": "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oozcitak/infra": "^2.0.2", - "@oozcitak/util": "^10.0.0" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@oozcitak/util": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-10.0.0.tgz", - "integrity": "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.0" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -6631,14 +6463,6 @@ "node": "*" } }, - "node_modules/discontinuous-range": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", - "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -7811,24 +7635,6 @@ "pako": "^2.1.0" } }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause", - "optional": true - }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -10688,14 +10494,6 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "license": "MIT" }, - "node_modules/moo": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.3.tgz", - "integrity": "sha512-m2fmM2dDm7GZQsY7KK2cme8agi+AAljILjQnof7p1ZMDe6dQ4bdnSMx0cPppudoeNv5hEFQirN6u+O4fDE0IWA==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true - }, "node_modules/motion-dom": { "version": "11.18.1", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", @@ -10728,14 +10526,6 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nan": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", - "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -10767,38 +10557,6 @@ "dev": true, "license": "MIT" }, - "node_modules/nearley": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", - "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "commander": "^2.19.0", - "moo": "^0.5.0", - "railroad-diagrams": "^1.0.0", - "randexp": "0.4.6" - }, - "bin": { - "nearley-railroad": "bin/nearley-railroad.js", - "nearley-test": "bin/nearley-test.js", - "nearley-unparse": "bin/nearley-unparse.js", - "nearleyc": "bin/nearleyc.js" - }, - "funding": { - "type": "individual", - "url": "https://nearley.js.org/#give-to-nearley" - } - }, - "node_modules/nearley/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -10961,57 +10719,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/normalize-package-data": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz", - "integrity": "sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^9.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/normalize-package-data/node_modules/hosted-git-info": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", - "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^11.1.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/normalize-package-data/node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -11297,14 +11004,6 @@ "dev": true, "license": "BlueOak-1.0.0" }, - "node_modules/packageurl-js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/packageurl-js/-/packageurl-js-2.0.1.tgz", - "integrity": "sha512-N5ixXjzTy4QDQH0Q9YFjqIWd6zH6936Djpl2m9QNFmDv5Fum8q8BjkpAcHNMzOFE0IwQrFhJWex3AN6kS0OSwg==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/pako": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", @@ -11883,29 +11582,6 @@ "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==", "license": "MIT" }, - "node_modules/railroad-diagrams": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", - "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", - "dev": true, - "license": "CC0-1.0", - "optional": true - }, - "node_modules/randexp": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", - "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "discontinuous-range": "1.0.0", - "ret": "~0.1.10" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -12420,17 +12096,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resedit": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz", @@ -12511,17 +12176,6 @@ "node": ">=8" } }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.12" - } - }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -12773,17 +12427,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/schemes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/schemes/-/schemes-1.4.0.tgz", - "integrity": "sha512-ImFy9FbCsQlVgnE3TCWmLPCFnVzx0lHL/l+umHplDqAKd0dzFpnS6lFZIpagBlYhKwzVmlV36ec0Y1XTu8JBAQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "extend": "^3.0.0" - } - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -13085,20 +12728,6 @@ "npm": ">= 3.0.0" } }, - "node_modules/smtp-address-parser": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/smtp-address-parser/-/smtp-address-parser-1.1.0.tgz", - "integrity": "sha512-Gz11jbNU0plrReU9Sj7fmshSBxxJ9ShdD2q4ktHIHo/rpTH6lFyQoYHYKINPJtPe8aHFnsbtW46Ls0tCCBsIZg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "nearley": "^2.20.1" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/socks": { "version": "2.8.7", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", @@ -13185,54 +12814,6 @@ "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", "dev": true }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-correct/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", - "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", - "dev": true, - "license": "CC0-1.0" - }, "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", @@ -14383,28 +13964,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, "node_modules/vaul": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", @@ -14776,23 +14335,6 @@ "node": ">=8.0" } }, - "node_modules/xmlbuilder2": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-4.0.3.tgz", - "integrity": "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@oozcitak/dom": "^2.0.2", - "@oozcitak/infra": "^2.0.2", - "@oozcitak/util": "^10.0.0", - "js-yaml": "^4.1.1" - }, - "engines": { - "node": ">=20.0" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index a077f88..573bf4b 100644 --- a/package.json +++ b/package.json @@ -146,8 +146,6 @@ "zod": "3.25.76" }, "devDependencies": { - "@cyclonedx/cyclonedx-npm": "4.2.1", - "@electron/notarize": "3.1.1", "@eslint/js": "9.39.2", "@types/node": "25.5.0", "@types/react": "18.3.27", From 7464ea91dabcabb4e59b7748142ef7d5c14db8e5 Mon Sep 17 00:00:00 2001 From: NeuroKoder3 Date: Fri, 27 Mar 2026 00:26:40 -0500 Subject: [PATCH 4/4] fix: unref rate limiter cleanup timer to prevent test process hanging --- electron/ipc/rateLimiter.cjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/electron/ipc/rateLimiter.cjs b/electron/ipc/rateLimiter.cjs index 253382d..de09360 100644 --- a/electron/ipc/rateLimiter.cjs +++ b/electron/ipc/rateLimiter.cjs @@ -71,8 +71,8 @@ function resetForUser(userId) { } } -// Periodic cleanup of stale entries -setInterval(() => { +// Periodic cleanup of stale entries (unref so it doesn't block process exit) +const cleanupTimer = setInterval(() => { const now = Date.now(); const windowStart = now - WINDOW_MS; @@ -85,6 +85,7 @@ setInterval(() => { } } }, CLEANUP_INTERVAL_MS); +if (cleanupTimer.unref) cleanupTimer.unref(); module.exports = { checkRateLimit,