Electron API Reference

Complete reference for the DeployYourApp Electron updater — main process class, IPC channels, preload bridge, renderer helpers, and events.


Reference for @deploy-your-app/electron-update-manager. The package publishes three entry points, one per Electron process.

import { ElectronUpdateManager, IPC_CHANNELS } from '@deploy-your-app/electron-update-manager/main';
import '@deploy-your-app/electron-update-manager/preload';
import { getUpdaterApi, autoUpdate } from '@deploy-your-app/electron-update-manager/renderer';

The root entry (@deploy-your-app/electron-update-manager) re-exports all four names for convenience.

Main process

new ElectronUpdateManager(config, builtinBundlePath)

Parameter Type Description
config UpdaterConfig Options table below. appId is required; the constructor throws without it.
builtinBundlePath string Directory containing the index.html shipped inside the app package. Resolved to an absolute path.

The constructor reads Electron's userData path and creates the device ID file, so construct it inside app.whenReady().

Configuration options

Option Type Default Description
appId string required App ID registered on DeployYourApp
updateUrl string https://api.deployyour.app/api/update Update check endpoint
statsUrl string https://api.deployyour.app/api/stats Analytics endpoint
channel string 'production' Update channel. A channel persisted by setChannel() overrides this at startup.
autoUpdate boolean true Run the full check/download/apply cycle automatically
appReadyTimeout number 10000 Milliseconds to wait for notifyAppReady() before rolling back
checkInterval number 600 Seconds between automatic checks
publicKey string PEM public key. When set, every bundle's RSA signature is verified. When unset, signature verification is skipped.
encryptionPrivateKey string PEM private key used to unwrap the AES session key of an encrypted bundle
analyticsEnabled boolean true Buffer and send analytics, including the automatic update_* events
analyticsBatchSize number 20 Buffered events before an automatic flush
analyticsFlushInterval number 30 Seconds between automatic flushes
applyMode string 'whenIdle' When a downloaded bundle is activated. See below.
resetWhenUpdate boolean true Drop back to the built-in bundle when the native app version changes
autoDeleteFailed boolean true Delete a rolled-back bundle's files. The version stays quarantined either way; this only reclaims disk space.
allowedDownloadHosts string[] ['storage.deployyour.app'] Extra hosts allowed to serve bundles. The updateUrl and statsUrl hosts are always allowed, so this is only needed when you serve bundles from your own storage or CDN. Downloads are https-only; http is accepted from localhost alone.
directUpdate string Deprecated. Alias for applyMode, honoured only when applyMode is not set. 'immediate' maps to 'immediate'; any other value maps to 'whenIdle'.

applyMode

Value Behaviour after a successful download
whenIdle Record the bundle as current without reloading. It loads on the next launch. Default.
immediate Apply and reload the window now
onLaunch Hold as pending. Applied by the first check after the next launch.
background Download only. Call apply() yourself.

The server can override the mode per update, force it with mandatory, and postpone it with delayUntil. See Update lifecycle.

Lifecycle methods

initialize(options?)

Creates the bundle directory, loads persisted state and settings, runs the crash-loop check, registers the IPC handlers, and starts the auto-update and analytics timers. Call it before creating the window.

Option Type Default Description
window BrowserWindow Window to reload on apply and rollback. Equivalent to calling setWindow().

Returns: Promise<void>

setWindow(window)

Sets the window the updater reloads when a bundle is applied or rolled back. Without a window, applying a bundle only emits reload, and your app must load getBundlePath() itself.

getBundlePath()

Returns: string — the absolute path to the active bundle's index.html, or the built-in bundle's index.html when no update is active or the recorded bundle is missing from disk.

checkForUpdate()

Applies any due pending bundle, then queries the update server.

Returns: Promise<UpdateCheckResult>

