The cycle-electron-driver
module provides Cycle.js drivers for building Electron apps.
If you are already familiar with the electron
API, here's a map of its interface to drivers:
- app
- events
will-finish-launching
- AppLifecycleDriverready
- AppLifecycleDriverwindow-all-closed
- AppLifecycleDriverbefore-quit
- AppLifecycleDriverwill-quit
- AppLifecycleDriverquit
- AppLifecycleDriveropen-file
- AppEventsDriveropen-url
- AppEventsDriveractivate
- AppEventsDriverbrowser-window-blur
- AppEventsDriverbrowser-window-focus
- AppEventsDriverbrowser-window-created
- AppEventsDrivercertificate-error
- CertErrorOverrideDriverselect-client-certificate
- ClientCertDriverlogin
- BasicAuthDrivergpu-process-crashed
- AppEventsDriver
- methods
quit
- AppLifecycleDriverexit
- AppLifecycleDriverhide
- AppVisibilityDrivershow
- AppVisibilityDrivergetAppPath
- AppConfigDrivergetPath
- AppConfigDriversetPath
- AppConfigDrivergetVersion
- AppMetadataDrivergetName
- AppMetadataDrivergetLocale
- AppMetadataDriveraddRecentDocument
- RecentDocsDriverclearRecentDocuments
- RecentDocsDriversetUserTasks
- AppConfigDriver
- events
AppConfigDriver
enables the getting/setting of configuration used by your app.
import { join } from 'path';
import { app } from 'electron';
import { AppPathsDriver } from 'cycle-electron-driver';
Cycle.run(({ config: { appPaths } }) => ({
appPaths: appPaths.appData$.map(dataPath => ({ downloads: join(dataPath, 'downloads') }))
}), {
config: AppConfigDriver(app)
});
The source for the driver is an object with the following structure.
allowNTMLForNonIntranet$
- Gives the currentallowNTMLForNonIntranet
config setting.paths
- An object with observable properties that match the electron path names with the idiomatic$
suffix (e.g.home$
,appData$
). Additionally, anapp$
property gives access to app.getAppPath().task$
- An observable ofTask
arrays.
The sink for the driver is an observable of objects describing the configuration settings to change. The following structure is supported:
allowNTMLForNonIntranet
- If set totrue
, enable NTLM auth for all domains. Otherwise, only intranet sites.paths
- An object with properties matching the electron path names. Only the specified paths are changed.tasks
: An array ofTask
objects (Windows only). These have the following properties:program
- The application executable; useprocess.execPath
to use the currently-executing app executable.arguments
- An array of strings to use as program argumentstitle
- The title to give the taskdescription
- The full description of the taskiconPath
- Path to the icon to show for the taskiconIndex
- IficonPath
contains multiple icons, the index of the icon to use for the task
AppEventsDriver
provides access to electron app events. It provides a source observable containing all events.
To create the driver, simply call the constructor with the electron app
:
import Cycle from '@cycle/core';
import { app } from 'electron';
Cycle.run(({ appEvent$ }) => ({
fileOpen$: appEvent$.filter(e => e.type === 'file-open')
}), {
appEvent$: AppEventsDriver(app)
});
These events have a type
property that matches
the names of the electron events. Additional
event arguments are normalized into the event object properties as follows:
open-file
-path
open-url
-url
activate
-hasVisibleWindows
browser-window-blur
-window
browser-window-focus
-window
browser-window-created
-window
certificate-error
-webContents
,url
,error
,certificate
login
-webContents
,request
,authInfo
AppLifecycleDriver
provides visibility into application lifecycle events & the ability to affect the app lifecycle.
The source object has the following properties:
- willFinishLaunching$ - will-finish-launching events
- ready$ - will-finish-launching events
- windowAllClosed$ - window-all-closed events
- beforeQuit$ - before-quit events
- willQuit$ - will-quit events
- quit$ - quit events. These contain an additional
exitCode
property.
The sink for AppLifecycleDriver
should provide objects describing the desired lifecycle state & behavior of the app.
The following properties are supported:
Property | Default | Description |
---|---|---|
state |
'started' |
Set to 'quitting' to initiate a quit event, 'exiting' to force an exit |
exitCode |
0 | If state is set to 'exiting' , sends this as the exit code |
isQuittingEnabled |
true |
If false , before-quit events will be cancelled |
isAutoExitEnabled |
true |
If false , will-quit events will be cancelled |
AppMetadataDriver
provides a source observable of objects describing the app. The objects have the following
properties:
name
version
locale
AppVisibilityDriver
consumes a sink of boolean values that show/hide the application's windows (OS X only).
import { app } from 'electron';
import { AppVisibilityDriver } from 'cycle-electron-driver';
Cycle.run(() => {
// ...
return {
visibility$: appState$.map(state => state.shouldHide)
};
}, {
visibility$: AppVisibilityDriver(app)
});
BasicAuthDriver
provides a source of HTTP basic auth prompts and consumes objects that provide the response
credentials.
import { app } from 'electron';
import { BasicAuthDriver } from 'cycle-electron-driver';
Cycle.run(({ login$ }) => ({
login$: login$.map(e => ({
event: e,
username: 'someuser',
password: 's0m3Pa$sw0rd'
}))
}), {
login$: BasicAuthDriver(app)
});
Source events are based on electron login events have the following properties:
webContents
- The contents of the window that received the promptrequest
- Information about the HTTP request that received the promptauthInfo
- Information about the auth prompt
Sink objects must be provided for each source event and must have the following properties:
event
- The source event that is being responded tousername
password
If you do not use this driver, then the auth prompts are automatically cancelled. Use AppEventsDriver
and watch for events of type login
if you only want to observe these failed logins.
CertErrorOverrideDriver
provides a source observable of events indicating when verification of a server's SSL
certificate has failed, and consumes a sink observable of objects indicating whether the certificate rejection should
be overridden. This driver should only rarely be needed, but it can be helpful for cases such as when you are using
a self-signed certificate during development and want your app to accept that certificate. For example:
import { app } from 'electron';
import { CertErrorOverrideDriver } from 'cycle-electron-driver';
Cycle.run(({ certErr$ }) => ({
certErr$: certErr$.map(e => ({ event: e, allow: e.certificate.issuerName === 'My Test CA' }));
}), {
certErr$: CertErrorOverrideDriver(app);
});
The source objects are based on electron certificate-error events and have the following properties:
webContents
- The contents of the window that received the errorurl
- The URL being requestederror
- The error codecertificate.data
- A buffer containing the PEM-formatted certificatecertificate.issuerName
- The issuer of the certificate
Sink objects should have these properties:
event
- The source event representing the certificate errorallow
- A booleantrue
orfalse
. Iftrue
, the SSL request will be allowed to continue. Else it will fail.
You must have one object for each source event; otherwise the driver does not know whether the certificate error should
cause the SSL requests to succeed or fail. If you do not want to override any certificate errors, do not use this
driver. If you only want to be notified when these events occur, filter the AppEventsDriver
events by type
certificate-error
.
ClientCertDriver
provides a source observable containing client SSL cert request events and consumes an observable
of client certificate selection objects.
import { app } from 'electron';
import { ClientCertDriver } from 'cycle-electron-driver';
Cycle.run(({ certSelection$ }) => ({
certSelection$: certSelection$.map(e => ({
event: e,
cert: e.certificateList.find(cert => cert.issuerName === 'My Issuer')
}));
}), {
certSelection$: ClientCertDriver(app);
});
Source event objects are based on electron select-client-certificate events and have the following properties:
webContents
- The contents of the window that received the certificate prompturl
- The URL that requested the certificatecertificateList
- An array of available certificates, each of which have the following properties:data
- PEM-encoded bufferissuerName
- Issuer’s Common Name
Sink objects must be provided for each source event and must contain the following properties:
event
- The source event representing the certificate promptcert
- One of the objects from the source event'scertificateList
property
Do not use this driver if you want to keep the default electron behavior of always selecting the first client
certificate. If you only wish to be notified when client certificates are being selected with the default behavior,
use the AppEventsDriver
and filter where type
equals select-client-certificate
.
RecentDocsDriver
provides a sink for changing the recent documents of the app. Each object in the observable should
contain one or more of the following properties:
clear
- If set totrue
, the recent documents list for the app is cleared.add
- If set to a string, the path to a document to add to the recent documents list.
import Cycle from '@cycle/core';
import { app } from 'electron';
import { RecentDocsDriver } from 'cycle-electron-driver';
Cycle.run(() => {
//...
return {
recentDoc$: model.openedDoc$.map(doc => ({ add: doc }))
}
}), {
recentDoc$: RecentDocsDriver(app)
});
To create the driver for the main process, call the MainDriver
function with the Electron app:
import Cycle from '@cycle/core';
import { app } from 'electron';
import { MainDriver } from 'cycle-electron-driver';
function main(sources) {
//...
}
Cycle.run(main, {
electron: MainDriver(app)
});
When constructing the main process driver, an optional second argument can provide the following options:
isSingleInstance
- If set totrue
, only one instance of the application can be created. TheextraLaunch$
source will emit when additional launches are attempted. This defaults tofalse
.
The source object provided by MainDriver
contains multiple properties and observables, most of which you will never
need to use. To summarize the overall structure, it looks something like this:
platformInfo:
isAeroGlassEnabled
events() :: String -> Observable
extraLaunch$
beforeAllWindowClose$
beforeExit$
exit$
badgeLabel$
The platformInfo
object provides the following information about the runtime platform:
isAeroGlassEnabled
- (Windows only) whether DWM composition is enabled
The events
source factory creates an Observable
for raw
electron app
events.
function main({ electron }) {
const readyEvent$ = electron.events('ready');
}
Note that events documented with more than one parameter will be truncated; only the Event
portion will be received.
It is recommended that you use one of the more normalized event sources listed below if you're handling an event.
When the isSingleInstance
option is true
, this observable indicates when blocked additional launches are attempted.
Values are objects with the following properties:
argv
- Array of command-line arguments used when this was launchedcwd
- The working directory of the process that was launched
This Observable
gives the current and future badge labels of the OS X dock icon.
The sink for the driver should be an observable that produces an object containing multiple sink observables. Any of these sinks can be omitted if not needed. The object properties can be summarized as follows:
pathUpdates:
appData$
desktop$
documents$
downloads$
exe$
home$
module$
music$
pictures$
temp$
userData$
videos$
newChromiumParam$AppTasksDriver
dock:
bounce:
start$
cancel$
visibility$
badgeLabel$
menu$
icon$
ntlmAllowedOverride$
appUserModelId$
Provide one of the following sinks to change the file path used by electron:
appData$
- The directory for application datadesktop$
- The directory for the user's desktop filesdocuments$
- The directory for the user's documentsdownloads$
- The directory for the user's downloaded filesexe$
- The path to the application executablehome$
- The user's home directorymodule$
- The path to thelibchromiumcontent
librarymusic$
- The directory for the user's music filespictures$
- The directory for the user's image filestemp$
- The directory for storing temporary datauserData$
- The directory for storing user-specific application datavideos$
- The directory for the user's video files
The newChromiumParam$
sink should produce objects with the following properties:
switches
- AnArray
of objects with a requiredswitch
and optionalvalue
property to be appended to the Chromium parametersargs
- AnArray
of strings that will be used for additional command-line arguments to Chromium
Note that these are write-only and cannot be undone. In other words, you cannot remove a switch or argument once it has been included.
The dock
property is a container for multiple OSX-specific sinks.
The bounce property of dock
has the following observable properties:
start$
- This should be anObservable
of objects with anid
andtype
property. Thetype
property should be a string equalling eithercritical
orinformational
.id
is an arbitrary string that should be unique and kept track of if you wish to cancel the bounce at a later time. Otherwise, it may be omitted.cancel$
- This should be anObservable
of string IDs; these IDs should correlate to theid
used in thestart$
observable objects.
This Observable
should contain boolean values; true
values will cause the dock icon to show, false
to hide.
This sink causes the OS X badge label to be updated.
This sink sets the menu in the OS X dock for the application. See the electron documentation for details on what these values should be.
This sink sets the icon in the OS X dock. Values should be
NativeImage objects.
This sink should be an Observable
of boolean values; when true, NTLM authentication is enabled for sites not
recognized as being part of the local intranet.
This causes the Windows
Application User Model ID to change
to the values of the Observable
.