Table of Contents
Launcher
The launcher UI is a webpage served from the files in the app/dist directory, which are installed alongside Bolt binaries. The "entry point" is index.html. This README documents everything that's provided by the application for the purposes of UI creation.
Query Params
The initial request to launcher.html may have any of the following query params:
platform: the platform this was built for. Currently, may only be "windows", "mac" or "linux". This param will always be present.credentials: a JSON-encoded string containing an array of objects, one for each account the user is signed in on. Contains access_token, id_token, refresh_token, expiry, login_provider, and sub (unique account ID). If this param is absent, the user has no credentials file.config: a JSON-encoded string containing the user config. Anything at all may be stored in the config object; when the object is sent in a/save-configrequest (described later in this readme), the same object will be present in this param next time Bolt opens. If this param is absent, the user has no config file.flathub: a boolean indicating whether this is a flathub build, useful for making error messages more helpful. Assume false if not present.plugins: a JSON-encoded string containing the contents of plugins.json. If this is present (even as an empty dict), then plugins are supported on the current system. If not, all plugin-related features should be hidden or disabled, as they will not work.rs3_linux_installed_hash: if RS3 is installed, this param will be present indicating the hash of the .deb from which it was installed. Used for update-checking by comparing the hash against the one found in the metafile of the official download repo.runelite_installed_id- if RuneLite is installed, this param will be present indicating the unique ID of the Github asset from which the JAR was downloaded. Used for update-checking.hdos_installed_version- if HDOS is installed, this param will be present indicating the valuelauncher.versionfrom the getdown config at the time when it was installed. Used for update-checking.
Request API
The following tasks are achieved by making web requests to https://bolt-internal/. All queries will respond with 200 if the request is successful, or otherwise 4xx or 5xx with a plain text error message. The requests are as follows:
/close: [deprecated] causes the process to exit./save-credentials: saves user credentials to a file, so they may be restored and passed via thecredentialsparam next time the program starts. This request must be a POST. Any POST data will be saved to the file as-is, overwriting the existing file if any. This request should be made immediately after the credentials object changes, since almost any change completely invalidates the old file contents./save-config: saves user configuration to a file, so it may be restored and passed via theconfigparam next time the program starts. This request must be a POST. Any POST data will be saved to the file as-is, overwriting the existing file if any. Unlike credentials, config changes are a fairly low priority and can be left until some time later, such as theonunloadevent./open-external-url: attempts to open a URL in the user's browser. This request must be a POST, with the POST data containing the URL to open. The URL must start withhttp://orhttps://./browse-data: attempts to open Bolt's data directory in the user's file explorer./jar-file-picker: shows the user a file-picker for .jar files. The response will contain an absolute file path in plain text, unless the user closed the dialog without choosing a file, in which case the response code will 204 and the response body should be ignored.- Note: this request can take a very long time to complete since it waits indefinitely for user input, so do not run it synchronously and do not specify a timeout.
/json-file-picker: shows the user a file-picker for .json files. Identical to the above, except for the file extension./launch-rs3-deb: launches RS3 from the linux .deb file. Should only be used on platforms which support x86_64 ELF binaries (i.e. linux). May have the following query params:jx_...: see "JX Variables" sectionhash: a hash of a newer version of the game client to install. If set, there must also be POST data containing the downloaded contents of the .deb file. The .deb will be extracted, saved and launched. If all of that is successful,rs3_linux_installed_hashwill be updated with the new hash.config_uri: a string to pass as the--configURIcommand-line argument. If absent, none will be passed.plugin_loader: a boolean indicating whether the game should be launched with the Bolt plugin loader. If built without the plugin library feature, this param will be silently ignored.
/launch-runelite-jar: launches RuneLite from a JAR file. May have the following query params:jx_...: see "JX Variables" sectionid: an ID of a newer game version of the JAR to install (seerunelite_installed_idabove for where this ID is obtained.) If set, there must also be POST data containing the downloaded contents of the JAR file. The JAR will be saved and launched. If successful,runelite_installed_idwill be updated with the new ID.jar_path: an absolute path to a JAR file, which should be obtained from/jar-file-picker. If this is set, the given JAR file will be launched, bypassing any installed version. Should not be passed at the same time asid.flatpak_rich_presence: boolean indicating whether to expose the game's rich presence to Flatpak Discord by symlinking discord-ipc-0. Will assume false if not present. Doesn't do anything on platforms other than linux.
/launch-hdos-jar: launches HDOS from a JAR file. May have the following query params:jx_...: see "JX Variables" sectionversion: a version of a newer launcher version to install (seehdos_installed_versionabove for where this number is obtained.) If set, there must also be POST data containing the downloaded contents of the JAR file. The JAR will be saved and launched. If successful,hdos_installed_versionwill be updated with the new version.
If plugins are supported on the current system, these additional requests will be available. If not, these will respond with 400.
/list-game-clients: responds with a JSON-encoded list of the game clients currently connected via the plugin library./save-plugin-config: same assave-configexcept writing to plugins.json/read-json-file: responds with the contents of the given JSON file, or 404 if it doesn't existpath: absolute path to the file, generally the one returned from json-file-picker
JX Variables
The following variables are used to pass authentication info to a game when launching it. They're the same across all games and clients.
jx_session_id: Session ID obtained from OAuth token exchange; stored assession_idin credentials objectjx_character_id: The ID of the unique game character the user wants to log intojx_display_name: the display name of the account being logged into - optional, as new accounts will not have a display name yet
App
Developing
Svelte
This app is developed using Svelte.
They recommend using SvelteKit over base Svelte, but for this project, it made sense to keep things simple.
Svelte uses Vite under the hood, which is a fantastic build and testing tool.
This app also uses TypeScript over JavaScript. There are plenty of reasons for this, check out their site for more information!
This was mentioned in the other README, but in case you missed it:
Instead of npm and a package-lock.json, the frontend uses bun with a bun.lockb. Checkout Bun to see why!
Bun can be easily installed using npm:
npm install -g bun
Begin by running bun install, this will install all necessary dependencies for development and release.
Take a look inside the package.json file, this will show you all the different packages being used as well as the commands you can run using bun run [COMMAND].
Because we are developing inside of CEF, here are some recommendation when doing development:
- Use
-D BOLT_HTML_DIR=/app/dist,-D BOLT_DEV_SHOW_DEVTOOLS=1, and-D BOLT_DEV_LAUNCHER_DIRECTORY=1when initialising cmake. This will allow us to debug and take advantage of hot reloading when we make changes in our files. - Use
bun run watch. This is a wrapper forvite build --watch. The reason we prefer this overbun run devis because CEF wants plain html, js, and css files. Perhaps there is a way to get the dev server working with CEF, but building after every change is fast enough (100ms or less).
General folder structure:
app/contains config files and the entry point,index.html.app/srchas all the .svelte and .ts files that are relevant for the app.app/src/libis where the components of the app live.app/src/assetscurrently only has the .css files
app/publicis for assets that the app may want to access, like images, svgs, etc.app/distwill be generated when doing a build, these are the .html,.js, and .css files for production.
tailwindcss
Styling for the app is done with tailwindcss.
- Installation
- Running
bun installwithin this directory will install it as a dev dependency. - It can be used with
bunx. - Or as a standalone executable. Get the binary for your OS here
- Running
- Usage
- Be sure to run tailwind in the same directory as the 'tailwind.config.js'.
- To use while developing, you will likely want to watch for css changes, here is an example:
bunx tailwindcss -i src/assets/input.css -o src/assets/output.css --watch
- Optimising for production
- To minify the 'output.css', use this:
bunx tailwindcss -o src/assets/output.css --minify
- To minify the 'output.css', use this:
Linting & Formatting
Keeping consistent styling is important, please run both the linter and formatter before submitting any changes to see potential problems.
Check in the package.json to see how to run the relevant linters and formatters.
The linter being used is TSLint. The formatter is Prettier.
Rules can be changed in their relevant .rc files.
When running bun run lint, you may notice an output about running prettier, go ahead and run bun run format so prettier can format the files.
Then, run lint again. Another thing to note is that you may get some errors regarding the use of type any.
We want to avoid using type any at all cost, but sometimes giving a type to very arbitrary values is tough and tedious, use it as a last resort.
Building
Be sure to have everything installed: bun install.
Then, bun run build to have Vite build and output files into the dist directory.
Those files will be the ones used in release.
Minifying
When doing a release build, it is useful to optimise the code further, whether it be for speed or size.
'Minify' means to make the files as small as possible. Let's see how we can minify the output.
First, let's minify the css:
bunx tailwindcss -o src/assets/output.css --minify
Then, the html and js:
bun run minify - Check the package.json to see what that does.
You could run just the second step. But maybe tailwind makes different decisions or optimisation on minifying its css.
We can see the result is incredibly small files:
dist/index.html 0.60 kB │ gzip: 0.37 kB
dist/assets/index-CiR6En4v.css 12.07 kB │ gzip: 3.05 kB
dist/assets/index-DnwvALoA.js 49.59 kB │ gzip: 16.28 kB
✓ built in 456ms