Property Type Description
available boolean Whether a bundle is offered
version string Version of the offered bundle
url string Download URL
checksum string Expected SHA-256 of the bytes to download
signature string Base64 RSA signature, or null for unsigned bundles
sessionKey string Encrypted AES session key, or null when the bundle is not encrypted
applyMode string Server-dictated mode for this update
mandatory boolean When true, the update is applied immediately regardless of applyMode
delayUntil string ISO 8601 timestamp, or null

This method never rejects. Network failures, non-2xx responses, and malformed bodies emit updateFailed with code CHECK_FAILED and resolve to { available: false }. A 204 or 404 response emits noUpdateAvailable and resolves to { available: false }.

download(options)

Downloads, verifies, decrypts, and extracts a bundle. Extraction happens in a hidden staging directory and is swapped into place only after the archive validates, so a failure never leaves a half-written bundle.

Option Type Description
url string Download URL
version string Bundle version. Used as a directory name, so it must match ^[0-9A-Za-z.\-+]{1,64}$.
checksum string Expected SHA-256 hex digest
signature string Base64 RSA signature, verified only when publicKey is configured
sessionKey string (optional) Encrypted AES session key. Triggers decryption.

Returns: Promise<{ id: string, version: string }>

Rejects when the version string is invalid, when the version is already the active bundle, when another download is in flight, on HTTP failure, on checksum or signature mismatch, on decryption failure, on path traversal in the archive, or when the archive has no index.html at its root.

apply(options)

Records a downloaded bundle as current and marks it unconfirmed.

Option Type Default Description
id string required Bundle version to activate
immediate boolean true Reload the window now and start the ready-check timer. When false, the bundle is recorded and takes effect on the next launch.

Returns: Promise<void> — rejects if the bundle is not on disk.

notifyAppReady()

Confirms the running bundle, clears the ready-check timer, resets the crash-loop counter, and emits appReady. Synchronous, returns undefined.

startReadyCheck()

Starts the appReadyTimeout timer. apply({ immediate: true }) calls it for you; call it manually only if you activate a bundle yourself.

reset()

Factory reset. Clears the current and pending bundle, deletes every downloaded bundle from disk, clears the quarantine list, clears any version override, then reloads the window with the built-in bundle.

Returns: Promise<void>

getFailedVersions()

Versions that were rolled back on this device and will not be installed again. Cleared by reset().

Returns: string[]

resolveApplyMode(params)

Resolves the effective apply mode for an update.

Parameter Type Default Description
serverApplyMode string applyMode from the check response. Wins over the configured mode.
mandatory boolean false When true, returns immediate and ignores delayUntil
delayUntil string ISO 8601 timestamp. A future value sets the pending delay and marks the result deferred.

Returns: { mode: string, deferred: boolean }

setPendingBundle(id)

Stores a bundle as pending and persists it. The next checkForUpdate() applies it once any delay has elapsed.

destroy()

Clears the check, analytics, and ready timers, and flushes buffered analytics. Call it from before-quit.

Bundle management

Method Returns Description
getCurrentBundle() { id, version, isBuiltin } Active bundle. id and version are null when the built-in bundle is active.
listBundles() Promise<Array<{ id, version, size }>> Bundle directories on disk. Hidden staging directories are excluded.
deleteBundle(id) Promise<void> Removes a bundle. Rejects when id is the active bundle.

Device, channel, and version

Method Returns Description
getDeviceId() string Random UUID generated on first run and persisted to dya-device-id
getChannel() string Active channel
setChannel(channel) Promise<void> Switches channel and persists it to dya-settings.json
getVersionOverride() string | null Current override
setVersionOverride(version) Promise<void> Reports this version to the server instead of the real bundle version. Pass null or '' to clear. Persisted.

Analytics

Method Description
trackEvent(name, properties?) Buffers a custom event
trackPageView(path, title?) Buffers a page_view event
trackError(message, stack?, fatal?) Buffers an error event
flushAnalytics() Posts the buffer now. On failure the events are put back and the buffer is re-capped.

The buffer holds at most 500 events; the oldest are dropped first. Every buffered event carries eventType, eventData, bundleVersion ('builtin' when no update is active), and an ISO timestamp.

