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
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.ymlHow 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.
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.
| Script | Purpose |
|---|---|
| dev | Run the Electron main process and the Vite renderer together |
| build | Compile the renderer and the main process for production |
| dist | Build the unpacked application |
| release | Build and publish the Windows installer |
Environment
# desktop/.env.development
VITE_API_URL=http://localhost:5000/api
# desktop/.env.production
VITE_API_URL=https://api.timelens.app/api