Add all code changes (features, deprecations, and enhancements) under the Unreleased
topic to track changes for
the next release. Once the changes are released,
rename Unreleased
topic with the new version tag. Finally, create a new Unreleased
topic for future changes.
Neutralinojs offers the extensions API to write custom backend code with any programming language, but extensions come with the following drawbacks that affect apps in several scenarios:
- Extensions use a shared WebSocket for communication, so using direct C++ references (i.e., the window handler) is impossible within extensions.
- The developer is responsible for packaging their extension binaries.
- A C++-based extension is not fast as native C++-based code due to the WebSockets-based IPC.
Alternatively, a developer can download the framework C++ code, modify it, and re-compile it. But, the developer may face issues while synching upstream code modifications. So, Neutralinojs offers a separate namespace, a function template, inbuilt helper functions (i.e., to get the window handler, validation, etc.), and a developer guide to add custom APIs to the Neutralinojs framework without updating the framework core.
Example:
let res = await Neutralino.custom.fetch('https://neutralino.js.org');
If developers make a custom API that others can use, we motivate them to contribute to the Neutralinojs framework by adding it to the main codebase.
Example:
let res = await Neutralino.net.fetch('https://neutralino.js.org');
If the developer adds a new custom method to the framework, the client library will automatically export it to the Neutralino.custom
namespace by using the NL_CMETHODS
internal global variable. The Neutralino.custom.getMethods
function returns an array of custom methods similar to NL_CMETHODS
.
The current Neutralinojs API offers non-stream-based (Promise-based but synchronous-like) functions for working with files. For example, the filesystem.readFile
function reads the file content and retrieves data synchronously even though the WebSocket communication mechanism supports asynchronous patterns. However, the synchronous API lets developers work with files in a simple way, but they face the following issues in some scenarios:
- Reading large files is not performance-friendly (The whole file content gets loaded into the memory).
- Unable to work with dynamic file objects (i.e., Device files).
- File descriptors are not persistent within the app lifecycle as they get destroyed after native API calls.
To solve this issue, we offer an event-based file stream API with the following functions/events:
filesystem.openFile
: Creates a file stream by openning a file.filesystem.updateOpenedFile
: Triggers a fileread
/readAll
event or sets the file cursor.filesystem.getOpenedFileInfo
: Returns (awaited) information about the file stream (Props:id
,eof
,pos
, andlastRead
)
openedFile
: Occurs per each file read event and whenever the file stream reachesEOF
.
os.getEnv
returns a value for a given environment variable key. Developers had to use alternative methods to retrieve a list of all environment variables with values. The os.getEnvs
returns all environment variables as a JavaScript object similar to Node's process.env
.
- Added
pos
andsize
options forreadFile
andreadBinaryFile
methods to set the file cursor position and buffer size respectively.
Added the storage.getKeys
function to get an array of Neutralinojs storage keys. Now, developers don't need to write their own functions to retrieve storage keys with the filesystem API.
Returns the current mouse cursor position via a JavaScript object that has x
and y
props. This function is helpful for develping interactive desktop widgets on all supported platforms.
- Replaced string error codes with enums in the C++ source code.
- Some refactorings done in C++ struct definitions and return values.
Ealier, we had the getMemoryInfo
function in the computer
namespace to retrieve system memory statistics. Now, we have added more functions to get details about the CPU, operating system, kernel, and connected displays:
computer.getArch
: Returns the CPU architecture. i.e,x64
,arm
, etc.computer.getKernelInfo
: Returns the operating system's kernel details.computer.getOSInfo
: Returns the operating system details.computer.getCPUInfo
: Returns the CPU details.computer.getDisplays
: Returns an array of all connected displays with the resolution, frequency-like information.
- Add the
defaultPath
option toshowSaveDialog
,showOpenDialog
, andshowFolderDialog
functions to set the initial path/filename of system dialogs.
- Run the test suite on Windows GitHub Actions instance.
- Fix the
armhf
framework binary generation issue in the GitHub Actions workflow.
- Hide the automation info bar from the Chrome mode by default -- Developers can add the
--enable-automation
flag to the config file if they need the particular command-line switch.
We have os.execCommand
for launching processes, but it's synchronous, meaning, the developer has to wait unti process completion to receive pid
, stdOut
and stdErr
. execCommand
is not suitable for long-running processes. The new spawning API offers API functions for handling long-running processes in a multi-threaded way.
os.spawnProcess(command)
: Spawns a process and returnsid
(A virtual Neutralino-scoped pid) andpid
(Operating system-level pid).os.getSpawnedProcesses()
: Returns a list of spawned processes.os.updateSpawnedProcess(id, action, data)
: Sends an action event for the spawned process. Supports the following actions:stdIn
: Sends a string via the standard input stream.data
is the input string.stdInEnd
: Closes the standard input stream.exit
: Terminates the spawned process.
spawnedProcess
: Dispatched when there is a change in the spawned process.CustomEvent
gets triggered with the following object:
{
id: <id>,
pid: <pid>,
action: <action>,
data: <data>
}
Available actions:
stdOut
: Outputs standard output data.data
contains the standard output payload.stdErr
: Outputs standard error data.data
contains the standard error payload.exit
: Notified when the process terminates.data
contains the process exit code.
- Add official Linux ARM (armhf and arm64) binary build support for the standard release workflow and nightly build.
- Expose
createdAt
andmodifiedAt
JavaScript timestamps via thefilesystem.getStats
function.
- Hide the
.storage
directory (Neutralinojs storage location) on Windows. - Support using query parameters in resources URLs. i.e.,
index.html?v=2.0
is supported, but caching is not yet implemented. - Show a user-friendly error message for Neutralinojs server initialization failures.
- Added
windowFocus
andwindowBlur
native events.
- Use BuildZri for C++ build automation.
- Implement a new workflow for nightly releases. Developers can get the nightly release binaries via the
nightly
version tag.
- Search and dynamically load app indicator libraries on Linux. This enhancement supports Neutralinojs to start without a crash when there is no app indicator library present on the system.
- Throw
NE_OS_TRAYIER
from theos.setTray
function for initialization failures. - Fix binary file write error on Windows with the
filesystem.writeBinaryFile
function. This was fixed by usingLF
as the line breaker on all platforms as a portable solution. If the developer needs CRLF on Windows (or CR on Darwin), the developer needs to handle it explicitly withNL_OS
.
- Add
NL_COMMIT
to hold framework's release commit. This is helpful to find the nightly release's code snapshot.
- Add
window.getPosition
to get the current window coordinates.
- Add
filesystem.appendFile
to append text content to a file. Thrown errors are similar to thefilesystem.writeFile
function. - Add
filesystem.appendBinaryFile
to append binary content to a file. Thrown errors are similar to thefilesystem.writeBinaryFile
function.
- Use
ayatana-appindicator3-0.1
instead ofappindicator3-0.1
(Marked as obsolete in Debian packages)
- Dynamically call
SetProcessDpiAwarenessContext
function to support previous Windows versions. - Display the native method name with the
NE_RT_NATPRME
error payload.
- Added
tokenSecurity
to the configuration to improve the security ofNL_TOKEN
. Accepted values arenone
andone-time
. Ifnone
is set, Neutralinojs server will always exposeNL_TOKEN
for any application instance, so you can open Neutralinojs apps from browser directly. Ifone-time
(recommended) is set, Neutralinojs server exposeNL_TOKEN
only once and client persists the token insessionStorage
, so all other clients that acces the app after the initial client will get an auth error message (Displayed to the user via HTML).
window.setAlwaysOnTop(bool)
was added.window.getSize
was added.
- Added
NL_EXTENABLED
which returnstrue
if extensions are enabled. It is used to check extensions status faster during initialization process.
- Fixed the file dialog order issue on Windows.
- Removed tray icon when the application exits.
- Add clipboard API for all platforms. Supports reading and writing text in the system clipboard.
- Accept chrome-related CLI args:
--chrome-width
,--chrome-height
, and--chrome-args
. - Accept
--neu-dev-extension
to enable devtools connections (For internal usages with CLI). - Accept custom HTTP headers via
serverHeaders
option.
- Added
NL_RESMODE
to get details about application resources source. Returnsbundle
if resources are loaded fromresources.neu
. Otherwise, returnsdirectory
.
- Fix chrome mode user data dir issue (Support paths with spaces).
- Fix browser mode's shutdown issue with neu CLI.
window.getTitle
returns the current native window title.
- Remove
NE_OS_ENVNOEX
fromos.getEnv
and return an empty string if environment variable is not defined.
- Now you can run Neutralinojs apps as Chrome apps via the
chrome
mode.
- Getting chrome mode config from
modes.chrome
. Addedheight
,width
, and args specially for the chrome mode.
- Renamed
shouldRunInBackground
option tobackground
. - Supports
stdIn
as an optional input. - Returns multiple values:
stdOut
,stdErr
,pid
, andexitCode
.
- Config file supports new
extensions
array globally or in a specific mode. - Neutralino spawns extension processes based on
extensions
array. - Neutralino doesn't send kill signals to extension processes. The extension developer needs to stop processes properly.
extension
setting has 4 fields:id
,command
,commandLinux
,commandDarwin
, andcommandWindows
.- The
command
's (platform-specific command's) value accepts${NL_PATH}
global variable. - Each extension process instance is called with three CLI args:
--nl-port={}
,--nl-extension-id={}
and--nl-token={}
- Enable/disable extensions with
enableExtensions
config.
- Supports setting document root (with
documentRoot
) via config. Now, it's possible to launch app without a subdirectory in the URL.
Now developers can use Neutralinojs as a part of their software with any programming language by spawning Neutralinojs as a child process.
Use exportAuthInfo
to write auth details to ${NL_PATH}/.tmp/auth_info.json
. Then the parent process can pickup access details there. Note that WebSocket communication needs to be initiated via extensions API/loader.
- Sends an event to all app clients. This method is for extension developers.
- Sends an event to all clients (apps and extensions). Useful for notifying important general events.
dispatch
: Sends an event to a specific extension.broadcast
: Sends an event to all connected extensions. Useful for sending shutdown signals.getStats
: Returns details about loaded extensions and connected extensions.
checkForUpdates
: Send a request to a seed URL (JSON) and fetch update details.install
: Install updates based on the currently downloaded manifest.
appClientConnect
andappClientDisconnect
: Occurs when a new app instance is launched and closed respectively.extClientConnect
andextClientDisconnect
: Occurs when a new extension is connected and disconnected respectively.extensionReady
can be used to implement immediate extension calls. This is implemented from the client-side withextensions.getStats
andextClientConnect
. This event gurantees that it will be triggered regardless of the extension's start time.
NE_EX_EXTNOTC
: Thrown byextensions.dispatch
if the target extension is not connected.NE_UP_CUPDMER
: Thrown byupdater.checkForUpdates
if the JSON update manifest is invalid or applicationId is not matching.NE_UP_CUPDERR
: Thrown byupdater.checkForUpdates
if the updater API cannot fetch the manifest.NE_UP_UPDNOUF
: Thrown byupdater.install
when the update manifest is not loaded.NE_UP_UPDINER
: Thrown byupdater.install
for update installation errors.
- Fix port 0 issue with modes. Earlier, if the developer sets port as 0 from a specific mode,
the
NL_PORT
also becomes 0. - Fix an issue with
writeToLogFile
config option. Earlier, the log file was created even this option is set tofalse
.
NL_APPVERSION
: Value of theversion
key in the config file.