When analyticsEnabled is true, the updater emits these events on its own:

update_check, update_available, update_download_start, update_download_complete, update_download_fail, update_verify_pass, update_verify_fail, update_apply, update_rollback, update_app_ready.

Setting analyticsEnabled: false suppresses these too. It is read at construction — there is no runtime toggle.

Main process events

ElectronUpdateManager extends EventEmitter.

Event Payload Description
updateAvailable { version, message } A bundle is offered
noUpdateAvailable The server has nothing for this device
downloadProgress { percent, bytesDownloaded, totalBytes } percent is 0 when the response has no content-length
downloadComplete { id, version } Bundle extracted and staged into place
downloadFailed { message, version } Download, verification, decryption, or extraction failed
updateApplied { id, version } Bundle recorded as current
updateFailed { message, code } See error codes below
rollback { from, to, reason } Reverted to the previous bundle. reason is appReadyTimeout or crashLoop; from is quarantined.
updateSkipped { version, reason } An offered update was not installed. reason is previouslyRolledBack.
reload The active bundle changed
appReady notifyAppReady() was called
appVersionChange { previousVersion, currentVersion } The native app version changed and resetWhenUpdate reset to the built-in bundle

appReady and appVersionChange are main-process only. Every other event is forwarded to all renderer processes.

IPC channels

Exported as IPC_CHANNELS from the /main entry. initialize() registers an ipcMain.handle for each request channel; event channels are sent with webContents.send to every window.

Request channels (renderer to main)

Constant Channel Maps to
CHECK_FOR_UPDATE dya:check-for-update checkForUpdate()
DOWNLOAD dya:download download(opts)
APPLY dya:apply apply(opts)
NOTIFY_APP_READY dya:notify-app-ready notifyAppReady()
RESET dya:reset reset()
GET_CURRENT_BUNDLE dya:get-current-bundle getCurrentBundle()
LIST_BUNDLES dya:list-bundles listBundles()
DELETE_BUNDLE dya:delete-bundle deleteBundle(id)
GET_DEVICE_ID dya:get-device-id getDeviceId()
GET_CHANNEL dya:get-channel getChannel()
SET_CHANNEL dya:set-channel setChannel(channel)
GET_VERSION_OVERRIDE dya:get-version-override getVersionOverride()
SET_VERSION_OVERRIDE dya:set-version-override setVersionOverride(version)
TRACK_EVENT dya:track-event trackEvent(name, props)
TRACK_PAGE_VIEW dya:track-page-view trackPageView(path, title)
TRACK_ERROR dya:track-error trackError(msg, stack, fatal)
FLUSH_ANALYTICS dya:flush-analytics flushAnalytics()

dya:set-channel, dya:get-version-override, and dya:set-version-override are handled by the main process but are not exposed on the preload bridge. To reach them from the renderer, add your own contextBridge method in a preload script.

Event channels (main to renderer)

Constant Channel Emitter event
ON_UPDATE_AVAILABLE dya:on-update-available updateAvailable
ON_DOWNLOAD_PROGRESS dya:on-download-progress downloadProgress
ON_DOWNLOAD_COMPLETE dya:on-download-complete downloadComplete
ON_DOWNLOAD_FAILED dya:on-download-failed downloadFailed
ON_UPDATE_APPLIED dya:on-update-applied updateApplied
ON_UPDATE_FAILED dya:on-update-failed updateFailed
ON_ROLLBACK dya:on-rollback rollback
ON_NO_UPDATE dya:on-no-update noUpdateAvailable
ON_RELOAD dya:on-reload reload

Preload bridge

Importing @deploy-your-app/electron-update-manager/preload exposes window.deployYourApp through contextBridge. Every method returns a promise; every on* method returns an unsubscribe function.

