English · 简体中文
Desktop app
Package manifest
desktop/package.json f3router-desktop@0.9.2 — Electron 38.8.6, better-sqlite3@12.10.0, electron-builder@25.1.8, esbuild@0.24.0. Entry build/main.mjs (type: module). AppId com.f3tools.f3router, publish github:f3tools/f3router (desktop/electron-builder.yml). asar + client-dist in extraResources; per-OS signing targets (mac dmg+zip arm64+x64 signed/notarized/stapled via refresh-mac-update-metadata.mjs, win nsis+zip x64, linux AppImage+deb+tar.xz+rpm x64 since #981 d8fae97).
Build pipeline
bundle:server → build:main / build:preload → stage:client → electron-builder
scripts/bundle-server.mjsesbuilddefine: { 'process.env.F3ROUTER_COMMIT_SHA', 'process.env.F3ROUTER_INSTALL_METHOD' }fromGITHUB_SHA(40-hex); mirrored into liveprocess.envinserver-host.tssoroutes/update.tsresolves.build/main.mjsbundlessrc/main.ts(--platform=node --format=esm --external:electron --external:./server.mjs),build/preloadforpreload.ts/preload-popover.ts.scripts/stage-client.mjscopiesclient/dist→build/client-distorResources/client-distin packaged app; dev override viaFREEAPI_REPO.
Runtime layout
| Path | Notes |
|---|---|
<userData>/freeapi.db |
SQLite DB (freeapi.db + WAL/-shm), same schema as Docker/Node |
<userData>/config.json |
Port (31415 default), lanAccess, theme/locale |
<userData>/logs/freeapi.log |
1 MB + freeapi.log.1 rotation (desktop/src/logger.ts) |
<userData>/backups |
Server dumps (services/backups.ts dataDir()) |
Resources/client-dist |
Packaged client; dev: client/dist via FREEAPI_REPO |
~/Library/Application Support/f3router (macOS), %APPDATA%/f3router (Windows), ~/.config/f3router (Linux).
Embedded server-host
desktop/src/server-host.ts is the only module allowed to import server/src/* (desktop/README.md). It bundles the server via bundle-server.mjs and re-exports the DB singleton (getDb, getUnifiedApiKey) to avoid a second copy in the main bundle.
Boot sequence mirrors server/src/index.ts step-for-step (#949); __tests__/server-host-boot.test.ts cross-checks the list so a new step added to index.ts fails a desktop test instead of silently never running (how startBackupScheduler was missed):
installLogRedaction → installProcessSafetyNet → initDb → ensureSessionToken → restoreProxySettings/flushProxyCache → startHealthChecker/checkAllKeys → startCatalogSync → startCooldownProbe → startCustomModelSync → startBackupScheduler → cleanupExpiredCooldowns → startWakeDetect → createApp → listenWithScan (port 31415, scan +50 on conflict, persist to config.json).
Deliberately NOT mirrored: restoreDbBackupIfNeeded/startDbBackupPump (FREEAPI_DB_BACKUP_* env-only, packaged app inherits no shell env).
listenWithScan binds 127.0.0.1 by default; lanAccess → 0.0.0.0 (relaunch required).
Main-process wiring (desktop/src/main.ts)
- Single-instance lock (
app.requestSingleInstanceLock); second launch focuses existing window. userDataoverride fromFREEAPI_REPOdev path.installFileLoggerordering — must run before anyconsole.logthe server will emit.- Theme/locale mirroring from system.
FREEAPI_SHOTcapture mode for screenshots.
Tray / popover / window
desktop/src/tray.ts— menu-bar icon,Open Logs Folder/Open Backups Folder(logger.ts:openLogsFolder/openBackupsFolderviashell.openPath),Open f3router, quit.desktop/src/popover.ts— popover window for quick access.desktop/src/window.ts— main BrowserWindow chrome.
Related
- Logging and updates —
freeapi.logrotation, update delivery, signing. - Install & deploy — desktop vs Docker vs local dev.
- Logs viewer — the polling API the desktop log tap feeds.