Documentation

Desktop App

Electron main process, foreground window sampling, the authentication handoff and the packaged build.

The desktop app is the only component that can see which window has focus.

Layout

text
desktop/
  electron/
    main.ts        process lifecycle, window, tray
    preload.ts     contextBridge surface exposed to the renderer
    tracker.ts     foreground window sampling
    ipc.ts         typed IPC channel definitions
  src/              React renderer (Vite)
  electron-builder.yml

How the active window is found

The main process samples the foreground window on an interval and compares it with the previous sample. A change closes the current activity block and opens a new one, which is why switching applications produces two timeline rows rather than one long row.

ts
const { appName } = foregroundWindow();
// appName changed -> flush previous block, start a new one
if (appName !== current?.appName) {
  await activity.flush(current);
  current = activity.start(appName);
}

What the desktop app never sends

Only the process name of the foreground window leaves the main process. Window titles, paths and contents are never read. Activity.title exists for the browser extension and the desktop app must not populate it.

Authentication

The renderer opens a browser window to the web client's sign-in route, which completes authentication and returns through a custom protocol handler. The main process receives the token and stores it for later API calls.

Building the installer

electron-builder produces a per-user installer, TimeLet.Setup.<version>.exe, published as a release asset that the download page links to directly.

ScriptPurpose
devRun the Electron main process and the Vite renderer together
buildCompile the renderer and the main process for production
distBuild the unpacked application
releaseBuild and publish the Windows installer

Environment

bash
# desktop/.env.development
VITE_API_URL=http://localhost:5000/api

# desktop/.env.production
VITE_API_URL=https://api.timelens.app/api