Member Signature
checkForUpdate () => Promise<UpdateCheckResult>
download (opts) => Promise<{ id, version }>
apply (opts) => Promise<void>
notifyAppReady () => Promise<void>
reset () => Promise<void>
getCurrentBundle () => Promise<BundleInfo>
listBundles () => Promise<BundleEntry[]>
deleteBundle (id) => Promise<void>
getDeviceId () => Promise<string>
getChannel () => Promise<string>
setChannel (channel) => Promise<void>
getVersionOverride () => Promise<string>
setVersionOverride (version) => Promise<void>
trackEvent (name, properties?) => Promise<void>
trackPageView (path, title?) => Promise<void>
trackError (message, stack?, fatal?) => Promise<void>
flushAnalytics () => Promise<void>
onUpdateAvailable (cb: ({ version, message }) => void) => () => void
onDownloadProgress (cb: ({ percent, bytesDownloaded, totalBytes }) => void) => () => void
onDownloadComplete (cb: ({ id, version }) => void) => () => void
onDownloadFailed (cb: ({ message, version }) => void) => () => void
onUpdateApplied (cb: ({ id, version }) => void) => () => void
onUpdateFailed (cb: ({ message, code }) => void) => () => void
onRollback (cb: ({ from, to, reason }) => void) => () => voidreason is appReadyTimeout or crashLoop
onNoUpdate (cb: () => void) => () => void
onReload (cb: () => void) => () => void

The bridge exposes no channel or version-override setters. setChannel and setVersionOverride are main-process only.

Renderer helpers

getUpdaterApi()

Returns: the window.deployYourApp object. Throws when the preload bridge is not registered.

import { getUpdaterApi } from '@deploy-your-app/electron-update-manager/renderer';

const api = getUpdaterApi();
const { id, version, isBuiltin } = await api.getCurrentBundle();

autoUpdate(options?)

Runs check, download, and apply in one call.

Option Type Default Description
onProgress function Called with { percent, bytesDownloaded, totalBytes }. Unsubscribed when the call settles.
immediate boolean true Passed through to apply(). Set false to defer activation to the next launch.

Returns: Promise<{ updated: boolean, version?: string }>{ updated: false } when no update is available. Rejects if the download or apply step fails.

This helper is for apps running with autoUpdate: false. With the main-process auto-update loop enabled, both would race for the same bundle directory and one would fail the single-flight guard.

Error codes

The Electron updater reports failures two ways: a code on the updateFailed event, and rejection messages from download() and apply().

updateFailed codes

Code Cause
CHECK_FAILED The update check threw — network failure, timeout, non-2xx status, or an unparseable body
LOAD_FAILED BrowserWindow.loadFile() rejected while activating a bundle

Rejection messages

download() and apply() reject with plain Error objects that carry no code. Branch on the message when you need to distinguish them.

Message Cause
Invalid bundle version string: <version> Version does not match ^[0-9A-Za-z.\-+]{1,64}$
Version <version> is already the active bundle Re-downloading the live bundle was blocked
A bundle download is already in progress (version <version>) Single-flight guard
Download failed: <status> Non-2xx HTTP status on the bundle URL
Checksum mismatch — bundle may be corrupted SHA-256 of the downloaded bytes does not match
Invalid bundle signature RSA verification failed against the configured publicKey
Encryption private key required for E2E decryption. Set config.encryptionPrivateKey Encrypted bundle with no encryptionPrivateKey
Unrecognized encrypted bundle format. Re-deploy the bundle with the current CLI. The payload is not in the DYA1 wire format
Path traversal detected in extracted ZIP: <name> An extracted entry resolved outside the bundle directory
Bundle <version> does not contain an index.html at its root Archive layout is wrong
Bundle <id> not found on disk apply() was given an id that was never downloaded

The same failures also emit downloadFailed with the message, and are recorded as update_download_fail or update_verify_fail analytics events.

Timeouts and limits

Behaviour Value
Update check timeout 30 seconds
Bundle download timeout 300 seconds
Analytics POST timeout 15 seconds
Buffered analytics cap 500 events
Unconfirmed launches before rollback 3
First automatic check after initialize() 3 seconds

Previous
Setup
Next
Update Lifecycle