### Start Development Server Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md Starts the esbuild bundler in watch mode, serving the application on http://127.0.0.1:8080. ```bash pnpm dev ``` -------------------------------- ### Clone and Install Ferdium Source: https://context7.com/ferdium/ferdium-app/llms.txt Steps to clone the Ferdium repository and install its dependencies using pnpm. ```bash git clone --recurse-submodules https://github.com/ferdium/ferdium-app.git cd ferdium-app pnpm install ``` -------------------------------- ### Start Development and Electron Together Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md Combines development server and Electron app launch. It waits for the development server to be ready before launching Electron. ```bash pnpm start:all-dev ``` -------------------------------- ### Install Fedora Dependencies Source: https://github.com/ferdium/ferdium-app/blob/develop/CONTRIBUTING.md Installs required development libraries for Fedora. ```bash dnf install libX11-devel libXext-devel libXScrnSaver-devel libxkbfile-devel rpm ``` -------------------------------- ### Install Debian/Ubuntu Dependencies Source: https://github.com/ferdium/ferdium-app/blob/develop/CONTRIBUTING.md Installs necessary system-level dependencies for Debian/Ubuntu, including rpm, ruby, gem, and fpm. ```bash apt-get update -y && apt-get install --no-install-recommends -y rpm ruby gem && gem install fpm --no-document ``` -------------------------------- ### Install Dependencies Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md Installs project dependencies using pnpm. Requires Node 22.18.0 and pnpm 10.14.0. ```bash pnpm install ``` -------------------------------- ### Start Ferdium in Development Mode Source: https://context7.com/ferdium/ferdium-app/llms.txt Commands to start the Ferdium application in development mode, including watching for changes and launching Electron. ```bash # Start the esbuild watcher AND the Electron app together pnpm start:all-dev # Or run them separately: pnpm dev # Watch & rebuild with esbuild pnpm start # Launch Electron from ./build # Start with local internal server (no remote API) pnpm start:local # Start against the live remote API pnpm start:live # Full debug mode (DEBUG=Ferdium:* logs emitted to console) pnpm debug ``` -------------------------------- ### Instantiate and Use Settings Store Source: https://context7.com/ferdium/ferdium-app/llms.txt Demonstrates how to instantiate a settings store for a specific type (e.g., 'app', 'proxy') with default values and perform operations like getting, setting, and accessing raw data. ```typescript import Settings from './src/electron/Settings'; // Instantiate a settings store for the "app" type // File written to: /config/settings.json const appSettings = new Settings('app', { theme: 'default', accentColor: '#7367f0', inactivityLock: 0, isLockingFeatureEnabled: false, automaticUpdates: true, beta: false, serviceRibbonWidth: 68, iconSize: 0, showServiceName: false, useHorizontalStyle: false, alwaysShowWorkspaces: false, }); // Read a single key const theme = appSettings.get('theme'); // 'default' // Read all settings as a plain JS object const all = appSettings.allSerialized; // { theme: 'default', accentColor: '#7367f0', ... } // Update one or more keys (merged with defaults + existing state, then written to disk) appSettings.set({ theme: 'dark', accentColor: '#ff6b6b' }); // Access the reactive MobX store directly (useful inside Electron main reactions) console.log(appSettings.all); // { theme: 'dark', accentColor: '#ff6b6b', ... } // Settings file path console.log(appSettings.settingsFile); // e.g. /home/user/.config/Ferdium/config/settings.json // Proxy settings (written to /config/proxy.json) const proxySettings = new Settings('proxy', {}); proxySettings.set({ 'service-abc123': { isEnabled: true, host: '10.0.0.1', port: 8080 }, }); ``` -------------------------------- ### startLocalServer Channel Source: https://context7.com/ferdium/ferdium-app/llms.txt Starts the bundled AdonisJS internal server and returns its address and a cryptographic token. ```APIDOC ## startLocalServer Channel ### Description Starts the bundled AdonisJS internal server on an available port, generates a cryptographic token, and sends the address back to the renderer. ### Method `ipcRenderer.send` (to start) `ipcRenderer.on` (to receive response) ### Endpoint `startLocalServer` (send) `localServerPort` (receive) ### Parameters None for sending `startLocalServer`. ### Response (on `localServerPort`) - **port** (number) - The port the local server is running on. - **token** (string) - A cryptographic token for authentication. ### Request Example ```javascript // Renderer triggers start import { ipcRenderer } from 'electron'; ipcRenderer.send('startLocalServer'); // Main process responds with port + token ipcRenderer.on('localServerPort', (_event, data) => { const { port, token } = data; console.log(`Local server running at http://localhost:${port}/token/${token}`); }); ``` ### Response Example ```json { "port": 45569, "token": "a3FzG...base64url..." } ``` ``` -------------------------------- ### Internal Server Setup Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md Contains the AdonisJS 5 backend setup, including controllers, models, migrations, and routes for offline functionality. ```typescript src/internal-server/ ``` -------------------------------- ### Debug Electron App Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md Launches the Electron app with DEBUG=Ferdium:* logging enabled, similar to 'start:all-dev'. ```bash pnpm debug ``` -------------------------------- ### Check Node.js and pnpm Versions Source: https://github.com/ferdium/ferdium-app/blob/develop/CONTRIBUTING.md Use this command to verify that your installed Node.js and pnpm versions meet the project's requirements as specified in package.json and recipes/package.json. ```bash jq --null-input '[inputs.engines] | add' < ./package.json < ./recipes/package.json { "node": "22.18.0", "pnpm": "10.14.0" } ``` -------------------------------- ### ServerApi - Recipe Management Source: https://context7.com/ferdium/ferdium-app/llms.txt Provides methods for interacting with recipes, including listing installed recipes, checking for updates, browsing available recipes, and downloading recipe packages. ```APIDOC ## `ServerApi` — Recipes Provides methods for interacting with recipes. ### Methods - **`getInstalledRecipes()`**: Lists all installed recipes. - Returns: `IRecipe[]` - An array of installed recipe objects. - **`getRecipeUpdates(installedVersions: { [recipeId: string]: string })`**: Checks for available updates for installed recipes. - Parameters: - `installedVersions` (object) - An object mapping recipe IDs to their currently installed versions. - Returns: `string[]` - An array of recipe IDs that have updates available. - **`getRecipePreviews()`**: Browses all available recipes. - Returns: `RecipePreviewModel[]` - An array of recipe preview objects. - **`getFeaturedRecipePreviews()`**: Browses featured or popular recipes. - Returns: `RecipePreviewModel[]` - An array of featured recipe preview objects. - **`searchRecipePreviews(query: string)`**: Searches for recipes based on a query. - Parameters: - `query` (string) - The search term. - Returns: `RecipePreviewModel[]` - An array of recipe preview objects matching the query. - **`getRecipePackage(recipeId: string)`**: Downloads and installs a recipe package. - Parameters: - `recipeId` (string) - The ID of the recipe to download and install. - Returns: `string` - The ID of the installed recipe. ``` -------------------------------- ### Build Ferdium on Unix Source: https://github.com/ferdium/ferdium-app/blob/develop/CONTRIBUTING.md Executes the build script for Unix-based systems to install dependencies and build Ferdium. Assets will be placed in the 'out' folder. ```bash ./scripts/build-unix.sh ``` -------------------------------- ### Build Ferdium on Windows Source: https://github.com/ferdium/ferdium-app/blob/develop/CONTRIBUTING.md Executes the build script for Windows using Powershell to install dependencies and build Ferdium. Assets will be placed in the 'out' folder. ```powershell .\scripts\build-windows.ps1 ``` -------------------------------- ### Start Local Server via IPC Source: https://context7.com/ferdium/ferdium-app/llms.txt Send the 'startLocalServer' IPC message from the renderer to initiate the internal AdonisJS server. The main process responds with the server's port and a security token. ```typescript // Renderer triggers start (from SettingsStore reaction when server === LOCAL_SERVER) import { ipcRenderer } from 'electron'; pcRenderer.send('startLocalServer'); // Main process responds with port + token pcRenderer.on('localServerPort', (_event, data) => { const { port, token } = data; // e.g. port=45569, token='a3FzG...base64url...' console.log(`Local server running at http://localhost:${port}/token/${token}`); // The renderer uses this URL as apiBase() for all subsequent API calls }); // The server auto-increments port from LOCAL_PORT (default 45569) // if the port is already in use (up to LOCAL_PORT + 10) ``` -------------------------------- ### Ferdium D-Bus Python Example Module Source: https://github.com/ferdium/ferdium-app/blob/develop/docs/DBUS.md This Python module demonstrates integration with Ferdium's D-Bus interface for status bars. It requires Python 3.11 and the 'dbus-next' PyPI package. Use 'ferdium_bar.py --help' and 'ferdium_bar.py unread --help' for usage instructions. ```python import asyncio from dbus_next import Message, MessageType, Signature from dbus_next.aio import MessageBus class FerdiumDBus: def __init__(self, bus_name: str = "org.ferdium.Ferdium"): self.bus_name = bus_name self.bus: MessageBus = None self.object_path: str = "/org/ferdium" self.interface_name: str = "org.ferdium.Ferdium" async def connect(self): self.bus = await MessageBus().connect(ConnectionType.SESSION) async def get_unread_count(self) -> int: if self.bus is None: await self.connect() message = Message( path=self.object_path, interface=self.interface_name, member="UnreadCount", signature=Signature("") ) reply = await self.bus.call(message) if reply.message_type == MessageType.ERROR: raise Exception(f"DBus Error: {reply.body[0].signature} - {reply.body[0].value}") return reply.body[0].value async def mute(self): if self.bus is None: await self.connect() message = Message( path=self.object_path, interface=self.interface_name, member="Mute", signature=Signature("") ) reply = await self.bus.call(message) if reply.message_type == MessageType.ERROR: raise Exception(f"DBus Error: {reply.body[0].signature} - {reply.body[0].value}") async def unmute(self): if self.bus is None: await self.connect() message = Message( path=self.object_path, interface=self.interface_name, member="Unmute", signature=Signature("") ) reply = await self.bus.call(message) if reply.message_type == MessageType.ERROR: raise Exception(f"DBus Error: {reply.body[0].signature} - {reply.body[0].value}") def main(): ferdium_dbus = FerdiumDBus() asyncio.run(ferdium_dbus.get_unread_count()) if __name__ == "__main__": main() ``` -------------------------------- ### Initialize and Open Publish Debug Info Modal Source: https://context7.com/ferdium/ferdium-app/llms.txt Initializes the Publish Debug Info feature and provides a way to programmatically open its modal. The modal displays system info, app version, installed services, logs, and options to copy or publish. ```typescript import initialize from './src/features/publishDebugInfo'; initialize(); // Open the debug info modal programmatically window['ferdium'].features.publishDebugInfo.showModal(); // The Component renders a dialog showing: // - Ferdium version, Electron version, OS info // - List of installed services and recipes // - Recent log output // User can copy to clipboard or publish to a Gist ``` -------------------------------- ### Extract Artifacts from Docker Image Source: https://github.com/ferdium/ferdium-app/blob/develop/CONTRIBUTING.md Mount a volume to copy built artifacts from the Docker image to your host machine. This example copies files from /ferdium to /ferdium-out. ```bash DATE=`date +"%Y-%b-%d-%H-%M"` mkdir -p ~/Downloads/$DATE docker run -e GIT_SHA=`git rev-parse --short HEAD` -v ~/Downloads/$DATE:/ferdium-out -it ferdium-package-`uname -m` sh # inside the container: mv /ferdium/Ferdium-*.AppImage /ferdium-out/Ferdium-$GIT_SHA.AppImage mv /ferdium/ferdium-*.tar.gz /ferdium-out/Ferdium-$GIT_SHA.tar.gz mv /ferdium/ferdium-*.x86_64.rpm /ferdium-out/Ferdium-x86_64-$GIT_SHA.rpm mv /ferdium/ferdium_*_amd64.deb /ferdium-out/Ferdium-amd64-$GIT_SHA.deb mv /ferdium/ferdium-*.freebsd /ferdium-out/Ferdium-$GIT_SHA.freebsd mv /ferdium/ferdium /ferdium-out/Ferdium-$GIT_SHA mv /ferdium/latest-linux.yml /ferdium-out/latest-linux-$GIT_SHA.yml ``` -------------------------------- ### List, Update, Browse, Search, and Download Recipes with ServerApi Source: https://context7.com/ferdium/ferdium-app/llms.txt Use ServerApi to interact with Ferdium recipes. This includes listing installed recipes, checking for updates, browsing available and featured recipes, searching for recipes, and downloading/installing recipe packages. Ensure ServerApi is imported and instantiated. ```typescript import ServerApi from './src/api/server/ServerApi'; const api = new ServerApi(); // --- List installed recipes (reads from userDataRecipesPath) --- const recipes = await api.getInstalledRecipes(); // recipes: IRecipe[] — e.g. [{ id: 'slack', name: 'Slack', version: '1.2.0', ... }] // --- Check for recipe updates --- const updates = await api.getRecipeUpdates({ slack: '1.1.0', whatsapp: '2.0.0', }); // updates: string[] of recipe IDs that have updates available // --- Browse all available recipes --- const previews = await api.getRecipePreviews(); // previews: RecipePreviewModel[] // --- Browse featured/popular recipes --- const featured = await api.getFeaturedRecipePreviews(); // --- Search recipes --- const results = await api.searchRecipePreviews('telegram'); // results: RecipePreviewModel[] matching the query // --- Download and install a recipe package --- const installedId = await api.getRecipePackage('telegram'); // Downloads telegram.tar.gz, extracts to userDataRecipesPath/telegram/ // Returns: 'telegram' ``` -------------------------------- ### Manage Settings via IPC (Renderer Process) Source: https://context7.com/ferdium/ferdium-app/llms.txt Interacts with the settings IPC bridge from the renderer process to get and update settings. Use `ipcRenderer.once` for initial fetches and `ipcRenderer.send` for updates. ```typescript // Renderer side (inside SettingsStore.setup()) import { ipcRenderer } from 'electron'; // Request current settings for a given type pcRenderer.send('getAppSettings', 'app'); // Response arrives on: pcRenderer.once('appSettings', (_event, resp) => { // resp = { type: 'app', data: { theme: 'dark', ... } } console.log(resp.data.theme); // 'dark' }); // Persist an update pcRenderer.send('updateAppSettings', { type: 'app', data: { theme: 'light', serviceRibbonWidth: 80 }, }); ``` -------------------------------- ### Handle Auto-Updates via IPC (Renderer Process) Source: https://context7.com/ferdium/ferdium-app/llms.txt Manages application auto-updates from the renderer process. Sends actions like 'check' and 'install', and listens for status updates including availability, download progress, and errors. ```typescript // Renderer-side usage (inside AppStore or UI components) import { ipcRenderer } from 'electron'; // Check for a new version pcRenderer.send('autoUpdate', { action: 'check' }); // Listen for update availability pcRenderer.on('autoUpdate', (_event, data) => { if (data.available) { console.log(`Update available: v${data.version}`); } if (data.downloaded) { console.log('Update downloaded — ready to install'); // Trigger install (closes all windows and relaunches) ipcRenderer.send('autoUpdate', { action: 'install' }); } if (data.error) { console.error('Update error:', data.error); } if (data.available === false) { console.log('App is up to date'); } }); // In main process — enable pre-release (beta) channel // Controlled via appSettings.get('beta') === true ``` -------------------------------- ### Production Build Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md Creates a production-ready build of the application using esbuild for bundling and electron-builder for packaging. ```bash pnpm build ``` -------------------------------- ### Initialize and Use Quick Switch Feature Source: https://context7.com/ferdium/ferdium-app/llms.txt Initializes the Quick Switch feature at startup. Programmatically opens the modal or observes its visibility state. ```typescript // Feature is initialised at startup and exposed on window.ferdium import initialize from './src/features/quickSwitch'; initialize(); // Programmatically open the Quick Switch modal window['ferdium'].features.quickSwitch.showModal(); // Equivalent to pressing Cmd/Ctrl+S (default shortcut) // Observe modal visibility import { state } from './src/features/quickSwitch/store'; console.log(state.isModalVisible); // false | true ``` -------------------------------- ### Main Process Entry Point Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md The main process handles app lifecycle, window management, IPC, deep linking, auto-updates, tray icon, and global shortcuts. ```typescript src/index.ts ``` -------------------------------- ### Build System Configuration Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md Configures the build process using esbuild for bundling and electron-builder for packaging the application for different operating systems. ```javascript esbuild.mjs ``` ```yaml electron-builder.yml ``` -------------------------------- ### Launch Electron App Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md Launches the Electron application. This command should be run after 'pnpm dev' or 'pnpm build'. ```bash pnpm start ``` -------------------------------- ### Initialize Settings IPC (Main Process) Source: https://context7.com/ferdium/ferdium-app/llms.txt Registers the settings IPC bridge in the main process. Ensure `mainWindow` is available and `Settings` instances are created before calling. ```typescript // Main process registration (called inside src/electron/index.ts) import initSettingsIpc from './ipc-api/settings'; import Settings from './Settings'; const appSettings = new Settings('app', DEFAULT_APP_SETTINGS); const proxySettings = new Settings('proxy', {}); const shortcutsSettings = new Settings('shortcuts', DEFAULT_SHORTCUTS); initSettingsIpc({ mainWindow, settings: { app: appSettings, proxy: proxySettings, shortcuts: shortcutsSettings }, }); ``` -------------------------------- ### SettingsStore - Reactive App Settings (Renderer) Source: https://context7.com/ferdium/ferdium-app/llms.txt MobX store that hydrates from IPC, exposes reactive getters, and feeds reactions that update the window state. ```APIDOC ## `SettingsStore` — Reactive App Settings (Renderer) MobX store that hydrates from IPC, exposes reactive getters, and feeds reactions that update the window state. ### Accessing Settings Settings can be accessed via the `settings` object within the main stores. ```javascript import stores from './src/stores'; const { settings } = stores; // Read current app settings const appSettings = settings.app; // Read proxy settings const proxies = settings.proxy; // Read custom keyboard shortcuts const shortcuts = settings.shortcuts; ``` ### Dispatching Settings Updates Settings updates are dispatched using actions. ```javascript import actions from './src/actions'; // Dispatch a settings update action for app settings actions.settings.update({ type: 'app', data: { isLockingFeatureEnabled: true, inactivityLock: 10, locked: false, }, }); // Remove a proxy setting actions.settings.remove({ type: 'proxy', key: 'service-id-123', }); ``` ### App Settings Structure (Example) ```json { "theme": "dark", "accentColor": "#7367f0", "serviceRibbonWidth": 68, "iconSize": 0, "isLockingFeatureEnabled": false, "locked": false, "inactivityLock": 0, // minutes; 0 = disabled "automaticUpdates": true, "beta": false, ... } ``` ### Proxy Settings Structure (Example) ```json { "service-id": { "isEnabled": true, "host": "10.0.0.1", "port": 8080 } } ``` ``` -------------------------------- ### AutoUpdate Channel Source: https://context7.com/ferdium/ferdium-app/llms.txt Wraps `electron-updater` to handle application updates, including checking for new versions, downloading them, and initiating installation. This channel is automatically disabled for Snap packages. ```APIDOC ## AutoUpdate Channel ### Description Wraps `electron-updater` to handle application updates, including checking for new versions, downloading them, and initiating installation. This channel is automatically disabled for Snap packages. ### Renderer-side Usage **To check for a new version:** ```javascript ipcRenderer.send('autoUpdate', { action: 'check' }); ``` **To listen for update events:** ```javascript ipcRenderer.on('autoUpdate', (_event, data) => { if (data.available) { console.log(`Update available: v${data.version}`); } if (data.downloaded) { console.log('Update downloaded — ready to install'); // Trigger install (closes all windows and relaunches) ipcRenderer.send('autoUpdate', { action: 'install' }); } if (data.error) { console.error('Update error:', data.error); } if (data.available === false) { console.log('App is up to date'); } }); ``` **Main process control:** * Enable pre-release (beta) channel via `appSettings.get('beta') === true`. ``` -------------------------------- ### Prepare Code for Commit Source: https://github.com/ferdium/ferdium-app/blob/develop/CLAUDE.md Runs a comprehensive pre-commit check including type checking, ESLint auto-fixing, and Biome/Prettier formatting. ```bash pnpm prepare-code ``` -------------------------------- ### Get macOS Do Not Disturb State via IPC Source: https://context7.com/ferdium/ferdium-app/llms.txt Invoke the 'get-dnd' IPC channel to retrieve the Do Not Disturb status on macOS. Returns `false` on non-Mac platforms or in development mode. ```typescript // Renderer-side usage import { ipcRenderer } from 'electron'; const isDND: boolean = await ipcRenderer.invoke('get-dnd'); // true → user has DND enabled; suppress notifications // false → DND off or platform is not macOS if (isDND) { console.log('Do Not Disturb is active — muting notification sounds'); } ``` -------------------------------- ### Build Ferdium Application Source: https://context7.com/ferdium/ferdium-app/llms.txt Commands for building the Ferdium application, including production builds, type-checking, linting, and code preparation. ```bash # Production build (all platforms detected automatically) pnpm build # TypeScript type-checking only (no emit) pnpm typecheck # Lint with zero warnings allowed pnpm lint # Auto-fix lint + biome + prettier in one pass pnpm prepare-code ``` -------------------------------- ### Detect Language of Text Sample via IPC Source: https://context7.com/ferdium/ferdium-app/llms.txt Use the 'detect-language' IPC channel to get the ISO-639-1 language code for a given text sample. Useful for auto-selecting spellcheck languages. ```typescript // Renderer-side (used to auto-select spellcheck language) import { ipcRenderer } from 'electron'; const sample = 'Bonjour, comment allez-vous aujourd\'hui?'; const langCode: string | null = await ipcRenderer.invoke('detect-language', { sample }); // Returns: 'fr' // Use result to configure spellchecker if (langCode) { console.log(`Detected language: ${langCode}`); // 'fr' } ``` -------------------------------- ### Read Workspace State with workspaceStore Source: https://context7.com/ferdium/ferdium-app/llms.txt Access observable properties from `workspaceStore` to get information about workspaces, including the list of all workspaces, the currently active workspace, and the state of the workspace drawer. Requires importing `workspaceStore`. ```typescript import { workspaceStore } from './src/features/workspaces'; // --- Read workspace state (MobX observable) --- console.log(workspaceStore.workspaces); // Workspace[] console.log(workspaceStore.activeWorkspace); // Workspace | undefined console.log(workspaceStore.isAnyWorkspaceActive); // boolean console.log(workspaceStore.isWorkspaceDrawerOpen); // boolean console.log(workspaceStore.userHasWorkspaces); // boolean ``` -------------------------------- ### Initialize Focus State IPC (Main Process) Source: https://context7.com/ferdium/ferdium-app/llms.txt Sets up the IPC channel in the main process to emit window focus and blur events to the renderer. ```typescript // Main process registration import initFocusState from './ipc-api/focusState'; initFocusState({ mainWindow }); ``` -------------------------------- ### Manage App Settings and Cache with LocalApi Source: https://context7.com/ferdium/ferdium-app/llms.txt LocalApi provides renderer-side access to main-process settings and cache management via IPC. Use it to read and write application settings, get the total cache size, and clear cache for specific services or all services. ```typescript import LocalApi from './src/api/server/LocalApi'; const localApi = new LocalApi(); // --- Read settings for a type --- const resp = await localApi.getAppSettings('app'); // resp: { type: 'app', data: { theme: 'dark', accentColor: '#7367f0', ... } } // --- Write settings --- await localApi.updateAppSettings('app', { theme: 'light', serviceRibbonWidth: 80, }); // --- Get total service cache size in bytes --- const bytes = await localApi.getAppCacheSize(); console.log(`Cache size: ${bytes} bytes`); // e.g. 104857600 // --- Clear cache for a specific service --- await localApi.clearCache('service-id-123'); // --- Clear ALL service caches --- await localApi.clearCache(null); ``` -------------------------------- ### Clone Ferdium Repository and Submodules Source: https://github.com/ferdium/ferdium-app/blob/develop/CONTRIBUTING.md Clones the Ferdium repository and initializes all necessary submodules, including ferdium-recipes. ```bash git clone https://github.com/ferdium/ferdium-app.git cd ferdium-app git submodule update --init --recursive --remote --rebase --force ``` -------------------------------- ### Authenticated Fetch Requests with sendAuthRequest Source: https://context7.com/ferdium/ferdium-app/llms.txt The sendAuthRequest utility wraps window.fetch to include JWT Bearer auth, Ferdium version headers, and optional local-server token injection. It supports authenticated GET and POST requests, as well as unauthenticated requests by setting the auth parameter to false. ```typescript import { sendAuthRequest, prepareAuthRequest } from './src/api/utils/auth'; // Simple authenticated GET const response = await sendAuthRequest('https://api.ferdium.app/v1/me'); const user = await response.json(); // Authenticated POST with body const res = await sendAuthRequest('https://api.ferdium.app/v1/service', { method: 'POST', body: JSON.stringify({ recipeId: 'slack', name: 'My Slack' }), }); if (!res.ok) throw new Error(res.statusText); const created = await res.json(); // Unauthenticated request (e.g. health check, signup) const health = await sendAuthRequest( 'https://api.ferdium.app/health', { method: 'GET' }, false, // auth = false → no Authorization header ); // Headers automatically injected on every request: // Authorization: Bearer (when auth=true) // Content-Type: application/json // X-Franz-Source: desktop // X-Franz-Version: 7.1.3-nightly.3 // X-Franz-platform: linux | darwin | win32 // X-Franz-Timezone-Offset: -60 // X-Franz-System-Locale: en-US // X-Ferdium-Local-Token: (when using local server) ``` -------------------------------- ### Initialize Appearance Feature Source: https://context7.com/ferdium/ferdium-app/llms.txt Dynamically generates and injects CSS for appearance customization based on user settings. Call this once during app boot after stores are ready. Appearance settings include accent colors, sidebar width, icon sizes, grayscale effects, and custom user CSS. ```typescript import initAppearance from './src/features/appearance'; // Called once during app boot after stores are ready initAppearance(stores); // Appearance reacts automatically to these settings keys: // settings.all.app.accentColor → e.g. '#7367f0' // settings.all.app.progressbarAccentColor // settings.all.app.serviceRibbonWidth → 35 | 45 | 68 | 80 | 90 | 100 (px) // settings.all.app.iconSize → numeric bias added to icon width // settings.all.app.useHorizontalStyle → horizontal sidebar layout // settings.all.app.showDragArea → macOS traffic-light drag region // settings.all.app.useGrayscaleServices → inactive services shown in greyscale // settings.all.app.grayscaleServicesDim → opacity % for greyscale services // settings.all.app.alwaysShowWorkspaces → workspace drawer always visible // settings.all.app.showServiceName → show label under service icon // settings.all.app.sidebarServicesLocation → TOPLEFT | CENTER | BOTTOMRIGHT // settings.all.app.useCompactWorkspaceDrawer // Custom user CSS is loaded from: // /config/custom.css // and appended to the generated style block on every refresh // Example: to change the accent colour at runtime via settings action actions.settings.update({ type: 'app', data: { accentColor: '#e74c3c' }, }); // → CSS is regenerated and injected into