v1.4.0
Adds five new framework lib modules and tightens early-init behavior.
New libs
- analytics β GA4 Measurement Protocol with cross-platform
uuidv5identity.client_id = uuidv5(deviceId, projectId-namespace),user_id = uuidv5(firebaseUid, projectId-namespace). Same Firebase projectId in BEM/UJM/web-manager/EM produces identical outputs β unified events for one human across desktop + web + backend. Auto-firesapp_launch, wireslogin/logouttowebManager.onAuthChange. Secret inprocess.env.GOOGLE_ANALYTICS_SECRET(matches BEM); webpack DefinePlugin bakes it into packaged bundles at build time. - context β runtime info block at
manager.context.{geolocation, client, session, app}. Mirrors BEM'sassistant.request.{geolocation, client}shape. Async ipify fetch forgeolocation.ip(cached so offline boots have last-known); MAC-derivedsession.deviceIdwithcrypto.randomUUID()fallback persisted on first launch. - usage β
opens/hoursTotal/hoursThisSession. Crash-safe: hours only credit on clean exits (lastQuitAtwritten viabefore-quit). Sessions that crashed don't contribute. - remote-config β "Hot config" fetched from
<brand.url>/data/resources/main.jsonand polled at auto-updater's feed-check cadence (1h). Defaults seeded immediately soget()never returns undefined; never blocks boot. Persisted to storage so offline boots still have last-known values.on('update', fn)for re-running gates. - restart-manager β auxiliary helper app for relaunches via
restart-manager://URL scheme. Auto-registers ~15s after launch, auto-unregisters on clean quit. Auto-installs RM if missing: mac uses signed/notarized.zipβ unzip β open (no DMG mount, no prompts); windows uses NSIS one-click installer; linux opens the.debURL in the user's browser (no sudo). Bails whenbrand.id === 'restart-manager', in dev (unlessEM_RESTART_MANAGER_DEV=1), or whenenabled: false. URLs point atrestart-manager/download-server.
Early init (main.js boot steps 1b + 1c)
- userData path append β in dev (
!app.isPackaged) appends(Development)toapp.getPath('userData')so dev session data, logs, andelectron-storefiles don't collide with a production-installed copy on the same machine. Logged before/after. Mirrors legacy electron-manager. - Global user agent fallback β sets
app.userAgentFallbackto a branded template vianode-powertools.template:Mozilla/5.0 (...) AppleWebKit/537.36 (KHTML, like Gecko) {brand.name}/{app.version} Chrome/{chrome} Safari/537.36with per-platform shape (Macintosh / Windows NT / X11). Every BrowserWindow load + electron-updater fetch + node-fetch via the renderer now carries the branded UA.
Try/catch audit
Removed ~14 paranoid try { require('electron') } wraps across 12+ lib files (protocol.js, logger-lite.js, ipc.js, deep-link.js, app-state.js, context-menu.js, menu.js, startup.js, tray.js, window-manager.js, app-root.js, main.js, preload.js, auto-updater.js). require('electron') doesn't throw β it returns different shapes per context. Correct pattern is const { app } = require('electron'); if (app) {β¦}.
Cross-context helpers (utils/{mode,url}-helpers.js)
isDevelopment(),isProduction(),isTesting(),getVersion(),getEnvironment(),getWebsiteUrl(),getFunctionsUrl(),getApiUrl().attachTo(Manager)mixin exposes the same API across main/renderer/preload/build Manager constructors.
Tests + Docs
- 7 new test suites (
analytics,analytics-bridge,context,usage,remote-config,restart-manager,startup-paths-and-ua). Suite total: 580 passing. - New docs:
docs/analytics.md,docs/context.md,docs/usage.md,docs/remote-config.md,docs/restart-manager.md. README.md + CLAUDE.md updated.