### Start the Application Source: https://github.com/balena-io/etcher/blob/master/docs/CONTRIBUTING.md Run this command to start the Etcher application after cloning the repository. ```sh npm start ``` -------------------------------- ### Install Etcher with WinGet Source: https://github.com/balena-io/etcher/blob/master/README.md Installs Etcher on Windows using the WinGet package manager. You can use either 'balenaEtcher' or 'Balena.Etcher' as the package name. ```powershell winget install balenaEtcher #or Balena.Etcher ``` -------------------------------- ### Install Etcher with Chocolatey Source: https://github.com/balena-io/etcher/blob/master/README.md Installs Etcher on Windows using the Chocolatey package manager. ```powershell choco install etcher ``` -------------------------------- ### Install .deb file using apt Source: https://github.com/balena-io/etcher/blob/master/README.md Use this command to install the Etcher .deb package on Debian and Ubuntu-based systems. Ensure you have the correct file name. ```sh sudo apt install ./balena-etcher_******_amd64.deb ``` -------------------------------- ### Install Etcher from AUR using yay Source: https://github.com/balena-io/etcher/blob/master/README.md Installs the latest release of Etcher from the Arch User Repository using the yay helper. This is for Arch/Manjaro Linux. ```sh yay -S balena-etcher ``` -------------------------------- ### Install Python Dependencies Source: https://github.com/balena-io/etcher/blob/master/docs/CONTRIBUTING.md Installs project dependencies using pip. May require administrator permissions. ```sh pip install -r requirements.txt ``` -------------------------------- ### supported-formats Source: https://context7.com/balena-io/etcher/llms.txt Utilities for image format detection, including a list of supported extensions and a helper to identify Windows installer images. ```APIDOC ## `supported-formats` — Image format detection utilities Exports the list of recognized image extensions and a helper to detect Windows installer images (which get a special warning in the UI). ### Exports - **`SUPPORTED_EXTENSIONS`**: An array of strings representing the file extensions of supported image formats. - **`looksLikeWindowsImage(filename: string)`**: A function that returns `true` if the given filename appears to be a Windows image, `false` otherwise. ### Example Usage ```typescript import { SUPPORTED_EXTENSIONS, looksLikeWindowsImage } from './shared/supported-formats'; console.log(SUPPORTED_EXTENSIONS); // ['bin','bz2','dmg','dsk','etch','gz','hddimg','img','raw', // 'rpi-sdimg','sdcard','vhd','wic','xz','zip'] console.log(looksLikeWindowsImage('Win10_22H2_x64.iso')); // true console.log(looksLikeWindowsImage('windows-server-2022.img')); // true console.log(looksLikeWindowsImage('raspios-bullseye.img')); // false ``` ``` -------------------------------- ### Install RPM file using yum Source: https://github.com/balena-io/etcher/blob/master/README.md Installs the Etcher RPM package on Fedora-based and Redhat systems using yum. Replace *** with the actual version number. ```sh sudo yum localinstall balena-etcher-***.x86_64.rpm ``` -------------------------------- ### Referencing Resources in Commits Source: https://github.com/balena-io/etcher/blob/master/docs/COMMIT-GUIDELINES.md Examples of using 'See' and 'Link' tags to reference external resources relevant to a commit, such as pull requests, issues, or websites. ```text See: https://github.com/xxx/yyy/ ``` ```text See: 49d89b4acebd80838303b011d30517cd6229fdbe ``` ```text Link: https://github.com/xxx/yyy/issues/zzz ``` -------------------------------- ### Detect Supported Image Formats with `supported-formats` Source: https://context7.com/balena-io/etcher/llms.txt Utilize `supported-formats` to access a list of recognized image file extensions and to detect specific Windows installer images. This helps in providing user feedback and warnings. ```typescript import { SUPPORTED_EXTENSIONS, looksLikeWindowsImage } from './shared/supported-formats'; console.log(SUPPORTED_EXTENSIONS); // ['bin','bz2','dmg','dsk','etch','gz','hddimg','img','iso','raw', // 'rpi-sdimg','sdcard','vhd','wic','xz','zip'] // Detect Windows images by filename console.log(looksLikeWindowsImage('Win10_22H2_x64.iso')); // true console.log(looksLikeWindowsImage('windows-server-2022.img')); // true console.log(looksLikeWindowsImage('raspios-bullseye.img')); // false ``` -------------------------------- ### Closing Issues with Commits Source: https://github.com/balena-io/etcher/blob/master/docs/COMMIT-GUIDELINES.md Examples of using 'Closes' and 'Fixes' tags to automatically close GitHub issues when a commit is merged. It is recommended to use absolute URLs. ```text Closes: https://github.com/balena-io/etcher/issues/XXX ``` ```text Fixes: https://github.com/balena-io/etcher/issues/XXX ``` -------------------------------- ### Uninstall Etcher with yay Source: https://github.com/balena-io/etcher/blob/master/README.md Removes Etcher from Arch/Manjaro systems when installed via the AUR using yay. ```sh yay -R balena-etcher ``` -------------------------------- ### Convert Flash State to Human-Readable Progress Labels Source: https://context7.com/balena-io/etcher/llms.txt Use `fromFlashState` to convert raw flash state into localized status strings for UI display. `titleFromFlashState` is specifically for OS window title bars. Both functions handle different states like decompressing, flashing, verifying, and starting, with or without percentage completion. ```typescript import { fromFlashState, titleFromFlashState } from './modules/progress-status'; import type { FlashState } from './modules/progress-status'; // Decompressing with known percentage const decomp = fromFlashState({ type: 'decompressing', percentage: 35, position: 0 }); // => { status: 'Decompressing...', position: '35%' } // Flashing at 72% const flashing = fromFlashState({ type: 'flashing', percentage: 72, position: 0 }); // => { status: 'Flashing...', position: '72%' } // Verifying without percentage (position-based) const verifying = fromFlashState({ type: 'verifying', percentage: undefined, position: 2_000_000_000 }); // => { status: 'Validating...', position: '2 GB' } // For the OS window title bar const title = titleFromFlashState({ type: 'flashing', percentage: 72, position: 0 }); // => '72% Flashing...' // Starting (no type yet) const starting = fromFlashState({ type: undefined, percentage: undefined, position: 0 }); // => { status: 'Starting...' } ``` -------------------------------- ### Run Test Suite Source: https://github.com/balena-io/etcher/blob/master/docs/CONTRIBUTING.md Execute the test suite using this command. Note that not all aspects of the application can be unit tested. ```sh npm test ``` -------------------------------- ### Format Disk Partition on Windows using Diskpart Source: https://github.com/balena-io/etcher/blob/master/docs/USER-DOCUMENTATION.md Use these commands in the diskpart utility to format a partition. Ensure the partition is selected before formatting. ```batch format override quick ``` ```batch format FS=NTFS override quick ``` -------------------------------- ### settings Source: https://context7.com/balena-io/etcher/llms.txt Provides an asynchronous API for reading and writing persistent user preferences stored in a JSON configuration file. ```APIDOC ## `settings` — Persistent user preferences Async get/set API over a JSON config file stored in the OS user-data directory (`%APPDATA%/etcher/config.json` on Windows, `~/.config/etcher/config.json` on Linux, `~/Library/Application Support/etcher/config.json` on macOS). Defaults are applied at startup; writes are atomic (reverts on failure). ### Methods - **`get(key: string)`**: Reads a single setting asynchronously. - **`getSync(key: string)`**: Reads a single setting synchronously (use after initial load). - **`set(key: string, value: any)`**: Writes a setting asynchronously, persisting to disk. - **`getAll()`**: Reads all settings asynchronously. ### Example Usage ```typescript import * as settings from './models/settings'; // Read a single setting const reporting = await settings.get('errorReporting'); // Synchronous read const autoMap = settings.getSync('autoBlockmapping'); // Write a setting await settings.set('desktopNotifications', false); // Read all settings const all = await settings.getAll(); ``` ``` -------------------------------- ### Configure npm for Node-gyp Source: https://github.com/balena-io/etcher/blob/master/docs/CONTRIBUTING.md Sets the Visual Studio version for node-gyp. Use '2019' for Visual Studio 2019. ```sh npm config set msvs_version 2019 ``` -------------------------------- ### Configure Git for Binary Diffs (Repository Local) Source: https://github.com/balena-io/etcher/blob/master/docs/CONTRIBUTING.md Add these Git configurations to your repository's local config to enable hexdump-style diffs for binary files. ```sh $ git config diff.hex.textconv hexdump $ git config diff.hex.binary true ``` -------------------------------- ### Manage Persistent User Preferences with `settings` Source: https://context7.com/balena-io/etcher/llms.txt Use the `settings` module for asynchronous get/set operations on user preferences stored in a JSON config file. Defaults are applied on startup, and writes are atomic. Ensure settings are loaded before using synchronous read operations. ```typescript import * as settings from './models/settings'; // Default settings at startup: // { // errorReporting: true, // updatesEnabled: true, // only for appimage/nsis/dmg package types // desktopNotifications: true, // autoBlockmapping: true, // decompressFirst: true, // } // Read a single setting (async, waits for initial load) const reporting = await settings.get('errorReporting'); console.log(reporting); // true // Synchronous read (use only after settings are loaded) const autoMap = settings.getSync('autoBlockmapping'); // Write a setting (persists to disk) await settings.set('desktopNotifications', false); // Read all settings at once const all = await settings.getAll(); console.log(all); // { errorReporting: true, updatesEnabled: true, desktopNotifications: false, // autoBlockmapping: true, decompressFirst: true } // Custom setting (e.g., ledsMapping for balenaEtcher Pro hardware) await settings.set('ledsMapping', { 'platform-xhci-hcd.0.auto-usb-0:1.1.1:1.0-scsi-0:0:0:0': ['led1_r', 'led1_g', 'led1_b'], }); await settings.set('drivesOrder', ['sda', 'sdb', 'sdc']); ``` -------------------------------- ### Configure Git for Binary Diffs (Global) Source: https://github.com/balena-io/etcher/blob/master/docs/CONTRIBUTING.md Add these Git configurations to your global Git config to enable hexdump-style diffs for binary files across all repositories. ```sh $ git config --global diff.hex.textconv hexdump $ git config --global diff.hex.binary true ``` -------------------------------- ### Initiate Flash Operation with imageWriter.flash Source: https://context7.com/balena-io/etcher/llms.txt Orchestrates the full flash lifecycle, including setting flags, delegating to `performWrite`, and clearing flags with results. Throws an error if a flash is already in progress. Requires `flash` and `cancel` imports from `./modules/image-writer` and type definitions for `SourceMetadata` and `Drive`. ```typescript // lib/gui/app/modules/image-writer.ts import { flash, cancel } from './modules/image-writer'; import type { SourceMetadata } from '../../shared/typings/source-selector'; import type { Drive } from 'drivelist'; const image: SourceMetadata = { path: '/home/user/raspios-bullseye.img', displayName: 'Raspberry Pi OS', description: 'raspios-bullseye.img', SourceType: 'File', extension: 'img', size: 4_000_000_000, isSizeEstimated: false, }; const drives: Drive[] = [ { device: '/dev/sdb', description: 'Kingston DataTraveler 32GB', size: 32_000_000_000, isSystem: false, isReadOnly: false }, ]; try { await flash(image, drives); console.log('Flash complete'); } catch (err) { console.error('Flash failed:', err.message); } // Cancel an in-progress flash await cancel('abort'); // passes 'abort' as cancel status to the sidecar ``` -------------------------------- ### permissions.elevateCommand / permissions.isElevated Source: https://context7.com/balena-io/etcher/llms.txt Provides cross-platform utilities for checking current privilege levels and elevating command execution when necessary. ```APIDOC ## `permissions.elevateCommand` / `permissions.isElevated` — Privilege escalation Cross-platform privilege escalation: uses `osascript` on macOS Catalina+, `sudo-prompt` on Linux, and a UAC prompt on Windows. Falls back to direct spawn if already elevated. Environment variables are passed as `--KEY=VALUE` CLI arguments to survive `sudo`'s env-stripping. ### Methods - **`isElevated()`**: Asynchronously checks if the current process is running with elevated privileges (root/administrator). - **`elevateCommand(command: string[], options?: { applicationName?: string, env?: NodeJS.ProcessEnv })`**: Executes a command, prompting the user for elevation if necessary. Returns a promise that resolves with an object indicating if the operation was cancelled or successful. ### Example Usage ```typescript import { isElevated, elevateCommand } from './shared/permissions'; // Check current privilege level const elevated = await isElevated(); console.log(`Running as root/admin: ${elevated}`); // Elevate a command const result = await elevateCommand( ['/path/to/etcher-util'], { applicationName: 'balenaEtcher', env: { ETCHER_SERVER_ADDRESS: '127.0.0.1', ETCHER_SERVER_PORT: '3435', ETCHER_SERVER_ID: 'etcher-abc123', UV_THREADPOOL_SIZE: '64', }, }, ); if (result.cancelled) { console.log('User cancelled the privilege prompt'); } else { console.log('Sidecar started with elevated privileges'); } ``` ``` -------------------------------- ### `progressStatus.fromFlashState` / `titleFromFlashState` Source: https://context7.com/balena-io/etcher/llms.txt Converts raw flash state into localized status strings for UI display and OS window titles. ```APIDOC ## `fromFlashState` / `titleFromFlashState` — Human-readable progress labels Converts raw flash state (type + percentage/position) into localized status strings for display in the UI and OS window title bar. ```typescript import { fromFlashState, titleFromFlashState } from './modules/progress-status'; import type { FlashState } from './modules/progress-status'; // Decompressing with known percentage const decomp = fromFlashState({ type: 'decompressing', percentage: 35, position: 0 }); // => { status: 'Decompressing...', position: '35%' } // Flashing at 72% const flashing = fromFlashState({ type: 'flashing', percentage: 72, position: 0 }); // => { status: 'Flashing...', position: '72%' } // Verifying without percentage (position-based) const verifying = fromFlashState({ type: 'verifying', percentage: undefined, position: 2_000_000_000 }); // => { status: 'Validating...', position: '2 GB' } // For the OS window title bar const title = titleFromFlashState({ type: 'flashing', percentage: 72, position: 0 }); // => '72% Flashing...' // Starting (no type yet) const starting = fromFlashState({ type: undefined, percentage: undefined, position: 0 }); // => { status: 'Starting...' } ``` ``` -------------------------------- ### Configure Wayland XWayland Module Source: https://github.com/balena-io/etcher/blob/master/docs/FAQ.md To run Etcher on Wayland, ensure the xwayland.so module is loaded by declaring it in your weston.ini file. This provides backwards compatibility for X clients. ```ini [core] modules=xwayland.so ``` -------------------------------- ### Package Etcher for All Platforms Source: https://github.com/balena-io/etcher/blob/master/docs/PUBLISHING.md Run this command on each platform to produce all targets specified in forge.config.ts for the host platform and architecture. The resulting artifacts can be found in `out/make`. ```sh npm run make ``` -------------------------------- ### Continuous Block Device Discovery with Drive Scanner Source: https://context7.com/balena-io/etcher/llms.txt The `drive-scanner` module, used in the sidecar process, sets up a continuous block device discovery mechanism. It utilizes `etcher-sdk`'s `Scanner` with various adapters (BlockDeviceAdapter, UsbbootDeviceAdapter, DriverlessDeviceAdapter on Windows) to detect drive attachments and detachments. Event listeners can be attached to `scanner.on('attach', ...)` and `scanner.on('detach', ...)`. ```typescript // lib/util/drive-scanner.ts (runs in the sidecar process) import { scanner } from './drive-scanner'; // scanner is a pre-configured sdk.scanner.Scanner instance scanner.on('attach', (drive) => { console.log('Drive attached:', drive.device, drive.description); }); scanner.on('detach', (drive) => { console.log('Drive removed:', drive.device); }); // Start scanning scanner.start(); // Stop scanning when done scanner.stop(); ``` -------------------------------- ### imageWriter.flash Source: https://context7.com/balena-io/etcher/llms.txt Initiates a flash operation from the GUI. This method orchestrates the entire flashing lifecycle, from setting the flashing state to delegating the write operation to a privileged sidecar process and handling the results. ```APIDOC ## imageWriter.flash — Initiate a flash operation from the GUI ### Description Orchestrates the full flash lifecycle from the renderer process: sets the flashing flag in the Redux store, delegates the actual write to `performWrite` (which spawns the privileged sidecar and wires WebSocket event handlers), then clears the flashing flag with results. Throws if a flash is already in progress. ### Method Signature ```typescript flash(image: SourceMetadata, drives: Drive[]): Promise ``` ### Parameters * **image** (SourceMetadata) - Required - Metadata about the image to be flashed. * **drives** (Drive[]) - Required - An array of drive objects representing the destinations for the flash operation. ### Request Example ```typescript import type { SourceMetadata } from '../../shared/typings/source-selector'; import type { Drive } from 'drivelist'; const image: SourceMetadata = { path: '/home/user/raspios-bullseye.img', displayName: 'Raspberry Pi OS', description: 'raspios-bullseye.img', SourceType: 'File', extension: 'img', size: 4_000_000_000, isSizeEstimated: false, }; const drives: Drive[] = [ { device: '/dev/sdb', description: 'Kingston DataTraveler 32GB', size: 32_000_000_000, isSystem: false, isReadOnly: false }, ]; try { await flash(image, drives); console.log('Flash complete'); } catch (err) { console.error('Flash failed:', err.message); } ``` ``` -------------------------------- ### `drive-scanner` (sidecar) Source: https://context7.com/balena-io/etcher/llms.txt Manages continuous block device discovery using etcher-sdk Scanner with various adapters. ```APIDOC ## `drive-scanner` (sidecar) — Continuous block device discovery Instantiates an `etcher-sdk` Scanner with `BlockDeviceAdapter` (all drives) and `UsbbootDeviceAdapter` (Raspberry Pi CM devices, root/admin only). On Windows, also adds `DriverlessDeviceAdapter` for devices lacking drivers. The scanner is a long-lived event emitter used by the sidecar. ```typescript // lib/util/drive-scanner.ts (runs in the sidecar process) import { scanner } from './drive-scanner'; // scanner is a pre-configured sdk.scanner.Scanner instance scanner.on('attach', (drive) => { console.log('Drive attached:', drive.device, drive.description); }); scanner.on('detach', (drive) => { console.log('Drive removed:', drive.device); }); // Start scanning scanner.start(); // Stop scanning when done scanner.stop(); ``` ``` -------------------------------- ### spawnChildAndConnect Source: https://context7.com/balena-io/etcher/llms.txt Spawns and connects to the privileged sidecar process (`etcher-util`). It handles retries for the WebSocket connection and provides methods to emit commands and register event handlers. ```APIDOC ## spawnChildAndConnect — Spawn and connect to the privileged sidecar ### Description Spawns the `etcher-util` sidecar (with or without privileges), retries a WebSocket connection up to 10 times with 1-second delays, and resolves with `{ emit, registerHandler }` once the handshake completes. Used internally by `imageWriter.flash`. ### Method Signature ```typescript spawnChildAndConnect(options: { withPrivileges: boolean }): Promise<{ emit: (command: string, payload?: any) => void; registerHandler: (event: string, handler: (payload: any) => void) => void }> ``` ### Parameters * **options** (object) - Required - Configuration options for spawning the child process. * **withPrivileges** (boolean) - Required - Whether to spawn the sidecar with elevated privileges. ### Request Example ```typescript import { spawnChildAndConnect } from './modules/api'; const { emit, registerHandler } = await spawnChildAndConnect({ withPrivileges: true }); // Register a handler for progress state events registerHandler('state', (state) => { console.log(`Progress: ${state.percentage}% at ${state.speed} MB/s`); }); // Register a handler for completion registerHandler('done', (payload) => { console.log('Bytes written:', payload.results.bytesWritten); console.log('Successful:', payload.results.devices.successful); console.log('Failed:', payload.results.devices.failed); }); // Kick off the write in the sidecar emit('write', { image: { path: '/home/user/image.img', SourceType: 'File' }, destinations: [{ device: '/dev/sdb' }], autoBlockmapping: true, decompressFirst: true, }); ``` ``` -------------------------------- ### `store` / `observe` Source: https://context7.com/balena-io/etcher/llms.txt Provides an Immutable.js-backed Redux store for application state and a subscription method with deep-equality change detection. ```APIDOC ## `store` / `observe` — Immutable Redux store and subscription The central Immutable.js-backed Redux store that holds all application state. `observe` wraps `store.subscribe` with deep-equality change detection so observers only fire on genuine state changes. ```typescript import { store, observe, Actions, DEFAULT_STATE } from './models/store'; // Dispatch an action directly store.dispatch({ type: Actions.SET_AVAILABLE_TARGETS, data: [{ device: '/dev/sdb', size: 32_000_000_000, isSystem: false }], }); // Read current state const state = store.getState().toJS(); console.log(state.isFlashing); // false console.log(state.availableDrives); // [{ device: '/dev/sdb', ... }] console.log(state.selection.devices); // [] // Subscribe with change detection (returns unsubscribe function) const unsubscribe = observe((newState) => { const js = newState.toJS(); console.log('State changed. isFlashing:', js.isFlashing); console.log('Selected drives:', js.selection.devices); }); // Later, unsubscribe unsubscribe(); ``` ``` -------------------------------- ### Clone Etcher Repository Source: https://github.com/balena-io/etcher/blob/master/docs/CONTRIBUTING.md Clones the Etcher repository and its submodules. Ensure you use the --recursive flag to fetch all necessary submodules. ```sh git clone --recursive https://github.com/balena-io/etcher cd etcher ``` -------------------------------- ### `getSourceMetadata` Source: https://context7.com/balena-io/etcher/llms.txt Fetches metadata for a given source image, which can be a file path, HTTP URL, or a JSON-encoded axios config. This is used before the flashing process begins to gather information about the source. ```APIDOC ## `getSourceMetadata` — Fetch metadata for a source image Resolves source metadata (size, partition table, MBR presence, extension) for a file path, HTTP URL, or JSON-encoded axios config. Used by the sidecar's `onSourceMetadata` handler before the flash starts. ```typescript import { getSourceMetadata } from './util/source-metadata'; // From a local file const meta = await getSourceMetadata('/home/user/ubuntu.iso', 'File'); console.log(meta.size); // uncompressed size in bytes console.log(meta.hasMBR); // true/false console.log(meta.partitions); // MBRPartition[] | GPTPartition[] console.log(meta.extension); // 'iso' // From an HTTP URL const httpMeta = await getSourceMetadata('https://example.com/os.img', 'Http'); // From an HTTP URL with custom axios config (URL-encoded JSON) const axiosMeta = await getSourceMetadata( encodeURIComponent(JSON.stringify({ url: 'https://example.com/os.img', headers: { Authorization: 'Bearer token' } })), 'Http', ); // With basic auth const authMeta = await getSourceMetadata( 'https://private.example.com/os.img', 'Http', { username: 'user', password: 'pass' }, ); ``` ``` -------------------------------- ### Manage Flashing State and Progress Source: https://context7.com/balena-io/etcher/llms.txt Use this module to track the flashing process, including the flashing flag, live progress, and final results. It integrates with the write engine via WebSocket state events and manages the Redux store. ```typescript import * as flashState from './models/flash-state'; import type { MultiDestinationProgress } from 'etcher-sdk/build/multi-write'; // Check if a flash is currently running console.log(flashState.isFlashing()); // false // Set the flashing flag (also disables screensaver via IPC) flashState.setFlashingFlag(); console.log(flashState.isFlashing()); // true // Update progress (called automatically via WebSocket state events) const progress: MultiDestinationProgress = { type: 'flashing', percentage: 42, speed: 12_000_000, // bytes/sec → converted to MB/s active: 1, failed: 0, position: 1_680_000_000, averageSpeed: 11_500_000, }; flashState.setProgressState(progress); const state = flashState.getFlashState(); console.log(state.percentage); // 42 console.log(state.speed); // 12.0 (MB/s, 1 decimal place) // After flash completes flashState.unsetFlashingFlag({ cancelled: false, sourceChecksum: 'abc123' }); const results = flashState.getFlashResults(); console.log(results.cancelled); // false console.log(results.sourceChecksum); // 'abc123' console.log(flashState.wasLastFlashCancelled()); // false console.log(flashState.getLastFlashErrorCode()); // undefined // Record a per-device failure flashState.addFailedDeviceError({ device: { device: '/dev/sdc', description: 'USB Drive', devicePath: '/dev/disk/by-path/...' }, error: new Error('I/O error'), }); // Reset everything for next flash flashState.resetState(); ``` -------------------------------- ### Fetch source image metadata with getSourceMetadata Source: https://context7.com/balena-io/etcher/llms.txt This function retrieves metadata for a source image, including its size, partition table, and MBR presence. It can be used with local files, HTTP URLs, or even custom axios configurations passed as URL-encoded JSON. Basic authentication can also be provided. ```typescript import { getSourceMetadata } from './util/source-metadata'; // From a local file const meta = await getSourceMetadata('/home/user/ubuntu.iso', 'File'); console.log(meta.size); // uncompressed size in bytes console.log(meta.hasMBR); // true/false console.log(meta.partitions); // MBRPartition[] | GPTPartition[] console.log(meta.extension); // 'iso' // From an HTTP URL const httpMeta = await getSourceMetadata('https://example.com/os.img', 'Http'); // From an HTTP URL with custom axios config (URL-encoded JSON) const axiosMeta = await getSourceMetadata( encodeURIComponent(JSON.stringify({ url: 'https://example.com/os.img', headers: { Authorization: 'Bearer token' } })), 'Http', ); // With basic auth const authMeta = await getSourceMetadata( 'https://private.example.com/os.img', 'Http', { username: 'user', password: 'pass' }, ); ``` -------------------------------- ### Uninstall Etcher with apt Source: https://github.com/balena-io/etcher/blob/master/README.md Command to remove Etcher from Debian and Ubuntu-based systems using apt. ```sh sudo apt remove balena-etcher ``` -------------------------------- ### Set Analytics Tokens for Production Binaries Source: https://github.com/balena-io/etcher/blob/master/docs/MAINTAINERS.md Set the Sentry analytics token as an environment variable before generating production release binaries. ```bash export ANALYTICS_SENTRY_TOKEN="xxxxxx" ``` -------------------------------- ### Spawn and Connect to Privileged Sidecar with spawnChildAndConnect Source: https://context7.com/balena-io/etcher/llms.txt Spawns the `etcher-util` sidecar, retries WebSocket connection up to 10 times with 1-second delays, and resolves with connection handlers. Used internally by `imageWriter.flash`. Requires `spawnChildAndConnect` import from `./modules/api`. ```typescript import { spawnChildAndConnect } from './modules/api'; const { emit, registerHandler } = await spawnChildAndConnect({ withPrivileges: true }); // Register a handler for progress state events registerHandler('state', (state) => { console.log(`Progress: ${state.percentage}% at ${state.speed} MB/s`); }); // Register a handler for completion registerHandler('done', (payload) => { console.log('Bytes written:', payload.results.bytesWritten); console.log('Successful:', payload.results.devices.successful); console.log('Failed:', payload.results.devices.failed); }); // Kick off the write in the sidecar emit('write', { image: { path: '/home/user/image.img', SourceType: 'File' }, destinations: [{ device: '/dev/sdb' }], autoBlockmapping: true, decompressFirst: true, }); ``` -------------------------------- ### Manage Application State with Immutable Redux Store Source: https://context7.com/balena-io/etcher/llms.txt The `store` provides an Immutable.js-backed Redux store for application state. Use `store.dispatch` to send actions and `store.getState` to retrieve the current state. `observe` wraps `store.subscribe` to provide deep-equality change detection, ensuring callbacks only fire on actual state modifications. ```typescript import { store, observe, Actions, DEFAULT_STATE } from './models/store'; // Dispatch an action directly store.dispatch({ type: Actions.SET_AVAILABLE_TARGETS, data: [{ device: '/dev/sdb', size: 32_000_000_000, isSystem: false }], }); // Read current state const state = store.getState().toJS(); console.log(state.isFlashing); // false console.log(state.availableDrives); // [{ device: '/dev/sdb', ... }] console.log(state.selection.devices); // [] // Subscribe with change detection (returns unsubscribe function) const unsubscribe = observe((newState) => { const js = newState.toJS(); console.log('State changed. isFlashing:', js.isFlashing); console.log('Selected drives:', js.selection.devices); }); // Later, unsubscribe unsubscribe(); ``` -------------------------------- ### Elevate Commands with `permissions` Module Source: https://context7.com/balena-io/etcher/llms.txt The `permissions` module provides cross-platform utilities to check if a process is elevated (`isElevated`) and to elevate commands (`elevateCommand`). It handles platform-specific mechanisms like `osascript`, `sudo-prompt`, and UAC prompts, falling back to direct execution if already elevated. Environment variables are passed as CLI arguments to preserve them through privilege escalation. ```typescript import { isElevated, elevateCommand } from './shared/permissions'; // Check current privilege level const elevated = await isElevated(); console.log(`Running as root/admin: ${elevated}`); // Elevate a command (spawns with privilege prompt if needed) const result = await elevateCommand( ['/path/to/etcher-util'], { applicationName: 'balenaEtcher', env: { ETCHER_SERVER_ADDRESS: '127.0.0.1', ETCHER_SERVER_PORT: '3435', ETCHER_SERVER_ID: 'etcher-abc123', UV_THREADPOOL_SIZE: '64', }, }, ); if (result.cancelled) { console.log('User cancelled the privilege prompt'); } else { console.log('Sidecar started with elevated privileges'); } ``` -------------------------------- ### Wipe Disk on GNU/Linux using dd Source: https://github.com/balena-io/etcher/blob/master/docs/USER-DOCUMENTATION.md This command overwrites the beginning of a disk with zeros on GNU/Linux. Ensure the drive is unmounted and run as root. Replace 'xxx' with the device path. ```shell dd if=/dev/zero of=/dev/xxx bs=512 count=1 conv=notrunc ``` -------------------------------- ### Validate Drive and Image Compatibility Source: https://context7.com/balena-io/etcher/llms.txt Utilize these pure functions to check if a drive is suitable for a given image. They are used for auto-selection and for displaying compatibility warnings or errors in the UI. ```typescript import * as constraints from './shared/drive-constraints'; import type { DrivelistDrive } from './shared/drive-constraints'; import type { SourceMetadata } from './shared/typings/source-selector'; const drive: DrivelistDrive = { device: '/dev/sdb', size: 32_000_000_000, isSystem: false, isReadOnly: false, disabled: false, mountpoints: [{ path: '/media/usb' }], devicePath: '/dev/disk/by-path/...', displayName: '/dev/sdb', name: 'USB Drive', path: '/dev/sdb', logo: '', }; const image: SourceMetadata = { path: '/images/os.img', size: 4_000_000_000, isSizeEstimated: false, displayName: 'OS', description: 'os.img', SourceType: 'File', }; console.log(constraints.isSystemDrive(drive)); // false console.log(constraints.isDriveLargeEnough(drive, image)); // true (32GB >= 4GB) console.log(constraints.isDriveSizeLarge(drive)); // false (< 128GB) console.log(constraints.isDriveSizeRecommended(drive, image)); // true console.log(constraints.isSourceDrive(drive, image)); // false (image not on drive) console.log(constraints.isDriveValid(drive, image)); // true // Get full compatibility status list (for UI warnings/errors) const statuses = constraints.getDriveImageCompatibilityStatuses(drive, image, true); // => [] when fully compatible // Example with a too-small drive const smallDrive = { ...drive, size: 1_000_000_000 }; const smallStatuses = constraints.getDriveImageCompatibilityStatuses(smallDrive, image, true); // => [{ type: 2, message: 'Drive is too small' }] (type 2 = ERROR) // Bulk check across multiple drives const allStatuses = constraints.getListDriveImageCompatibilityStatuses([drive, smallDrive], image, true); // => [{ type: 2, message: 'Drive is too small' }] (only the small drive's status) ``` -------------------------------- ### `selectionState` Source: https://context7.com/balena-io/etcher/llms.txt Manages the Redux store for image and drive selections, providing getters and setters for user choices. It enforces validation through reducers and dispatches actions to update the store. ```APIDOC ## `selectionState` — Manage image and drive selections in the Redux store Provides getters and setters for the current user selections (source image and target drives). All mutations dispatch Redux actions to the Immutable.js store; validation (drive size, write-protection) is enforced by the reducer. ```typescript import * as selectionState from './models/selection-state'; import type { SourceMetadata } from '../../../shared/typings/source-selector'; // Select a source image const image: SourceMetadata = { path: '/images/raspios.img', displayName: 'Raspberry Pi OS', description: 'raspios.img', SourceType: 'File', extension: 'img', size: 4_000_000_000, }; selectionState.selectSource(image); // Select a target drive by device path selectionState.selectDrive('/dev/sdb'); // Toggle drive selection selectionState.toggleDrive('/dev/sdc'); // selects if not selected, deselects if selected // Read selections const selectedDrives = selectionState.getSelectedDrives(); // => DrivelistDrive[] const selectedImage = selectionState.getImage(); // => SourceMetadata | undefined console.log(selectionState.hasDrive()); // true console.log(selectionState.hasImage()); // true // Check if a specific device is selected console.log(selectionState.isDriveSelected('/dev/sdb')); // true // Clear all selections selectionState.clear(); // Deselect individually selectionState.deselectDrive('/dev/sdb'); selectionState.deselectImage(); ``` ``` -------------------------------- ### `analytics` Source: https://context7.com/balena-io/etcher/llms.txt Initializes Sentry error reporting, captures exceptions, and anonymizes file paths in events and payloads. ```APIDOC ## `analytics` — Error reporting and path anonymization Initializes Sentry error reporting (once), captures exceptions, and anonymizes file paths in both Sentry events and analytics payloads before they leave the machine. ```typescript import { logException, anonymizePath, anonymizeAnalyticsPayload, initAnalytics } from './modules/analytics'; // Log an unhandled exception (only sent to Sentry if errorReporting setting is true) try { throw new Error('Unexpected state'); } catch (err) { logException(err); } // Anonymize a file path (strips the user home prefix) const raw = '/Users/johndoe/Downloads/os.img'; const safe = anonymizePath(raw); // => '[PERSONAL PATH]/Downloads/os.img' (or similar based on path markers) // Sanitize an analytics event payload const payload = { 'image.path': '/home/alice/os.img', 'error.message': '/tmp/johndoe/flash.log: permission denied', version: '2.1.6', }; const cleaned = anonymizeAnalyticsPayload(payload); // => { 'image.path': '[PERSONAL PATH]/...', 'error.message': '[PERSONAL PATH]/...', version: '2.1.6' } // Initialize analytics manually (called lazily by logException) initAnalytics(); ``` ``` -------------------------------- ### Convert Bytes to Megabytes with Units Source: https://context7.com/balena-io/etcher/llms.txt This utility converts raw byte counts into megabytes, using a divisor of 1,000,000. It is particularly useful for formatting and displaying flash speeds in a user-friendly manner. ```typescript import { bytesToMegabytes } from './shared/units'; const speedBytes = 45_000_000; // 45 MB/s raw const speedMB = bytesToMegabytes(speedBytes); console.log(speedMB); // 45 (bytes / 1,000,000) // Used in flashState.setProgressState: // speed: _.round(bytesToMegabytes(state.speed), 1) // => 45.0 displayed in UI ``` -------------------------------- ### Skip AppImage Desktop Integration Prompt Source: https://github.com/balena-io/etcher/blob/master/docs/USER-DOCUMENTATION.md To deactivate the desktop shortcut prompt for AppImages, touch one of these files or set the SKIP environment variable before executing the AppImage. ```sh SKIP=1 ./Etcher-linux-.AppImage ``` -------------------------------- ### Embed 'Flash with Etcher' Button Source: https://github.com/balena-io/etcher/blob/master/docs/FAQ.md Integrate the 'Flash with Etcher' button into your website or blog to allow users to easily flash an OS image. Replace with the direct URL to the image file. ```html ``` -------------------------------- ### Initialize Sentry Error Reporting and Anonymize Paths Source: https://context7.com/balena-io/etcher/llms.txt The `analytics` module initializes Sentry for error reporting and provides utilities to anonymize file paths and analytics payloads. `logException` captures errors, `anonymizePath` removes user-specific prefixes from paths, and `anonymizeAnalyticsPayload` cleans event data before transmission. `initAnalytics` can be called manually. ```typescript import { logException, anonymizePath, anonymizeAnalyticsPayload, initAnalytics } from './modules/analytics'; // Log an unhandled exception (only sent to Sentry if errorReporting setting is true) try { throw new Error('Unexpected state'); } catch (err) { logException(err); } // Anonymize a file path (strips the user home prefix) const raw = '/Users/johndoe/Downloads/os.img'; const safe = anonymizePath(raw); // => '[PERSONAL PATH]/Downloads/os.img' (or similar based on path markers) // Sanitize an analytics event payload const payload = { 'image.path': '/home/alice/os.img', 'error.message': '/tmp/johndoe/flash.log: permission denied', version: '2.1.6', }; const cleaned = anonymizeAnalyticsPayload(payload); // => { 'image.path': '[PERSONAL PATH]/...', 'error.message': '[PERSONAL PATH]/...', version: '2.1.6' } // Initialize analytics manually (called lazily by logException) initAnalytics(); ``` -------------------------------- ### Uninstall Etcher with WinGet Source: https://github.com/balena-io/etcher/blob/master/README.md Removes Etcher from Windows using the WinGet package manager. ```powershell winget uninstall balenaEtcher ``` -------------------------------- ### Validate and Convert Percentages with Shared Utils Source: https://context7.com/balena-io/etcher/llms.txt Use these functions to validate if a number is a valid percentage (0-100) and to convert a percentage value to its float representation. The delay function provides asynchronous pausing, and isJson helps differentiate between URLs and JSON objects. ```typescript import { isValidPercentage, percentageToFloat, delay, isJson } from './shared/utils'; // Validate and convert percentages console.log(isValidPercentage(50)); // true console.log(isValidPercentage(101)); // false console.log(isValidPercentage(-1)); // false const float = percentageToFloat(75); console.log(float); // 0.75 try { percentageToFloat(110); // throws Error: 'Invalid percentage: 110' } catch (e) { console.error(e.message); } // Async sleep await delay(500); // waits 500ms // JSON detection (used to differentiate plain URLs from axios config objects) console.log(isJson('{"url":"https://example.com"}')); // true console.log(isJson('https://example.com')); // false console.log(isJson('not json at all')); // false ``` -------------------------------- ### Low-level write and validate with child-writer.write Source: https://context7.com/balena-io/etcher/llms.txt Use this function to perform a low-level write and validation operation within the privileged `etcher-util` sidecar process. It supports optimizations like blockmapping and decompression before flashing. Ensure the `image` and `destinations` are correctly configured. ```typescript // lib/util/child-writer.ts (runs in the sidecar process, not the renderer) import { write } from './child-writer'; const result = await write({ image: { path: 'https://example.com/os.img.gz', SourceType: 'Http', displayName: 'OS Image', description: 'os.img.gz', }, destinations: [ { device: '/dev/sdb', description: '32 GB Drive' }, ], autoBlockmapping: true, // trims ext partitions before writing decompressFirst: true, // decompress to tmp file before flashing SourceType: 'Http', }); // result: WriteResult console.log(result.bytesWritten); // e.g. 4000000000 console.log(result.devices.successful); // e.g. 1 console.log(result.devices.failed); // e.g. 0 console.log(result.errors); // [] on success ``` -------------------------------- ### Erase Disk on macOS using diskutil Source: https://github.com/balena-io/etcher/blob/master/docs/USER-DOCUMENTATION.md This command erases and formats a disk on macOS. Replace 'N' with the actual disk number. ```shell diskutil eraseDisk FAT32 UNTITLED MBRFormat /dev/diskN ``` -------------------------------- ### `child-writer.write` Source: https://context7.com/balena-io/etcher/llms.txt Performs a low-level write and validation operation within the privileged `etcher-util` sidecar process. It supports optimizations like blockmapping and decompression-before-flash. ```APIDOC ## `child-writer.write` — Low-level write-and-validate in the sidecar process Runs inside the privileged `etcher-util` sidecar. Constructs `etcher-sdk` source/destination objects (`File`, `Http`, or `BlockDevice`), calls `writeAndValidate` (which invokes `decompressThenFlash`), and returns a `WriteResult`. Supports blockmapping and decompression-before-flash optimizations. ```typescript // lib/util/child-writer.ts (runs in the sidecar process, not the renderer) import { write } from './child-writer'; const result = await write({ image: { path: 'https://example.com/os.img.gz', SourceType: 'Http', displayName: 'OS Image', description: 'os.img.gz', }, destinations: [ { device: '/dev/sdb', description: '32 GB Drive' }, ], autoBlockmapping: true, // trims ext partitions before writing decompressFirst: true, // decompress to tmp file before flashing SourceType: 'Http', }); // result: WriteResult console.log(result.bytesWritten); // e.g. 4000000000 console.log(result.devices.successful); // e.g. 1 console.log(result.devices.failed); // e.g. 0 console.log(result.errors); // [] on success ``` ``` -------------------------------- ### Uninstall Etcher with Chocolatey Source: https://github.com/balena-io/etcher/blob/master/README.md Removes Etcher from Windows using the Chocolatey package manager. ```powershell choco uninstall etcher ``` -------------------------------- ### Manage Redux store selections with selectionState Source: https://context7.com/balena-io/etcher/llms.txt This module manages the user's selected image and target drives within the Redux store. Mutations dispatch actions to the Immutable.js store, and validation is handled by the reducer. Use these functions to select, toggle, read, and clear selections. ```typescript import * as selectionState from './models/selection-state'; import type { SourceMetadata } from '../../../shared/typings/source-selector'; // Select a source image const image: SourceMetadata = { path: '/images/raspios.img', displayName: 'Raspberry Pi OS', description: 'raspios.img', SourceType: 'File', extension: 'img', size: 4_000_000_000, }; selectionState.selectSource(image); // Select a target drive by device path selectionState.selectDrive('/dev/sdb'); // Toggle drive selection selectionState.toggleDrive('/dev/sdc'); // selects if not selected, deselects if selected // Read selections const selectedDrives = selectionState.getSelectedDrives(); // => DrivelistDrive[] const selectedImage = selectionState.getImage(); // => SourceMetadata | undefined console.log(selectionState.hasDrive()); // true console.log(selectionState.hasImage()); // true // Check if a specific device is selected console.log(selectionState.isDriveSelected('/dev/sdb')); // true // Clear all selections selectionState.clear(); // Deselect individually selectionState.deselectDrive('/dev/sdb'); selectionState.deselectImage(); ```