diff --git a/build-scripts b/build-scripts deleted file mode 160000 index ececd00..0000000 --- a/build-scripts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ececd00d5fcbc78b83947db8fbab4a4b628ffd13 diff --git a/neutralino.config.json b/neutralino.config.json index e6b473c..f537c0c 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -9,7 +9,7 @@ "nativeAllowList": ["app.*"], "modes": { "window": { - "title": "myapp", + "title": "Pucoti", "width": 800, "height": 500, "minWidth": 400, @@ -18,7 +18,7 @@ } }, "cli": { - "binaryName": "myapp", + "binaryName": "pucoti", "resourcesPath": "/www/dist/", "extensionsPath": "/extensions/", "clientLibrary": "/www/public/neutralino.js", @@ -29,9 +29,9 @@ "mac": { "architecture": ["x64", "arm64", "universal"], "minimumOS": "10.13.0", - "appName": "myapp", - "appBundleName": "myapp", - "appIdentifier": "com.marketmix.ext.bun.demo", + "appName": "pucoti", + "appBundleName": "pucoti", + "appIdentifier": "com.pucoti.app", "appIcon": "/packaging/pucoti.icns" } } diff --git a/scripts/.gitattributes b/scripts/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/scripts/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/scripts/LICENSE b/scripts/LICENSE new file mode 100644 index 0000000..bb13d65 --- /dev/null +++ b/scripts/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 hschneider + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..9173a73 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,178 @@ +![](https://marketmix.com/git-assets/neutralino-build-scripts/neutralino-macos-appbundles.jpg) + +# neutralino-build-scripts + +**Neutralino Build-Automation for macOS, Linux and Windows App-Bundles**. + +This set of scripts replace the `neu build` command for macOS-, Linux and Windows-builds. Instead of plain binaries, it outputs ready-to-use app-bundles. + +> The macOS build-script solves the problem, that Neutralino only produces plain macOS binaries and not macOS AppBundles. These files cannot be signed and notarized. +> **build-mac.sh** generates valid AppBundles which pass Apple's notarization process successfully :- + +## Setup + +Copy all, **except neutralino.config.json** (which is just an example) to your project's root folder. The scripts are tested under macOS and should also run on Linux or Windows/WSL. + +Install **jq**, which is required for parsing JSON files: + +```bash +# On macOS: +brew install jq +# On Linux or Windows/WSL: +sudo apt-get install jq +``` + +If your are a Mac-user and never heard of Homebrew, visit https://brew.sh + +Add this to your neutralino.config.json: + +```json + "buildScript": { + "mac": { + "architecture": ["x64", "arm64", "universal"], + "minimumOS": "10.13.0", + "appName": "ExtBunDemo", + "appBundleName": "ExtBunDemo", + "appIdentifier": "com.marketmix.ext.bun.demo", + "appIcon": "icon.icns" + }, + "win": { + "architecture": ["x64"], + "appName": "ExtBunDemo", + "appIcon": "icon.ico" + }, + "linux": { + "architecture": ["x64", "arm64", "armhf"], + "appName": "ExtBunDemo", + "appIcon": "icon.png", + "appPath": "/usr/share/ExtBunDemo", + "appIconLocation": "/usr/share/ExtBunDemo/icon.png" + } + } +``` + +If you are unsure where to add, examine **the example neutralino.config.json**, included in this repo. + +## Build for macOS + +```bash +./build-mac.sh +``` + +This starts the following procedure: + +- Erase the target folder ./dist/APPNAME +- Run `neu build` +- Execute `preproc-mac.sh` +- Clone the app-bundle scaffold from `_app_scaffolds/mac` and adapt it to your app. +- Copy all resources and extensions to the app-bundle. +- Execute `postproc-mac.sh` + +All build targets are created in the ./dist folder. + +Because the macOS-platform consists of 3 binary architectures, you might want to add different resources after the app has been built. That's what `postproc-mac.sh` is for. Just add your custom code there and you are good to go. + +If you need to prepare platform-specific resource before bundling starts, you can add your custom code to `preproc-mac.sh`. + +Keep in mind that alle additional resources have to be copied to `${APP_RESOURCES}/`, which resolves to `MyApp.app/Contents/Resources`. If you place them elsewhere, your signature or notarization might break. + +The `buildScript/mac` JSON segment in the config-file contains the following fields: + +| Key | Description | +| ------------- | ------------------------------------------------------------ | +| architecture | This is an array of the architectures, you want to build. In our example we build all 3 architectures. | +| minimumOS | The minimum macOS version. | +| appName | The app-name as displayed in the Finder. | +| appBundleName | The macOS app-bundle name. | +| appIdentifier | The macOS app-identifier. | +| appIcon | Path to the app-icon in **.icns-format**. If only the filename is submitted, the file is expected in the project's root. | + +If you want to streamline your deployment process under macOS, you might also be interested in **[Sign and Notarize Automation](https://github.com/hschneider/macos-sign-notarize)** from commandline. + +## Build for Windows + +```bash +./build-win.sh +``` + +This starts the following procedure: + +- Erase the target folder ./dist/APPNAME +- Run `neu build` +- Execute `preproc-win.sh` +- Copy all resources and extensions to the app-bundle. +- Execute `postproc-win.sh` +- Create the `install-icon.cmd` helper script from its template in `_app_scaffolds/win/`, if an app icon file exists. + +The build is created in the ./dist folder. + +In contrast to macOS, the whole process is straight-forward. The app-bundle is just a plain folder with the binary, resources.neu, the extensions-folder and WebView2Loader.dll. The DLL can be deleted, if you deploy on WIndows 11 or newer. + +If you need to prepare platform-specific resource before bundling starts, you can add your custom code to `preproc-win.sh`. + +You can also put custom code into `postproc-win.sh` to perform any action after the bundle has been built. + +The `buildScript/win` JSON segment in the config-file contains the following fields: + +| Key | Description | +| ------------ | ------------------------------------------------------------ | +| architecture | This is an array of the architectures, you want to build. Because Neutralino currently only support 'x64', you should leave this untouched. | +| appName | The app-name as displayed in the File Explorer, with or without .exe-suffix. | +| appIcon | Path to the app-icon in **.ico-format**. If only the filename is submitted, the file is expected in the project's root. The icon is copied from this path into the app-bundle. To apply the icon to the executable file, you'll have to run **[Resource Hacker](https://www.angusj.com/resourcehacker/)** from a Windows machine. To do so, just double-click **install-icon.cmd** in the app-bundle. | + +The icon installer in action: + +![](https://marketmix.com//git-assets/neutralino-build-scripts/neutralino-icon-installer.gif) + +## Build for Linux + +```bash +./build-linux.sh +``` + +This starts the following procedure: + +- Erase the target folder ./dist/APPNAME +- Run `neu build` +- Execute `preproc-linux.sh` +- Copy all resources and extensions to the app-bundle. +- Clones the .desktop-file from `_app_scaffolds/linux` to the app-bundle and adapts its content. +- Execute `postproc-linux.sh` + +All build targets are created in the ./dist folder. + +Because the Linux-platform consists of 3 binary architectures, you might want to add different resources after the app has been built. That's what `postproc-linux.sh` is for. Just add your custom code there and you are good to go. + +If you need to prepare platform-specific resource before bundling starts, you can add your custom code to `preproc-linux.sh`. + +> The **APP_NAME.desktop**-file and the **app icon** have to be copied to their proper places, when you deploy your app. + +The following paths are proposed: + +| Resource | Path | +| ------------------ | ---------------------------------------- | +| Application Folder | /usr/share/APP_NAME | +| Application Icon | /usr/share/APP_NAME/icon.png | +| Desktop File | /usr/share/applications/APP_NAME.desktop | + +The `buildScript/win` JSON segment in the config-file contains the following fields: + +| Key | Description | +| ------------ | ------------------------------------------------------------ | +| architecture | This is an array of the architectures, you want to build. In our example we build all 3 architectures. | +| appName | The app-name as displayed in the File Explorer. | +| appPath | The application path without the executable name and without ending slash. | +| appIcon | Path to the app-icon in .**png- or svg-format**. If only the filename is submitted, the file is expected in the project's root. The icon is copied from this path into the app-bundle. | +| appIconPath | This is the icon's path **after** the has been installed on a Linux system. That path is written to the .desktop-file. | + +Calling `sudo ./install.sh` from your build folder automatically installs the app to the locations you defined. + +## More about Neutralino + +- [NeutralinoJS Home](https://neutralino.js.org) + +- [Neutralino related blog posts at marketmix.com](https://marketmix.com/de/tag/neutralinojs/) + + + + diff --git a/scripts/_VERSION b/scripts/_VERSION new file mode 100644 index 0000000..65087b4 --- /dev/null +++ b/scripts/_VERSION @@ -0,0 +1 @@ +1.1.4 diff --git a/scripts/_app_scaffolds/linux/install.sh b/scripts/_app_scaffolds/linux/install.sh new file mode 100644 index 0000000..a50f7b5 --- /dev/null +++ b/scripts/_app_scaffolds/linux/install.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +echo "Installing ..." +cd .. +mkdir {APP_PATH} +cp -r {APP_NAME} {APP_BASEPATH} + +cd {APP_NAME} +chmod +x {APP_EXEC} +cp {APP_ICON} {APP_ICON_PATH} +cp {APP_NAME}.desktop /usr/share/applications/{APP_NAME}.desktop + +read -p "Delete original files? (y/n): " answer +if [[ $answer == "y" ]]; then + echo "Deleting ..." + cd .. + rm -rf {APP_NAME} +fi + +echo "DONE." diff --git a/scripts/_app_scaffolds/linux/myapp.desktop b/scripts/_app_scaffolds/linux/myapp.desktop new file mode 100644 index 0000000..694e83e --- /dev/null +++ b/scripts/_app_scaffolds/linux/myapp.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Version=1.0 +Encoding=UTF-8 +Name={APP_NAME} +Icon={APP_ICON_PATH} +Exec={APP_EXEC} +Path={APP_PATH} +Terminal=false +Type=Application diff --git a/scripts/_app_scaffolds/mac/myapp.app/Contents/Info.plist b/scripts/_app_scaffolds/mac/myapp.app/Contents/Info.plist new file mode 100644 index 0000000..4095ef0 --- /dev/null +++ b/scripts/_app_scaffolds/mac/myapp.app/Contents/Info.plist @@ -0,0 +1,31 @@ + + + + + NSHighResolutionCapable + + CFBundleExecutable + bootstrap + CFBundleGetInfoString + {APP_NAME} + CFBundleIconFile + icon.icns + CFBundleIdentifier + {APP_ID} + CFBundleName + {APP_BUNDLE} + CFBundleShortVersionString + {APP_VERSION} + CFBundleGetInfoString + {APP_NAME} {APP_VERSION} + CFBundlePackageType + APPL + LSMinimumSystemVersion + {APP_MIN_OS} + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + + \ No newline at end of file diff --git a/scripts/_app_scaffolds/mac/myapp.app/Contents/MacOS/bootstrap b/scripts/_app_scaffolds/mac/myapp.app/Contents/MacOS/bootstrap new file mode 100755 index 0000000..ba25bc4 --- /dev/null +++ b/scripts/_app_scaffolds/mac/myapp.app/Contents/MacOS/bootstrap @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# Based on code by https://github.com/malipetek - hey you did a brilliant job! +MACOS="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +CONTENTS="$(dirname "$MACOS")" +exec "${MACOS}/main" --path="${CONTENTS}/Resources" --enable-extensions=true diff --git a/scripts/_app_scaffolds/mac/myapp.app/Contents/Resources/icon.icns b/scripts/_app_scaffolds/mac/myapp.app/Contents/Resources/icon.icns new file mode 100644 index 0000000..7897061 Binary files /dev/null and b/scripts/_app_scaffolds/mac/myapp.app/Contents/Resources/icon.icns differ diff --git a/scripts/_app_scaffolds/win/WebView2Loader.dll b/scripts/_app_scaffolds/win/WebView2Loader.dll new file mode 100644 index 0000000..6f3eed4 Binary files /dev/null and b/scripts/_app_scaffolds/win/WebView2Loader.dll differ diff --git a/scripts/_app_scaffolds/win/install-icon.cmd b/scripts/_app_scaffolds/win/install-icon.cmd new file mode 100644 index 0000000..a300cb3 --- /dev/null +++ b/scripts/_app_scaffolds/win/install-icon.cmd @@ -0,0 +1,13 @@ +@echo off +set TOOL="c:\Program Files (x86)\Resource Hacker\ResourceHacker.exe" +if exist %TOOL% ( + %TOOL% -open {APP_NAME} -save {APP_NAME} -action addskip -res {APP_ICON} -mask ICONGROUP,MAINICON, + del {APP_ICON} + del install-icon.cmd +) +else ( + echo "Please install 'Resource Hacker' first." + echo "Press any key ..." + pause + start "" "https://www.angusj.com/resourcehacker/" +) diff --git a/scripts/build-linux.sh b/scripts/build-linux.sh new file mode 100755 index 0000000..0b6adeb --- /dev/null +++ b/scripts/build-linux.sh @@ -0,0 +1,195 @@ +#!/bin/bash +# +# build-linux.sh +# +# Linux build script for NeutralinoJS +# +# Call: +# ./build-linux.sh +# +# Requirements: +# brew install jq +# +# (c)2023-2024 Harald Schneider - marketmix.com + +VERSION='1.0.8' + +OS=$(uname -s) + +echo +echo -e "\033[1mNeutralino BuildScript for Linux platform, version ${VERSION}\033[0m" + +CONF=./neutralino.config.json + +if [ ! -e "./${CONF}" ]; then + echo + echo -e "\033[31m\033[1mERROR: ${CONF} not found.\033[0m" + exit 1 +fi + +if ! jq -e '.buildScript | has("linux")' "${CONF}" > /dev/null; then + echo + echo -e "\033[31m\033[1mERROR: Missing buildScript JSON structure in ${CONF}\033[0m" + exit 1 +fi + +APP_ARCH_LIST=($(jq -r '.buildScript.linux.architecture[]' ${CONF})) +APP_VERSION=$(jq -r '.version' ${CONF}) +APP_BINARY=$(jq -r '.cli.binaryName' ${CONF}) +APP_NAME=$(jq -r '.buildScript.linux.appName' ${CONF}) +APP_ICON=$(jq -r '.buildScript.linux.appIcon' ${CONF}) +APP_ICON_PATH=$(jq -r '.buildScript.linux.appIconLocation' ${CONF}) + +if jq -e '.buildScript.linux.appPath' "${CONF}" &> /dev/null; then + APP_PATH=$(jq -r '.buildScript.linux.appPath' ${CONF}) +else + echo + echo -e "\033[31m\033[1mWARNING: Please set appPath in neutralino.config.json!\033[0m" + APP_PATH="/usr/share/${APP_NAME}" +fi + +APP_BASEPATH=$(echo ${APP_PATH} | awk -v replacement="" -v search="/${APP_NAME}" '{gsub(search, replacement)}1') + +if jq -e '.buildScript.linux.appIconPath' "${CONF}" &> /dev/null; then + APP_ICON_PATH=$(jq -r '.buildScript.linux.appIconPath' ${CONF}) +else + echo + echo -e "\033[31m\033[1mWARNING: Please set appIconPath in neutralino.config.json!\033[0m" + APP_ICON_PATH="/usr/share/${APP_NAME}" +fi + +APP_SRC=./_app_scaffolds/linux/myapp.desktop +INSTALL_SCRIPT=./_app_scaffolds/linux/install.sh + +if [ ! -e "./${APP_SRC}" ]; then + echo + echo -e "\033[31m\033[1mERROR: App scaffold not found: ${APP_SRC}\033[0m" + exit 1 +fi + +if [ ! -e "./${INSTALL_SCRIPT}" ]; then + echo + echo -e "\033[31m\033[1mERROR: App install script not found: ${INSTALL_SCRIPT}\033[0m" + exit 1 +fi + +if [ "$1" != "--test" ]; then + echo + echo -e "\033[1mBuilding Neutralino Apps ...\033[0m" + echo + rm -rf "./dist/${APP_BINARY}" + neu build + echo -e "\033[1mDone.\033[0m" +else + echo + echo "Skipped 'neu build' in test-mode ..." +fi + +for APP_ARCH in "${APP_ARCH_LIST[@]}"; do + + APP_DST=./dist/linux_${APP_ARCH}/${APP_NAME} + + if [ -e "./preproc-linux.sh" ]; then + echo " Running pre-processor ..." + . preproc-linux.sh + fi + + EXE=./dist/${APP_BINARY}/${APP_BINARY}-linux_${APP_ARCH} + RES=./dist/${APP_BINARY}/resources.neu + EXT=./dist/${APP_BINARY}/extensions + + APP_EXEC=${APP_PATH}/${APP_BINARY}-linux_${APP_ARCH} + chmod +x "${APP_DST}" + + echo + echo -e "\033[1mBuilding App Bundle (${APP_ARCH}):\033[0m" + echo + echo " App Name: ${APP_NAME}" + echo " App Executable: ${APP_EXEC}" + echo " Icon: ${APP_ICON}" + echo " Icon Install Path: ${APP_ICON_PATH}" + echo " App Path: ${APP_PATH}" + echo " Target Folder: ${APP_DST}" + echo + + if [ ! -e "./${EXE}" ]; then + echo -e "\033[31m\033[1m ERROR: File not found: ${EXE}\033[0m" + exit 1 + fi + + if [ ! -e "./${RES}" ]; then + echo -e "\033[31m\033[1m ERROR: Resource file not found: ${RES}\033[0m" + exit 1 + fi + + echo " Cloning scaffold ..." + mkdir -p "${APP_DST}" + cp "${APP_SRC}" "${APP_DST}/${APP_NAME}.desktop" + cp "${INSTALL_SCRIPT}" "${APP_DST}" + + echo " Copying content:" + echo " - Binary File" + cp "${EXE}" "${APP_DST}/" + echo " - Resources" + cp "${RES}" "${APP_DST}/" + + if [ -e "./${EXT}" ]; then + echo " - Extensions" + cp -r "${EXT}" "${APP_DST}/" + fi + + if [ -e "./${APP_ICON}" ]; then + echo " - Icon" + cp -r "${APP_ICON}" "${APP_DST}/" + fi + + echo " Processing Desktop File ..." + + if [ "$OS" == "Darwin" ]; then + sed -i '' "s/{APP_NAME}/${APP_NAME}/g" "${APP_DST}/${APP_NAME}.desktop" + sed -i '' "s|{APP_ICON_LOCATION}|${APP_ICON_PATH}|g" "${APP_DST}/${APP_NAME}.desktop" + sed -i '' "s|{APP_ICON_PATH}|${APP_ICON_PATH}|g" "${APP_DST}/${APP_NAME}.desktop" + sed -i '' "s|{APP_PATH}|${APP_PATH}|g" "${APP_DST}/${APP_NAME}.desktop" + sed -i '' "s|{APP_EXEC}|${APP_EXEC}|g" "${APP_DST}/${APP_NAME}.desktop" + + sed -i '' "s|{APP_NAME}|${APP_NAME}|g" "${APP_DST}/install.sh" + sed -i '' "s|{APP_PATH}|${APP_PATH}|g" "${APP_DST}/install.sh" + sed -i '' "s|{APP_BASEPATH}|${APP_BASEPATH}|g" "${APP_DST}/install.sh" + sed -i '' "s|{APP_EXEC}|${APP_EXEC}|g" "${APP_DST}/install.sh" + sed -i '' "s|{APP_ICON}|${APP_ICON}|g" "${APP_DST}/install.sh" + sed -i '' "s|{APP_ICON_PATH}|${APP_ICON_PATH}|g" "${APP_DST}/install.sh" + else + sed -i "s/{APP_NAME}/${APP_NAME}/g" "${APP_DST}/${APP_NAME}.desktop" + sed -i "s|{APP_ICON_LOCATION}|${APP_ICON_PATH}|g" "${APP_DST}/${APP_NAME}.desktop" + sed -i "s|{APP_ICON_PATH}|${APP_ICON_PATH}|g" "${APP_DST}/${APP_NAME}.desktop" + sed -i "s|{APP_PATH}|${APP_PATH}|g" "${APP_DST}/${APP_NAME}.desktop" + sed -i "s|{APP_EXEC}|${APP_EXEC}|g" "${APP_DST}/${APP_NAME}.desktop" + + sed -i "s|{APP_NAME}|${APP_NAME}|g" "${APP_DST}/install.sh" + sed -i "s|{APP_PATH}|${APP_PATH}|g" "${APP_DST}/install.sh" + sed -i "s|{APP_BASEPATH}|${APP_BASEPATH}|g" "${APP_DST}/install.sh" + sed -i "s|{APP_EXEC}|${APP_EXEC}|g" "${APP_DST}/install.sh" + sed -i "s|{APP_ICON}|${APP_ICON}|g" "${APP_DST}/install.sh" + sed -i "s|{APP_ICON_PATH}|${APP_ICON_PATH}|g" "${APP_DST}/install.sh" + fi + + if [ -e "./postproc-linux.sh" ]; then + echo " Running post-processor ..." + . postproc-linux.sh + fi + + echo + echo -e "\033[1mBuild finished.\033[0m" +done + +echo +echo -e "\033[1mI propose the following paths for your installer:\033[0m" +echo +echo " Application Folder: ${APP_PATH}" +echo " Application Icon: ${APP_ICON_PATH}" +echo " Desktop File: /usr/share/applications/${APP_NAME}.desktop" +echo +echo "You can call ./install.sh to start a quick installation on the target machine." + +echo +echo -e "\033[1mAll done.\033[0m" diff --git a/scripts/build-mac.sh b/scripts/build-mac.sh new file mode 100755 index 0000000..f273e8b --- /dev/null +++ b/scripts/build-mac.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# +# build-mac.sh +# +# macOS build script for NeutralinoJS +# +# Call: +# ./build-mac.sh +# +# Requirements: +# brew install jq +# +# (c)2023-2024 Harald Schneider - marketmix.com + +VERSION='1.0.7' + +OS=$(uname -s) + +echo +echo -e "\033[1mNeutralino BuildScript for macOS platform, version ${VERSION}\033[0m" + +CONF=./../neutralino.config.json + +if [ ! -e "./${CONF}" ]; then + echo + echo -e "\033[31m\033[1mERROR: ${CONF} not found.\033[0m" + exit 1 +fi + +if ! jq -e '.buildScript | has("mac")' "${CONF}" > /dev/null; then + echo + echo -e "\033[31m\033[1mERROR: Missing buildScript JSON structure in ${CONF}\033[0m" + exit 1 +fi + +APP_ARCH_LIST=($(jq -r '.buildScript.mac.architecture[]' ${CONF})) +APP_VERSION=$(jq -r '.version' ${CONF}) +APP_MIN_OS=$(jq -r '.buildScript.mac.minimumOS' ${CONF}) +APP_BINARY=$(jq -r '.cli.binaryName' ${CONF}) +APP_NAME=$(jq -r '.buildScript.mac.appName' ${CONF}) +APP_ID=$(jq -r '.buildScript.mac.appIdentifier' ${CONF}) +APP_BUNDLE=$(jq -r '.buildScript.mac.appBundleName' ${CONF}) +APP_ICON=$(jq -r '.buildScript.mac.appIcon' ${CONF}) + +APP_SRC=./_app_scaffolds/mac/myapp.app + +if [ ! -e "./${APP_SRC}" ]; then + echo + echo -e "\033[31m\033[1mERROR: App scaffold not found: ${APP_SRC}\033[0m" + exit 1 +fi + +if [ "$1" != "--test" ]; then + echo + echo -e "\033[1mBuilding Neutralino Apps ...\033[0m" + echo + rm -rf "./dist/${APP_BINARY}" + neu build + echo -e "\033[1mDone.\033[0m" +else + echo + echo "Skipped 'neu build' in test-mode ..." +fi + +for APP_ARCH in "${APP_ARCH_LIST[@]}"; do + + APP_DST=./dist/mac_${APP_ARCH}/${APP_NAME}.app + APP_MACOS=${APP_DST}/Contents/MacOS + APP_RESOURCES=${APP_DST}/Contents/Resources + + if [ -e "./preproc-mac.sh" ]; then + echo " Running pre-processor ..." + . preproc-mac.sh + fi + + EXE=./dist/${APP_BINARY}/${APP_BINARY}-mac_${APP_ARCH} + RES=./dist/${APP_BINARY}/resources.neu + EXT=./dist/${APP_BINARY}/extensions + + echo + echo -e "\033[1mBuilding App Bundle (${APP_ARCH}):\033[0m" + echo + echo " Minimum macOS: ${APP_MIN_OS}" + echo " App Name: ${APP_NAME}" + echo " Bundle Name: ${APP_BUNDLE}" + echo " Identifier: ${APP_ID}" + echo " Icon: ${APP_ICON}" + echo " Source Folder: ${APP_SRC}" + echo " Target Folder: ${APP_DST}" + echo + + if [ ! -e "./${EXE}" ]; then + echo -e "\033[31m\033[1m ERROR: File not found: ${EXE}\033[0m" + exit 1 + fi + + if [ ! -e "./${RES}" ]; then + echo -e "\033[31m\033[1m ERROR: Resource file not found: ${RES}\033[0m" + exit 1 + fi + + echo " Cloning scaffold ..." + mkdir -p "${APP_DST}" + cp -r ${APP_SRC}/* ${APP_DST}/ + + echo " Copying content:" + echo " - Binary File" + cp "${EXE}" "${APP_MACOS}/main" + chmod 755 "${APP_MACOS}/main" + echo " - Resources" + cp "${RES}" "${APP_RESOURCES}/" + + if [ -e "./${EXT}" ]; then + echo " - Extensions" + cp -r "${EXT}" "${APP_RESOURCES}/" + fi + + if [ -e "./${APP_ICON}" ]; then + echo " - Icon" + cp -r "${APP_ICON}" "${APP_RESOURCES}/" + fi + + echo " Processing Info.plist ..." + + if [ "$OS" == "Darwin" ]; then + sed -i '' "s/{APP_NAME}/${APP_NAME}/g" "${APP_DST}/Contents/Info.plist" + sed -i '' "s/{APP_BUNDLE}/${APP_BUNDLE}/g" "${APP_DST}/Contents/Info.plist" + sed -i '' "s/{APP_ID}/${APP_ID}/g" "${APP_DST}/Contents/Info.plist" + sed -i '' "s/{APP_VERSION}/${APP_VERSION}/g" "${APP_DST}/Contents/Info.plist" + sed -i '' "s/{APP_MIN_OS}/${APP_MIN_OS}/g" "${APP_DST}/Contents/Info.plist" + else + sed -i "s/{APP_NAME}/${APP_NAME}/g" "${APP_DST}/Contents/Info.plist" + sed -i "s/{APP_BUNDLE}/${APP_BUNDLE}/g" "${APP_DST}/Contents/Info.plist" + sed -i "s/{APP_ID}/${APP_ID}/g" "${APP_DST}/Contents/Info.plist" + sed -i "s/{APP_VERSION}/${APP_VERSION}/g" "${APP_DST}/Contents/Info.plist" + sed -i "s/{APP_MIN_OS}/${APP_MIN_OS}/g" "${APP_DST}/Contents/Info.plist" + fi + + if [ -e "./postproc-mac.sh" ]; then + echo " Running post-processor ..." + . postproc-mac.sh + fi + + if [ "$OS" == "Darwin" ]; then + echo " Clearing Extended Attributes ..." + find "${APP_DST}" -type f -exec xattr -c {} \; + fi + + echo + echo -e "\033[1mBuild finished, ready to sign and notarize.\033[0m" +done + +echo +echo -e "\033[1mAll done.\033[0m" diff --git a/scripts/build-win.sh b/scripts/build-win.sh new file mode 100755 index 0000000..d2de8c8 --- /dev/null +++ b/scripts/build-win.sh @@ -0,0 +1,140 @@ +#!/bin/bash +# +# build-win.sh +# +# Windows build script for NeutralinoJS +# +# Call: +# ./build-win.sh +# +# Requirements: +# brew install jq +# +# (c)2023-2024 Harald Schneider - marketmix.com + +VERSION='1.1.0' + +OS=$(uname -s) + +echo +echo -e "\033[1mNeutralino BuildScript for Windows platform, version ${VERSION}\033[0m" + +CONF=./neutralino.config.json + +if [ ! -e "./${CONF}" ]; then + echo + echo -e "\033[31m\033[1mERROR: ${CONF} not found.\033[0m" + exit 1 +fi + +if ! jq -e '.buildScript | has("win")' "${CONF}" > /dev/null; then + echo + echo -e "\033[31m\033[1mERROR: Missing buildScript JSON structure in ${CONF}\033[0m" + exit 1 +fi + +APP_ARCH_LIST=($(jq -r '.buildScript.win.architecture[]' ${CONF})) +APP_BINARY=$(jq -r '.cli.binaryName' ${CONF}) +APP_NAME=$(jq -r '.buildScript.win.appName' ${CONF}) +APP_ICON=$(jq -r '.buildScript.win.appIcon' ${CONF}) + +if [[ $APP_NAME != *".exe"* ]]; then + APP_NAME=${APP_NAME}.exe +fi + +APP_SRC=./_app_scaffolds/win + +if [ "$1" != "--test" ]; then + echo + echo -e "\033[1mBuilding Neutralino Apps ...\033[0m" + echo + rm -rf "./dist/${APP_BINARY}" + neu build + echo -e "\033[1mDone.\033[0m" +else + echo + echo "Skipped 'neu build' in test-mode ..." +fi + +for APP_ARCH in "${APP_ARCH_LIST[@]}"; do + + APP_DST=./dist/win_${APP_ARCH} + + if [ -e "./preproc-win.sh" ]; then + echo " Running pre-processor ..." + . preproc-win.sh + fi + + EXE=./dist/${APP_BINARY}/${APP_BINARY}-win_${APP_ARCH}.exe + RES=./dist/${APP_BINARY}/resources.neu + EXT=./dist/${APP_BINARY}/extensions + + echo + echo -e "\033[1mBuilding App Bundle (${APP_ARCH}):\033[0m" + echo + echo " App Name: ${APP_NAME}" + echo " Target Folder: ${APP_DST}" + echo + + if [ ! -e "./${EXE}" ]; then + echo -e "\033[31m\033[1m ERROR: Binary file not found: ${EXE}\033[0m" + exit 1 + fi + + if [ ! -e "./${RES}" ]; then + echo -e "\033[31m\033[1m ERROR: Resource file not found: ${RES}\033[0m" + exit 1 + fi + + echo " Creating target folder ..." + mkdir -p "${APP_DST}" + + if [ -e "./${APP_ICON}" ]; then + + echo " Cloning scaffold ..." + + set +f + cp ${APP_SRC}/* "${APP_DST}/" + set -f + + if [ "$OS" == "Darwin" ]; then + sed -i '' "s/{APP_NAME}/${APP_NAME}/g" "${APP_DST}/install-icon.cmd" + sed -i '' "s/{APP_ICON}/${APP_ICON}/g" "${APP_DST}/install-icon.cmd" + else + sed -i "s/{APP_NAME}/${APP_NAME}/g" "${APP_DST}/install-icon.cmd" + sed -i "s/{APP_ICON}/${APP_ICON}/g" "${APP_DST}/install-icon.cmd" + fi + fi + + echo " Copying content:" + echo " - Binary File" + cp "${EXE}" "${APP_DST}/${APP_NAME}" + echo " - Resources" + cp "${RES}" "${APP_DST}/" + + if [ -e "./${EXT}" ]; then + echo " - Extensions" + cp -r "${EXT}" "${APP_DST}/" + fi + + if [ -e "./${APP_ICON}" ]; then + echo " - Icon" + cp -r "${APP_ICON}" "${APP_DST}/" + fi + + if [ -e "./postproc-win.sh" ]; then + echo " Running post-processor ..." + . postproc-win.sh + fi + + echo + echo -e "\033[1mBuild finished.\033[0m" + + if [ -e "./${APP_ICON}" ]; then + echo + echo -e "\033[32m\033[1mDouble-click install-icon.cmd on a Windows machine to apply the app icon.\033[0m" + fi +done + +echo +echo -e "\033[1mAll done.\033[0m" diff --git a/scripts/icon.ico b/scripts/icon.ico new file mode 100644 index 0000000..a6a4bad Binary files /dev/null and b/scripts/icon.ico differ diff --git a/scripts/icon.png b/scripts/icon.png new file mode 100644 index 0000000..291d941 Binary files /dev/null and b/scripts/icon.png differ diff --git a/scripts/neutralino.config.json b/scripts/neutralino.config.json new file mode 100644 index 0000000..0c0acdc --- /dev/null +++ b/scripts/neutralino.config.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://raw.githubusercontent.com/neutralinojs/neutralinojs/main/schemas/neutralino.config.schema.json", + "applicationId": "js.neutralino.zero", + "version": "1.0.0", + "defaultMode": "window", + "port": 0, + "documentRoot": "/www/dist/", + "url": "/", + "enableServer": true, + "enableNativeAPI": true, + "enableExtensions": false, + "exportAuthInfo": true, + "tokenSecurity": "one-time", + "nativeAllowList": ["app.*"], + "logging": { + "enabled": false, + "writeToLogFile": false + }, + "globalVariables": {}, + "modes": { + "window": { + "title": "myapp", + "width": 800, + "height": 500, + "minWidth": 400, + "minHeight": 200, + "fullScreen": false, + "alwaysOnTop": false, + "icon": "/www/dist/favicon.ico", + "enableInspector": true, + "borderless": false, + "maximize": false, + "hidden": false, + "center": true, + "useSavedState": false, + "resizable": true, + "exitProcessOnClose": false + } + }, + "cli": { + "binaryName": "myapp", + "resourcesPath": "/www/dist/", + "extensionsPath": "/extensions/", + "clientLibrary": "/www/public/neutralino.js", + "binaryVersion": "6.1.0", + "clientVersion": "6.1.0" + }, + "buildScript": { + "mac": { + "architecture": ["x64", "arm64", "universal"], + "minimumOS": "10.13.0", + "appName": "myapp", + "appBundleName": "myapp", + "appIdentifier": "com.marketmix.ext.bun.demo", + "appIcon": "../packaging/pucoti.icns" + }, + "win": { + "architecture": ["x64"], + "appName": "myapp", + "appIcon": "icon.ico" + }, + "linux": { + "architecture": ["x64", "arm64", "armhf"], + "appName": "myapp", + "appIcon": "icon.png", + "appPath": "/usr/share/myapp", + "appIconPath": "/usr/share/myapp/icon.png" + } + } +} \ No newline at end of file diff --git a/scripts/postproc-linux.sh b/scripts/postproc-linux.sh new file mode 100755 index 0000000..4b4f3ea --- /dev/null +++ b/scripts/postproc-linux.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# postproc-linux.sh 1.0.1 +# +# Linux build script post-processor. +# +# This is called from build-win.sh after the app-bundle has been built. +# Use this e.g. to copy additional resources to the app-bundle. +# You can use all variables from the main script here. +# +# (c)2023 Harald Schneider - marketmix.com + +if [ $APP_ARCH = "x64" ]; then + : + # Handle Intel releases here + # cp SOME_FILE "${APP_DST}/" +fi + +if [ $APP_ARCH = "arm64" ]; then + : + # Handle ARM releases here + # cp SOME_FILE "${APP_DST}/" +fi + +if [ $APP_ARCH = "armhf" ]; then + : + # Handle ARM hard_float releases here. + # cp SOME_FILE "${APP_DST}/" +fi diff --git a/scripts/postproc-mac.sh b/scripts/postproc-mac.sh new file mode 100755 index 0000000..8dd450d --- /dev/null +++ b/scripts/postproc-mac.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# postproc-mac.sh 1.0.0 +# +# macOS build script post-processor. +# +# This is called from build-mac.sh after each app-bundle has been built. +# Use this e.g. to copy additional resources to the app-bundle. +# You can use all variables from the main script here. +# +# (c)2023 Harald Schneider - marketmix.com + +if [ $APP_ARCH = "x64" ]; then + : + # Handle Intel releases here + # cp SOME_FILE "${APP_RESOURCES}/" +fi + +if [ $APP_ARCH = "arm64" ]; then + : + # Handle Apple Silicon releases here + # cp SOME_FILE "${APP_RESOURCES}/" +fi + +if [ $APP_ARCH = "universal" ]; then + : + # Handle Universal releases here. + # cp SOME_FILE "${APP_RESOURCES}/" +fi diff --git a/scripts/postproc-win.sh b/scripts/postproc-win.sh new file mode 100755 index 0000000..afca5bf --- /dev/null +++ b/scripts/postproc-win.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# +# postproc-win.sh 1.0.1 +# +# Windows build script post-processor. +# +# This is called from build-win.sh after the app-bundle has been built. +# Use this e.g. to copy additional resources to the app-bundle. +# You can use all variables from the main script here. +# +# (c)2023 Harald Schneider - marketmix.com + +if [ $APP_ARCH = "x64" ]; then + : + # Handle Intel releases here + # cp SOME_FILE "${APP_DST}/" +fi diff --git a/scripts/preproc-linux.sh b/scripts/preproc-linux.sh new file mode 100755 index 0000000..8cff337 --- /dev/null +++ b/scripts/preproc-linux.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# preproc-linux.sh 1.0.1 +# +# Linux build script pre-processor. +# +# This is called from build-win.sh before the app-bundle has been built. +# Use this e.g. to preoare platform specific resources. +# +# (c)2024 Harald Schneider - marketmix.com + +if [ $APP_ARCH = "x64" ]; then + : + # Handle Intel releases here +fi + +if [ $APP_ARCH = "arm64" ]; then + : + # Handle ARM releases here +fi + +if [ $APP_ARCH = "armhf" ]; then + : + # Handle ARM hard_float releases here. +fi diff --git a/scripts/preproc-mac.sh b/scripts/preproc-mac.sh new file mode 100755 index 0000000..e2778b5 --- /dev/null +++ b/scripts/preproc-mac.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# preproc-mac.sh 1.0.0 +# +# macOS build script pre-processor. +# +# This is called from build-win.sh before the app-bundle has been built. +# Use this e.g. to preoare platform specific resources. +# +# (c)2024 Harald Schneider - marketmix.com + +if [ $APP_ARCH = "x64" ]; then + : + # Handle Intel releases here +fi + +if [ $APP_ARCH = "arm64" ]; then + : + # Handle Apple Silicon releases here +fi + +if [ $APP_ARCH = "universal" ]; then + : + # Handle Universal releases here. +fi diff --git a/scripts/preproc-win.sh b/scripts/preproc-win.sh new file mode 100755 index 0000000..97e1c27 --- /dev/null +++ b/scripts/preproc-win.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# +# preproc-win.sh 1.0.0 +# +# Windows build script pre-processor. +# +# This is called from build-win.sh before the app-bundle has been built. +# Use this e.g. to preoare platform specific resources. +# +# (c)2024 Harald Schneider - marketmix.com + +if [ $APP_ARCH = "x64" ]; then + : + # Handle Intel releases here +fi diff --git a/scripts/resources/js/neutralino.d.ts b/scripts/resources/js/neutralino.d.ts new file mode 100644 index 0000000..2414c04 --- /dev/null +++ b/scripts/resources/js/neutralino.d.ts @@ -0,0 +1,343 @@ +// Type definitions for Neutralino 5.0.1 +// Project: https://github.com/neutralinojs +// Definitions project: https://github.com/neutralinojs/neutralino.js + +declare namespace Neutralino { + +namespace filesystem { + interface DirectoryEntry { + entry: string; + path: string; + type: string; + } + interface FileReaderOptions { + pos: number; + size: number; + } + interface DirectoryReaderOptions { + recursive: boolean; + } + interface OpenedFile { + id: number; + eof: boolean; + pos: number; + lastRead: number; + } + interface Stats { + size: number; + isFile: boolean; + isDirectory: boolean; + createdAt: number; + modifiedAt: number; + } + interface Watcher { + id: number; + path: string; + } + function createDirectory(path: string): Promise; + function remove(path: string): Promise; + function writeFile(path: string, data: string): Promise; + function appendFile(path: string, data: string): Promise; + function writeBinaryFile(path: string, data: ArrayBuffer): Promise; + function appendBinaryFile(path: string, data: ArrayBuffer): Promise; + function readFile(path: string, options?: FileReaderOptions): Promise; + function readBinaryFile(path: string, options?: FileReaderOptions): Promise; + function openFile(path: string): Promise; + function createWatcher(path: string): Promise; + function removeWatcher(id: number): Promise; + function getWatchers(): Promise; + function updateOpenedFile(id: number, event: string, data?: any): Promise; + function getOpenedFileInfo(id: number): Promise; + function readDirectory(path: string, options?: DirectoryReaderOptions): Promise; + function copy(source: string, destination: string): Promise; + function move(source: string, destination: string): Promise; + function getStats(path: string): Promise; +} +namespace os { + interface ExecCommandOptions { + stdIn?: string; + background?: boolean; + cwd?: string; + } + interface ExecCommandResult { + pid: number; + stdOut: string; + stdErr: string; + exitCode: number; + } + interface SpawnedProcess { + id: number; + pid: number; + } + interface Envs { + [key: string]: string; + } + interface OpenDialogOptions { + multiSelections?: boolean; + filters?: Filter[]; + defaultPath?: string; + } + interface FolderDialogOptions { + defaultPath?: string; + } + interface SaveDialogOptions { + forceOverwrite?: boolean; + filters?: Filter[]; + defaultPath?: string; + } + interface Filter { + name: string; + extensions: string[]; + } + interface TrayOptions { + icon: string; + menuItems: TrayMenuItem[]; + } + interface TrayMenuItem { + id?: string; + text: string; + isDisabled?: boolean; + isChecked?: boolean; + } + enum Icon { + WARNING = "WARNING", + ERROR = "ERROR", + INFO = "INFO", + QUESTION = "QUESTION" + } + enum MessageBoxChoice { + OK = "OK", + OK_CANCEL = "OK_CANCEL", + YES_NO = "YES_NO", + YES_NO_CANCEL = "YES_NO_CANCEL", + RETRY_CANCEL = "RETRY_CANCEL", + ABORT_RETRY_IGNORE = "ABORT_RETRY_IGNORE" + } + type KnownPath = "config" | "data" | "cache" | "documents" | "pictures" | "music" | "video" | "downloads" | "savedGames1" | "savedGames2"; + function execCommand(command: string, options?: ExecCommandOptions): Promise; + function spawnProcess(command: string, cwd?: string): Promise; + function updateSpawnedProcess(id: number, event: string, data?: any): Promise; + function getSpawnedProcesses(): Promise; + function getEnv(key: string): Promise; + function getEnvs(): Promise; + function showOpenDialog(title?: string, options?: OpenDialogOptions): Promise; + function showFolderDialog(title?: string, options?: FolderDialogOptions): Promise; + function showSaveDialog(title?: string, options?: SaveDialogOptions): Promise; + function showNotification(title: string, content: string, icon?: Icon): Promise; + function showMessageBox(title: string, content: string, choice?: MessageBoxChoice, icon?: Icon): Promise; + function setTray(options: TrayOptions): Promise; + function open(url: string): Promise; + function getPath(name: KnownPath): Promise; +} +namespace computer { + interface MemoryInfo { + total: number; + available: number; + } + interface KernelInfo { + variant: string; + version: string; + } + interface OSInfo { + name: string; + description: string; + version: string; + } + interface CPUInfo { + vendor: string; + model: string; + frequency: number; + architecture: string; + logicalThreads: number; + physicalCores: number; + physicalUnits: number; + } + interface Display { + id: number; + resolution: Resolution; + dpi: number; + bpp: number; + refreshRate: number; + } + interface Resolution { + width: number; + height: number; + } + interface MousePosition { + x: number; + y: number; + } + function getMemoryInfo(): Promise; + function getArch(): Promise; + function getKernelInfo(): Promise; + function getOSInfo(): Promise; + function getCPUInfo(): Promise; + function getDisplays(): Promise; + function getMousePosition(): Promise; +} +namespace storage { + function setData(key: string, data: string): Promise; + function getData(key: string): Promise; + function getKeys(): Promise; +} +namespace debug { + enum LoggerType { + WARNING = "WARNING", + ERROR = "ERROR", + INFO = "INFO" + } + function log(message: string, type?: LoggerType): Promise; +} +namespace app { + interface OpenActionOptions { + url: string; + } + interface RestartOptions { + args: string; + } + function exit(code?: number): Promise; + function killProcess(): Promise; + function restartProcess(options?: RestartOptions): Promise; + function getConfig(): Promise; + function broadcast(event: string, data?: any): Promise; + function readProcessInput(readAll?: boolean): Promise; + function writeProcessOutput(data: string): Promise; + function writeProcessError(data: string): Promise; +} +namespace window { + interface WindowOptions extends WindowSizeOptions, WindowPosOptions { + title?: string; + icon?: string; + fullScreen?: boolean; + alwaysOnTop?: boolean; + enableInspector?: boolean; + borderless?: boolean; + maximize?: boolean; + hidden?: boolean; + maximizable?: boolean; + useSavedState?: boolean; + exitProcessOnClose?: boolean; + extendUserAgentWith?: string; + processArgs?: string; + } + interface WindowSizeOptions { + width?: number; + height?: number; + minWidth?: number; + minHeight?: number; + maxWidth?: number; + maxHeight?: number; + resizable?: boolean; + } + interface WindowPosOptions { + x: number; + y: number; + } + function setTitle(title: string): Promise; + function getTitle(): Promise; + function maximize(): Promise; + function unmaximize(): Promise; + function isMaximized(): Promise; + function minimize(): Promise; + function setFullScreen(): Promise; + function exitFullScreen(): Promise; + function isFullScreen(): Promise; + function show(): Promise; + function hide(): Promise; + function isVisible(): Promise; + function focus(): Promise; + function setIcon(icon: string): Promise; + function move(x: number, y: number): Promise; + function center(): Promise; + function setDraggableRegion(domElementOrId: string | HTMLElement): Promise; + function unsetDraggableRegion(domElementOrId: string | HTMLElement): Promise; + function setSize(options: WindowSizeOptions): Promise; + function getSize(): Promise; + function getPosition(): Promise; + function setAlwaysOnTop(onTop: boolean): Promise; + function create(url: string, options?: WindowOptions): Promise; +} +namespace events { + interface Response { + success: boolean; + message: string; + } + type Builtin = "ready" | "trayMenuItemClicked" | "windowClose" | "serverOffline" | "clientConnect" | "clientDisconnect" | "appClientConnect" | "appClientDisconnect" | "extClientConnect" | "extClientDisconnect" | "extensionReady" | "neuDev_reloadApp"; + function on(event: string, handler: (ev: CustomEvent) => void): Promise; + function off(event: string, handler: (ev: CustomEvent) => void): Promise; + function dispatch(event: string, data?: any): Promise; + function broadcast(event: string, data?: any): Promise; +} +namespace extensions { + interface ExtensionStats { + loaded: string[]; + connected: string[]; + } + function dispatch(extensionId: string, event: string, data?: any): Promise; + function broadcast(event: string, data?: any): Promise; + function getStats(): Promise; +} +namespace updater { + interface Manifest { + applicationId: string; + version: string; + resourcesURL: string; + } + function checkForUpdates(url: string): Promise; + function install(): Promise; +} +namespace clipboard { + function readText(key: string, data: string): Promise; + function writeText(data: string): Promise; +} +namespace custom { + function getMethods(): Promise; +} +interface InitOptions { + exportCustomMethods?: boolean; +} +function init(options?: InitOptions): void; +type ErrorCode = "NE_FS_DIRCRER" | "NE_FS_RMDIRER" | "NE_FS_FILRDER" | "NE_FS_FILWRER" | "NE_FS_FILRMER" | "NE_FS_NOPATHE" | "NE_FS_COPYFER" | "NE_FS_MOVEFER" | "NE_OS_INVMSGA" | "NE_OS_INVKNPT" | "NE_ST_INVSTKY" | "NE_ST_STKEYWE" | "NE_RT_INVTOKN" | "NE_RT_NATPRME" | "NE_RT_APIPRME" | "NE_RT_NATRTER" | "NE_RT_NATNTIM" | "NE_CL_NSEROFF" | "NE_EX_EXTNOTC" | "NE_UP_CUPDMER" | "NE_UP_CUPDERR" | "NE_UP_UPDNOUF" | "NE_UP_UPDINER"; +interface Error { + code: ErrorCode; + message: string; +} + +} + +// --- globals --- +/** Mode of the application: window, browser, cloud, or chrome */ +declare const NL_MODE: string; +/** Application port */ +declare const NL_PORT: number; +/** Command-line arguments */ +declare const NL_ARGS: string[]; +/** Basic authentication token */ +declare const NL_TOKEN: string; +/** Neutralinojs client version */ +declare const NL_CVERSION: string; +/** Application identifier */ +declare const NL_APPID: string; +/** Application version */ +declare const NL_APPVERSION: string; +/** Application path */ +declare const NL_PATH: string; +/** Returns true if extensions are enabled */ +declare const NL_EXTENABLED: boolean; +/** Operating system name: Linux, Windows, Darwin, FreeBSD, or Uknown */ +declare const NL_OS: string; +/** CPU architecture: x64, arm, itanium, ia32, or unknown */ +declare const NL_ARCH: string; +/** Neutralinojs server version */ +declare const NL_VERSION: string; +/** Current working directory */ +declare const NL_CWD: string; +/** Identifier of the current process */ +declare const NL_PID: string; +/** Source of application resources: bundle or directory */ +declare const NL_RESMODE: string; +/** Release commit of the client library */ +declare const NL_CCOMMIT: string; +/** An array of custom methods */ +declare const NL_CMETHODS: string[]; +