# CrabNebula Products Full Documentation
> CrabNebula is built on the vision of enabling individuals, entrepreneurs and businesses to sustainably build, develop and distribute their apps to the universe.
# Cloud
# CrabNebula Cloud
**CrabNebula Cloud is a way to distribute apps across multiple platforms and architectures all from one unified platform.** Using the power of our Rust-powered CLI, you can automate uploading and releasing your app from your CI pipeline of choice or directly from your computer.
## Getting Started
CrabNebula Cloud is comprised up of two components:
- **[Cloud Platform](https://crabnebula.cloud/)**: Manage all of your organizations, apps, and releases from a centralized web app.
- **[Command Line Interface (CLI)](/cloud/cli/install)**: A tool to automate uploading and releasing your app binary. [**Download it from our CDN**](https://crabnebula.cloud/crabnebula/cn-cli/releases).
:::tip
The CLI offers a quick way to create your first organization and set up your Tauri application with support to auto-updates via CrabNebula Cloud.
See the [bootstrap](/cloud/cli/bootstrap) documentation for more information.
:::
To begin using CrabNebula Cloud go to http://crabnebula.cloud/. There you can use your GitHub or GitLab account to sign up for the platform.
The next step will be to create an organization.
## Set up an Organization
Application, billing, members, and organization-specific settings are managed at the organization level. Organizations allow a user to collaborate in multiple organizations and for apps to be shared with multiple users.
When you first create an account you will be asked to create a new organization with the following information:
- **Organization's name**: The public name of the organization apps belong to
- **Organization's slug**: A unique identifier for the organization
:::note
At this time you cannot delete or modify an organization's name.
:::
Once you have created the organization, you can start using CrabNebula Cloud right away. The platform is free for everyone — there is no trial period, no subscription, and no payment details required. See the [Billing & Usage](/cloud/org-management/billing) page for usage guidelines.
Afterwards you will be able invite other users to join the organization. For more information on how to do this, see [Invite a Member](/cloud/org-management/invite-member).
## Create an Application
An application represents a single app distributed to users. A single application can support multiple platforms and architectures.
- **Name**: A human-readable name for the application. This is shown on the application's market page.
- **Slug**: An identifier for your application.
- **Visibility**: If an application is "Public" then a market page is created where end users are able to download the application.
- **Description** (optional): A description that is shown on the application's market page.
- **Application Type**: Allows you to specify the type of application you are creating.
- **Tauri (v1)**: A [first generation Tauri](https://v1.tauri.app/) app.
- **Tauri (v2)**: A [second generation Tauri](https://tauri.app/) app.
- **Packager**: An app that is packaged with [cargo-packager](/packager).
- **Other**: Any generic app/asset.
:::tip[Looking for Multiple Environments?]
If you would like different environments or distribution channels for your application (such as separate beta and release channels), you can use the `--channel` argument when [drafting a release](/cloud/cli/create-draft) or a separate application to represent each of those environments.
:::
After creating an application, you will be able to manage the application from the dedicated [Application Overview page](/cloud/org-management/application-pages#application-overview-page).
## Create a Release
Creating a release is done with the [CrabNebula Cloud CLI](/cloud/cli/install). After building an app locally or in a CI environment, follow these steps to create, upload, publish and finally fetch said release of the app:
:::warn[API Key Required]
You will need to [create an API key](/cloud/org-management/create-api-key) before moving to the release management process.
:::
1. [Create a Release Draft](/cloud/cli/create-draft)
2. [Upload Assets](/cloud/cli/upload-assets)
3. [Publish a Release](/cloud/cli/publish-release)
4. [Fetch Latest Release](/cloud/cli/fetch-latest-release)
The whole release process can be automated in your CI pipeline. For more information on how to do this, have a look at the [Continuous Integration](/cloud/ci/overview) page which features sample GitHub Action workflows.
# Packager
On this page you will find an overview of how to configure [**Packager**](/packager) auto-updater with **CrabNebula Cloud**. This will allow you to automatically update your application as soon as you publish a new release on Cloud without having to manually handle the update process.
:::tip
A more in depth explanation for Packager can be found in this [guide](/cloud/guides/packager-auto-updater/).
Detailed documentation for the updater can be found in the [docs](/packager/updater/) and the [GitHub repository](https://github.com/crabnebula-dev/cargo-packager/tree/main/crates/updater).
:::
Packager includes a built-in updater which can be configured to automatically update your application as soon as you publish a new release on Cloud.
Start off by adding the `cargo-packager-updater` dependency to your project:
```bash
cargo add cargo-packager-updater
```
Afterwards you need to generate a cryptographic key pair which will be used to verify the integrity of the update. New updates will be signed with the private key and the public key will be used to confirm the integrity of the update.
```bash
cargo packager signer generate
```
Save the private key in a secure location as it will be used to sign the new release when you publish it. For the configuration of the updater code you will only need the public key.
In your Rust project navigate to the specific file where you want to add the updater code and add the following imports:
```rust
use cargo_packager_updater::{semver::Version, url::Url};
```
Now add the following code:
```rust
let config = cargo_packager_updater::Config {
endpoints: vec![Url::parse("https://cdn.crabnebula.app/update/YOUR_ORG_SLUG/YOUR_APP_SLUG/{{target}}-{{arch}}/{{current_version}}").expect("Failed to parse URL")], // REPLACE: YOUR_ORG_SLUG and YOUR_APP_SLUG of the app in CN Cloud
pubkey: String::from("YOUR_PUBLIC_KEY"), // REPLACE: YOUR_PUBLIC_KEY generated by the signer
..Default::default()
};
let current_version =
Version::parse(env!("CARGO_PKG_VERSION")).expect("Failed to parse version");
println!("Current version: {}", current_version);
if let Some(update) = cargo_packager_updater::check_update(current_version.clone(), config)
.expect("Failed to check for update")
{
update
.download_and_install()
.expect("Failed to download and install update");
println!("Update installed")
} else {
println!("No update available")
}
```
Make sure to replace `YOUR_ORG_SLUG` and `YOUR_APP_SLUG` with the slug of your organization and app on Cloud. Also replace `YOUR_PUBLIC_KEY` with the public key generated by the signer.
Now as soon as that code is run, the updater will check for updates and if a new update is available, it will be downloaded and installed automatically.
# Tauri
import { Tabs, TabItem } from "@astrojs/starlight/components";
On this page you will find an overview of how to configure Tauri (v1 and v2) auto-updater with **CrabNebula Cloud**. This will allow you to automatically update your application as soon as you publish a new release on Cloud without having to manually handle the update process.
:::tip
A more in depth explanation for Tauri v2 can be found in this [guide](/cloud/guides/auto-updates-tauri/).
For more details on how to configure Tauri updater, please refer to the Tauri documentation for [Tauri v1](https://v1.tauri.app/v1/guides/distribution/updater/) and [Tauri v2](https://tauri.app/plugin/updater/) respectively.
:::
Before you can adjust your `tauri.conf.json` file to configure the update endpoint, you need to generate a cryptographic key pair for your application which will be used to check if the update is valid or might have been tampered with.
The public key will be used to verify the update (needs to be put in the `tauri.conf.json` file) and the private key (has to be kept secret!) will be used to sign the new release when you publish it.
Run the following command to generate a key pair for your application:
```bash
cargo tauri signer generate -w ~/.tauri/myapp.key
```
```bash
cargo tauri signer generate -w $HOME/.tauri/myapp.key
```
You should now see the two keyfiles `~/.tauri/myapp.key` and `~/.tauri/myapp.key.pub`.
Now you need to add the following configuration to your `tauri.conf.json` file:
```json
"tauri": {
"updater": {
"active": true,
"endpoints": [
"https://cdn.crabnebula.app/update/ORG_NAME/APP_NAME/{{target}}-{{arch}}/{{current_version}}"
],
"dialog": true,
"pubkey": "PUBKEY"
},
},
```
Before you can configure the update endpoint, you need to install the `updater` plugin:
```bash
cargo tauri add updater
```
Now you need to add the following configuration to your `tauri.conf.json` file:
```json
"bundle": {
"createUpdaterArtifacts": true
},
"plugins": {
"updater": {
"endpoints": [
"https://cdn.crabnebula.app/update/ORG_NAME/APP_NAME/{{target}}-{{arch}}/{{current_version}}"
],
"pubkey": "PUBKEY"
}
}
```
:::caution
Note that the `createUpdaterArtifacts` value must be set to `true` for new applications,
but set to `"v1Compatible"` when updating from a Tauri v1 application.
:::
Make sure to replace `ORG_NAME` with your organizations name on Cloud, `APP_NAME` with the apps name on Cloud and `PUBKEY` with the public key from `~/.tauri/myapp.key.pub`.
:::caution
It is important to sign the app with the private key from `~/.tauri/myapp.key` before you publish a new release as otherwise the update will not be valid.
:::
# Changelogs for Cloud
import logs from '@components/Changelog.astro';
export const components = {blockquote: logs}
>
# Generic Assets
import { Tabs, TabItem } from "@astrojs/starlight/components";
This workflow is not tailored to any specific framework or bundler. It's a generic workflow that can be used to release any type of asset, such as executables, installers, or app bundles.
If your app is written with [Tauri v2](/cloud/ci/tauri-v2-workflow), [v1](/cloud/ci/tauri-v1-workflow), or [Packager](/cloud/ci/packager-workflow).
## Versioning
Make sure to adjust the version number before reaching this workflow during your CI process. This step can read a `config.json` file and extract the version number from it.
```yaml
- name: Get version from config.json
id: get_version
run: |
VERSION=$(jq -r '.version' config.json)
NOTES=$(jq -r '.notes' config.json)
echo "NOTES=$NOTES" >> $GITHUB_ENV
echo "VERSION=$VERSION" >> $GITHUB_ENV
```
```json
{
"notes": "release notes",
"version": "0.0.0"
}
```
## Workflow Triggers
For testing and developing purposes it may be useful to set a `workflow_dispatch` trigger, so the workflow can be initiated from the GitHub UI.
```yaml
run-name: triggered by ${{ github.actor }}.
on: workflow_dispatch
```
Once testing is done, it's recommended to use Continuous Deployment.
```yaml
on:
push:
branches:
- main
```
## Draft Release
The release draft command will create a new entry in your CrabNebula project, but it won't upload any assets just yet. It uses the **crabnebula-dev/cloud-release** action, which requires [`CN_API_KEY`](/cloud/org-management/create-api-key) to be defined within your GitHub Action scope.
```yaml
- name: draft release
uses: crabnebula-dev/cloud-release@v0
id: draft
with:
command: release draft ${{ env.CN_APPLICATION }} ${{ env.VERSION }} --notes ${{ env.NOTES }}
api-key: ${{ secrets.CN_API_KEY }}
```
### Upload Assets to Cloud
Once your app is built (you must write this step according yo your own framework and targets), we push all assets to the **Cloud** project. At this point, you will be able to see the binaries showing up in your dashboard. But the release is not published yet!
```yaml
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload --file ${{ env.CN_ASSET_PATH }} ${{ env.CN_APPLICATION }} ${{ env.VERSION }}
api-key: ${{ secrets.CN_API_KEY }}
```
## Publishing
At this point, the heavy lifting has been done and it's time ot publish the release. If you don't want to autopublish, you can do it manually from the **Cloud** dashboard.
```yaml
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} ${{ env.VERSION }}
api-key: ${{ secrets.CN_API_KEY }}
```
## Full Workflow
```yaml
name: Generic Workflow Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: YOUR_ORG_NAME/YOUR_APP_NAME
CN_ASSET_PATH: YOUR-ASSET-PATH
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: draft release
uses: crabnebula-dev/cloud-release@v0
id: draft
with:
command: release draft ${{ env.CN_APPLICATION }} ${{ env.VERSION }} --notes ${{ env.NOTES }}
api-key: ${{ secrets.CN_API_KEY }}
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload --file ${{ env.CN_ASSET_PATH }} ${{ env.CN_APPLICATION }} ${{ env.VERSION }}
api-key: ${{ secrets.CN_API_KEY }}
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} ${{ env.VERSION }}
api-key: ${{ secrets.CN_API_KEY }}
```
# Overview
Creating a draft, uploading assets, and publishing a release can all also be automated via [GitHub Actions](https://docs.github.com/en/actions). In order to improve developer experience we have a [cloud-release](https://github.com/crabnebula-dev/cloud-release) action which forms a wrapper around the [CrabNebula CLI](/cloud/cli/install).
With its two required arguments, **cloud-release** will create a [draft release](/cloud/cli/create-draft) in your organization account, [upload all assets](/cloud/cli/upload-assets), and [publish](/cloud/cli/publish-release) when everything is done. Two optional arguments are also available.
| key | description | required |
| ------------------- | -------------------------------------------------------------------------------------------- | ------------------ |
| `api-key` | The [CrabNebula Cloud API key](/cloud/org-management/create-api-key) to use. | Yes |
| `command` | The [CrabNebula Cloud CLI](/cloud/cli/install) command to run. (without the `cn` namespace). | Yes |
| `path` | Directory the CLI is downloaded into; must be a valid path (Unix syntax). | No (default: `.`) |
| `working-directory` | Working directory to use when running the CLI. | No (default: `.`) |
## Workflows
**CrabNebula Cloud** supports every existing framework through its 5 workflow types. Check the table below to find which one is best suited for your project.
| Workflow Type | Description |
| --------------------------------------------------- | ---------------------------------------------------------------------- |
| [Tauri v1](/cloud/ci/tauri-v1-workflow) | [Tauri v1](https://tauri.app) applications. |
| [Tauri v2](/cloud/ci/tauri-v2-workflow) | [Tauri v2](https://v2.tauri.app) applications. |
| [Packager](/cloud/ci/packager-workflow) | Apps using [packager](/packager) to create their binaries. |
| [Taurify](/cloud/ci/taurify-workflow) | [Taurify](/taurify) applications. |
| [Generic Assets](/cloud/ci/generic-assets-workflow) | Build agnostic workflow that will handle release and upload of assets. |
# Packager
The following workflow is specifically tailored to [Packager](/packager) applications.
## Versionining
The release version number can be defined in 3 different file names, the order of priority within which **Packager** checks them is as follows:
1. `Packager.toml`.
2. `packager.json`.
3. `Cargo.toml`.
In order for any of these files to work, they must be at the root of your project.
## Workflow Triggers
For testing and developing purposes it may be useful to set a `workflow_dispatch` trigger, so the workflow can be initiated from the GitHub UI.
```yaml
run-name: triggered by ${{ github.actor }}.
on: workflow_dispatch
```
Once testing is done, it's recommended to use Continuous Deployment.
```yaml
on:
push:
branches:
- main
```
## Action Environment
The runtime where **Packager** will run depends on the app or framework you want to target and the platform you want to build for. We recommend using `ubuntu-latest` whenever possible, but check the table below for specific use-cases:
| Framework | Image |
| --------- | -------------- |
| Tauri v1 | 'ubuntu-20.04' |
| Tauri v2 | 'ubuntu-22.04' |
:::note[Windows and macOS]
For Windows and macOS, you can always opt for "latest".
:::
Once defined, we establish variables so the images can be used consistently across the entire workflow. Additionally we store our CrabNebula Cloud application name to be used in the CLI commands.
```yaml
env:
CN_APPLICATION: YOUR_ORG_NAME/YOUR_APP_NAME
```
:::tip[Your App Name]
Remember to replace `YOUR_ORG_NAME/YOUR_APP_NAME` for your org and app's slugs.
For example `crabnebula/devtools-desktop`.
:::
Finally, when deploying to multiple platforms, it's useful to make builds concurrent. Also, cancelling ongoing processes when a new workflow starts.
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
```
## Jobs
The following section snippets must be added in the `jobs` map.
```yaml
jobs:
:
```
Note that the indentation is important.
### Draft Release
The release draft command will create a new entry in your CrabNebula project, but it won't upload any assets just yet. It uses the **crabnebula-dev/cloud-release** action, which requires [`CN_API_KEY`](/cloud/org-management/create-api-key) to be defined within your GitHub Action scope.
```yaml
draft:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework packager
api-key: ${{ secrets.CN_API_KEY }}
```
### Build Your App
The build step is for setting up the container image in which our task will run for each platform, and finally run **Packager** to create your binaries.
Establish the dependencies and the matrix of platforms we want to run concurrently. Add Rust toolchain and create a cache for it.
```yaml
build:
needs: draft
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install cargo packager
run: |
cargo install cargo-packager --locked
- name: build packager app
run: |
cargo packager --release
- name: Move assets to workdir
run: |
mv target/release/* .
```
#### Upload Assets to Cloud
At the last step of our **build**, we push all assets to the **Cloud** project. At this point, you will be able to see the binaries showing up in your dashboard. But the release is not published yet!
```yaml
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework packager
api-key: ${{ secrets.CN_API_KEY }}
```
### Publishing
At this point, the heavy lifting has been done and it's time ot publish the release. If you don't want to autopublish, you can do it manually from the **Cloud** dashboard.
```yaml
publish:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework packager
api-key: ${{ secrets.CN_API_KEY }}
```
## Full Workflow
```yaml
name: Packager Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: YOUR_ORG_NAME/YOUR_APP_NAME
jobs:
draft:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework packager
api-key: ${{ secrets.CN_API_KEY }}
build:
needs: draft
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install cargo packager
run: |
cargo install cargo-packager --locked
- name: build packager app
run: |
cargo packager --release
- name: Move assets to workdir
run: |
mv target/release/* .
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework packager
api-key: ${{ secrets.CN_API_KEY }}
publish:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework packager
api-key: ${{ secrets.CN_API_KEY }}
```
# Tauri v1
import { Tabs, TabItem } from "@astrojs/starlight/components";
This workflow is specifically tailored to [Tauri v1](https://tauri.app) applications. It can be easily adapted to work with any Tauri app and only requires the your project's slug within your CrabNebula organization as an input. Instead of just uploading assets (like in the previous workflow), the `build` job builds the Tauri app automatically for Linux, MacOS, and Windows. and uploads the assets directly afterwards.
:::tip[Tauri v2]
If working in a greenfield project, we strongly recommend that you give [Tauri v2](https://tauri.app) priority. It has been released and comes with a lot of new awesome features. See [Tauri 2.0 Stable Release blog](https://tauri.app/blog/tauri-20/)
:::
## Versionining
The release version number is automatically extracted from [Tauri configuration files (`tauri.conf.json`)](https://tauri.app/v1/references/configuration-files/). The version entries in `Cargo.toml` and `package.json` will be ignored for your project release in CrabNebula and thus can be removed/ommitted.
## Code Signing
For security reasons, it's recommended to sign your code by generating a **private key** and a **private key password** for your app. Passing those keys via the environment variables (`TAURI_PRIVATE_KEY` and `TAURI_KEY_PASSWORD`) to your `tauri build` command will be enough. See the [Tauri Docs](https://v1.tauri.app/v1/guides/distribution/sign-linux/) for more details.
## Workflow Triggers
For testing and developing purposes it may be useful to set a `workflow_dispatch` trigger, so the workflow can be initiated from the GitHub UI.
```yaml
run-name: triggered by ${{ github.actor }}.
on: workflow_dispatch
```
Once testing is done, it's recommended to use Continuous Deployment.
```yaml
on:
push:
branches:
- main
```
## Deploy Platforms
When deploying to multiple platforms, it's useful to make builds concurrent. Also, cancelling ongoing processes when a new workflow starts.
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
```
## Jobs
The following section snippets must be added in the `jobs` map.
```yaml
jobs:
:
```
Note that the indentation is important.
### Draft Release
The release draft command will create a new entry in your CrabNebula project, but it won't upload any assets just yet. It uses the **crabnebula-dev/cloud-release** action, which requires [`CN_API_KEY`](/cloud/org-management/create-api-key) to be defined within your GitHub Action scope.
Because we'll refer to this later on as well, we'll store our application name in `env` first.
```yaml
env:
# ...
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
```
:::tip[Your App Name]
Remember to replace `YOUR_ORG_NAME/YOUR_APP_NAME` for your org and app's slugs.
For example `crabnebula/devtools-desktop`.
:::
And then call the release draft command.
```yaml
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
### Build Your App
The build step is for setting up the container image in which our task will run for each platform, and finally run your app's build to create the Tauri binaries.
Establish the dependencies and the matrix of platforms we want to run concurrently. Add the common dependencies (Rust, and Node.js), create a cache for Rust.
```yaml
build:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
```
```yaml
build:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
```
```yaml
build_desktop:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install bun
uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
```
#### Linux and Windows
Linux distros require additional system dependencies. For Tauri v1 we need `webkit2gtk-4.0`, that's the WebView our frontend will be running in.
```yaml
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev
```
With dependencies setup for Linux, it's time to build the Tauri app for Windows and Linux.
```yaml
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
npm ci
npm exec tauri build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
```
```yaml
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
pnpm install
pnpm tauri build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
```
```yaml
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
yarn install --frozen-lockfile
yarn tauri build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
```
```yaml
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
bun install
bun run tauri build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
```
#### MacOS
GitHub Actions run on Apple Silicon by default, so we must add Mac Intel support to our platform and establish the appropriate target to our Tauri CLI.
```yaml
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
npm ci
npm exec tauri build -- --target x86_64-apple-darwin
npm exec tauri build -- --target aarch64-apple-darwin
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
```
```yaml
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
pnpm install
pnpm tauri build --target x86_64-apple-darwin
pnpm tauri build --target aarch64-apple-darwin
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
```
```yaml
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
yarn install --frozen-lockfile
yarn tauri build --target x86_64-apple-darwin
yarn tauri build --target aarch64-apple-darwin
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
```
```yaml
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
bun install
bun run tauri build --target x86_64-apple-darwin
bun run tauri build --target aarch64-apple-darwin
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
```
#### Upload Assets to Cloud
At the last step of our **build**, we push all assets to the **Cloud** project. At this point, you will be able to see the binaries showing up in your dashboard. But the release is not published yet!
```yaml
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
path: ./src-tauri
```
### Publishing
At this point, the heavy lifting has been done and it's time ot publish the release. If you don't want to autopublish, you can do it manually from the **Cloud** dashboard.
```yaml
publish:
needs: build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
## Full Workflow
```yaml
name: Tauri v1 Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
jobs:
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
npm ci
npm exec tauri build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
npm ci
npm exec tauri build -- --target x86_64-apple-darwin
npm exec tauri build -- --target aarch64-apple-darwin
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
path: ./src-tauri
publish:
needs: build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
```yaml
name: Tauri v1 Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
jobs:
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
pnpm install
pnpm tauri build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
pnpm install
pnpm tauri build --target x86_64-apple-darwin
pnpm tauri build --target aarch64-apple-darwin
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
path: ./src-tauri
publish:
needs: build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
```yaml
name: Tauri v1 Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
jobs:
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
yarn install --frozen-lockfile
yarn tauri build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
yarn install --frozen-lockfile
yarn tauri build --target x86_64-apple-darwin
yarn tauri build --target aarch64-apple-darwin
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
path: ./src-tauri
publish:
needs: build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
```yaml
name: Tauri v1 Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
jobs:
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install bun
uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
bun install
bun run tauri build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
bun install
bun run tauri build --target x86_64-apple-darwin
bun run tauri build --target aarch64-apple-darwin
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
path: ./src-tauri
publish:
needs: build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
# Tauri v2
import { Steps, Tabs, TabItem } from "@astrojs/starlight/components";
This workflow is specifically tailored to [Tauri v2](https://tauri.app) applications. It can be easily adapted to work with any Tauri app and only requires the your project's slug within your CrabNebula organization as an input. Instead of just uploading assets (like in the previous workflow), the `build` job builds the Tauri app automatically for Linux, MacOS, and Windows. and uploads the assets directly afterwards.
:::caution[Coming from v1]
If you are in the process of migrating a Tauri v1 project, make sure to run [`tauri migrate`](https://tauri.app/start/migrate/) in your codebase before proceeding with this workflow.
:::
## Versionining
The release version number is automatically extracted from [Tauri configuration files (`tauri.conf.json`)](https://tauri.app/develop/configuration-files/). The version entries in `Cargo.toml` and `package.json` will be ignored for your project release in CrabNebula and thus can be removed/ommitted.
## Code Signing
For security reasons, it's recommended to sign your code by generating a **private key** and a **private key password** for your app. Passing those keys via the environment variables (`TAURI_SIGNING_PRIVATE_KEY` and `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`) to your `tauri build` command will be enough. See the [Tauri Docs](https://tauri.app/distribute/sign/linux/) for more details.
## Workflow Triggers
For testing and developing purposes it may be useful to set a `workflow_dispatch` trigger, so the workflow can be initiated from the GitHub UI.
```yaml
run-name: triggered by ${{ github.actor }}.
on: workflow_dispatch
```
Once testing is done, it's recommended to use Continuous Deployment.
```yaml
on:
push:
branches:
- main
```
## Deploy Platforms
When deploying to multiple platforms, it's useful to make builds concurrent. Also, cancelling ongoing processes when a new workflow starts.
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
```
## Jobs
The following section snippets must be added in the `jobs` map.
```yaml
jobs:
:
```
Note that the indentation is important.
### Draft Release
The release draft command will create a new entry in your CrabNebula project, but it won't upload any assets just yet. It uses the **crabnebula-dev/cloud-release** action, which requires [`CN_API_KEY`](/cloud/org-management/create-api-key) to be defined within your GitHub Action scope.
Because we'll refer to this later on as well, we'll store our application name in `env` first.
```yaml
env:
# ...
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
```
:::tip[Your App Name]
Remember to replace `YOUR_ORG_NAME/YOUR_APP_NAME` for your org and app's slugs.
For example `crabnebula/devtools-desktop`.
:::
And then call the release draft command.
```yaml
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
### Build Your App
The build step is for setting up the GitHub Action runner in which our task will run for each platform, and finally run your app's build to create the Tauri binaries.
Establish the dependencies and the matrix of platforms we want to run concurrently. Add the common dependencies (Rust, and Node.js), create a cache for Rust, build the binaries and upload the artifacts.
```yaml
build_desktop:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
```
```yaml
build_desktop:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
```
```yaml
build_desktop:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install bun
uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
```
#### Linux and Windows
Linux distros require additional system dependencies. For Tauri v2 we need `webkit2gtk-4.1`, that's the WebView our frontend will be running in.
```yaml
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev
```
With dependencies setup for Linux, it's time to build the Tauri app for Windows and Linux.
```yaml
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
npm ci
npm exec tauri build
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
```
```yaml
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
pnpm install
pnpm tauri build
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
```
```yaml
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
yarn install --frozen-lockfile
yarn tauri build
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
```
```yaml
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
bun install
bun run tauri build
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
```
#### MacOS
GitHub Actions run on Apple Silicon by default, so we must add Mac Intel support to our platform and establish the appropriate target to our Tauri CLI.
```yaml
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
npm ci
npm exec tauri build -- --target x86_64-apple-darwin
npm exec tauri build -- --target aarch64-apple-darwin
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
```
```yaml
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
pnpm install --frozen-lockfile
pnpm tauri build --target x86_64-apple-darwin
pnpm tauri build --target aarch64-apple-darwin
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
```
```yaml
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
yarn install --frozen-lockfile
yarn tauri build --target x86_64-apple-darwin
yarn tauri build --target aarch64-apple-darwin
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
```
```yaml
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
bun install
bun run tauri build --target x86_64-apple-darwin
bun run tauri build --target aarch64-apple-darwin
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
```
#### Upload Assets to Cloud
At the last step of our **build**, we push all assets to the **Cloud** project. At this point, you will be able to see the binaries showing up in your dashboard. But the release is not published yet!
```yaml
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
#### Mobile
If your application targets Android and iOS, we recommend defining separate jobs per platform so your workflow is easier to read.
##### Android
1. Create the job and install Rust and Node.js
```yml
build_android:
needs: draft
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
```
2. Install Android dependencies
```yml
- name: setup JDK 17
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
- name: setup Android SDK
uses: android-actions/setup-android@v3
- name: setup Android NDK
uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: r26d
link-to-sdk: true
- name: install Android targets
run: rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
```
3. Setup Android signing
See the [official documentation](https://v2.tauri.app/distribute/sign/android) for more information.
```yml
- name: setup Android signing
working-directory: src-tauri/gen/android
run: |
echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" > keystore.properties
echo "password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> keystore.properties
base64 -d <<< "${{ secrets.ANDROID_KEY_BASE64 }}" > $RUNNER_TEMP/keystore.jks
echo "storeFile=$RUNNER_TEMP/keystore.jks" >> keystore.properties
```
4. Build the Android application
```yml
- name: build Tauri app for Android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
npm ci
npm run tauri android build
```
```yml
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- name: build Tauri app for Android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
pnpm install
pnpm tauri android build
```
```yml
- name: build Tauri app for Android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
yarn install
yarn tauri android build
```
```yml
- name: build Tauri app for Android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
bun install
bun run tauri android build
```
5. Upload to CrabNebula Cloud
```yml
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
##### iOS
1. Create the job and install Rust and Node.js
```yml
build_ios:
needs: draft
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install iOS target
run: rustup target add aarch64-apple-ios
```
2. Install iOS dependencies
```yml
- name: setup xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
```
3. Setup iOS signing
See the [official documentation](https://v2.tauri.app/distribute/sign/ios/) for more information.
```yml
- name: setup Apple API key
run: |
APPLE_API_KEY_PATH="$RUNNER_TEMP/AuthKey_${{ secrets.APPLE_API_KEY_ID }}.p8"
echo "${{ secrets.APPLE_API_KEY }}" > $APPLE_API_KEY_PATH
echo "APPLE_API_KEY_PATH=$APPLE_API_KEY_PATH" >> $GITHUB_ENV
echo "API_PRIVATE_KEYS_DIR=$RUNNER_TEMP" >> $GITHUB_ENV
```
4. Build the iOS application
```yml
- name: build Tauri app for iOS
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_DEVELOPMENT_TEAM:
run: |
npm ci
npm run tauri ios build --export-method app-store-connect
```
```yml
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- name: build Tauri app for iOS
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_DEVELOPMENT_TEAM:
run: |
pnpm install
pnpm tauri ios build --export-method app-store-connect
```
```yml
- name: build Tauri app for iOS
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_DEVELOPMENT_TEAM:
run: |
yarn install
yarn tauri ios build --export-method app-store-connect
```
```yml
- name: build Tauri app for iOS
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_DEVELOPMENT_TEAM:
run: |
bun install
bun run tauri ios build --export-method app-store-connect
```
:::caution
Note that you **must** set a value for the APPLE_DEVELOPMENT_TEAM environment variable.
:::
5. Upload to CrabNebula Cloud
```yml
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
### Publishing
At this point, the heavy lifting has been done and it's time ot publish the release. If you don't want to autopublish, you can do it manually from the **Cloud** dashboard.
```yaml
publish:
needs: [build_desktop, build_android, build_ios]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
## Full Workflow
```yaml
name: Tauri v2 Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
jobs:
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_desktop:
needs: draft
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
- os: macos-latest
- os: windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
npm ci
npm exec tauri build
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: Install x86_64-apple-darwin target for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
npm ci
npm exec tauri build -- --target x86_64-apple-darwin
npm exec tauri build -- --target aarch64-apple-darwin
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_android:
needs: draft
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: setup JDK 17
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
- name: setup Android SDK
uses: android-actions/setup-android@v3
- name: setup Android NDK
uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: r26d
link-to-sdk: true
- name: install Android targets
run: rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
- name: setup Android signing
working-directory: src-tauri/gen/android
run: |
echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" > keystore.properties
echo "password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> keystore.properties
base64 -d <<< "${{ secrets.ANDROID_KEY_BASE64 }}" > $RUNNER_TEMP/keystore.jks
echo "storeFile=$RUNNER_TEMP/keystore.jks" >> keystore.properties
- name: build Tauri app for Android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
npm ci
npm run tauri android build
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_ios:
needs: draft
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install iOS target
run: rustup target add aarch64-apple-ios
- name: setup xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: setup Apple API key
run: |
APPLE_API_KEY_PATH="$RUNNER_TEMP/AuthKey_${{ secrets.APPLE_API_KEY_ID }}.p8"
echo "${{ secrets.APPLE_API_KEY }}" > $APPLE_API_KEY_PATH
echo "APPLE_API_KEY_PATH=$APPLE_API_KEY_PATH" >> $GITHUB_ENV
echo "API_PRIVATE_KEYS_DIR=$RUNNER_TEMP" >> $GITHUB_ENV
- name: build Tauri app for iOS
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_DEVELOPMENT_TEAM:
run: |
npm ci
npm run tauri ios build --export-method app-store-connect
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
publish:
needs: [build_desktop, build_android, build_ios]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
```yaml
name: Tauri v2 Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
jobs:
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_desktop:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
pnpm install
pnpm tauri build
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
pnpm install
pnpm tauri build --target x86_64-apple-darwin
pnpm tauri build --target aarch64-apple-darwin
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_android:
needs: draft
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: setup JDK 17
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
- name: setup Android SDK
uses: android-actions/setup-android@v3
- name: setup Android NDK
uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: r26d
link-to-sdk: true
- name: install Android targets
run: rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
- name: setup Android signing
working-directory: src-tauri/gen/android
run: |
echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" > keystore.properties
echo "password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> keystore.properties
base64 -d <<< "${{ secrets.ANDROID_KEY_BASE64 }}" > $RUNNER_TEMP/keystore.jks
echo "storeFile=$RUNNER_TEMP/keystore.jks" >> keystore.properties
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- name: build Tauri app for Android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
pnpm install
pnpm tauri android build
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_ios:
needs: draft
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install iOS target
run: rustup target add aarch64-apple-ios
- name: setup xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: setup Apple API key
run: |
APPLE_API_KEY_PATH="$RUNNER_TEMP/AuthKey_${{ secrets.APPLE_API_KEY_ID }}.p8"
echo "${{ secrets.APPLE_API_KEY }}" > $APPLE_API_KEY_PATH
echo "APPLE_API_KEY_PATH=$APPLE_API_KEY_PATH" >> $GITHUB_ENV
echo "API_PRIVATE_KEYS_DIR=$RUNNER_TEMP" >> $GITHUB_ENV
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- name: build Tauri app for iOS
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_DEVELOPMENT_TEAM:
run: |
pnpm install
pnpm tauri ios build --export-method app-store-connect
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
publish:
needs: [build_desktop, build_android, build_ios]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
```yaml
name: Tauri v2 Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
jobs:
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_desktop:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
yarn install --frozen-lockfile
yarn tauri build
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
yarn install --frozen-lockfile
yarn tauri build --target x86_64-apple-darwin
yarn tauri build --target aarch64-apple-darwin
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_android:
needs: draft
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: setup JDK 17
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
- name: setup Android SDK
uses: android-actions/setup-android@v3
- name: setup Android NDK
uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: r26d
link-to-sdk: true
- name: install Android targets
run: rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
- name: setup Android signing
working-directory: src-tauri/gen/android
run: |
echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" > keystore.properties
echo "password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> keystore.properties
base64 -d <<< "${{ secrets.ANDROID_KEY_BASE64 }}" > $RUNNER_TEMP/keystore.jks
echo "storeFile=$RUNNER_TEMP/keystore.jks" >> keystore.properties
- name: build Tauri app for Android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
yarn install
yarn tauri android build
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_ios:
needs: draft
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install iOS target
run: rustup target add aarch64-apple-ios
- name: setup xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: setup Apple API key
run: |
APPLE_API_KEY_PATH="$RUNNER_TEMP/AuthKey_${{ secrets.APPLE_API_KEY_ID }}.p8"
echo "${{ secrets.APPLE_API_KEY }}" > $APPLE_API_KEY_PATH
echo "APPLE_API_KEY_PATH=$APPLE_API_KEY_PATH" >> $GITHUB_ENV
echo "API_PRIVATE_KEYS_DIR=$RUNNER_TEMP" >> $GITHUB_ENV
- name: build Tauri app for iOS
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_DEVELOPMENT_TEAM:
run: |
yarn install
yarn tauri ios build --export-method app-store-connect
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
publish:
needs: [build_desktop, build_android, build_ios]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
```yaml
name: Tauri v2 Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: "YOUR_ORG_NAME/YOUR_APP_NAME"
jobs:
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_desktop:
needs: draft
strategy:
fail-fast: false
matrix:
os:
- ubuntu-22.04
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install bun
uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev
- name: build Tauri app for Windows, Linux
if: matrix.os != 'macos-latest'
run: |
bun install
bun run tauri build
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: Install x86_64-apple-darwin for mac and build Tauri binaries
if: matrix.os == 'macos-latest'
run: |
rustup target add x86_64-apple-darwin
bun install
bun run tauri build --target x86_64-apple-darwin
bun run tauri build --target aarch64-apple-darwin
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_android:
needs: draft
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: setup JDK 17
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
- name: setup Android SDK
uses: android-actions/setup-android@v3
- name: setup Android NDK
uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: r26d
link-to-sdk: true
- name: install Android targets
run: rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
- name: setup Android signing
working-directory: src-tauri/gen/android
run: |
echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" > keystore.properties
echo "password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> keystore.properties
base64 -d <<< "${{ secrets.ANDROID_KEY_BASE64 }}" > $RUNNER_TEMP/keystore.jks
echo "storeFile=$RUNNER_TEMP/keystore.jks" >> keystore.properties
- name: Install bun
uses: oven-sh/setup-bun@v2
- name: build Tauri app for Android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
bun install
bun run tauri android build
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build_ios:
needs: draft
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install iOS target
run: rustup target add aarch64-apple-ios
- name: setup xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: setup Apple API key
run: |
APPLE_API_KEY_PATH="$RUNNER_TEMP/AuthKey_${{ secrets.APPLE_API_KEY_ID }}.p8"
echo "${{ secrets.APPLE_API_KEY }}" > $APPLE_API_KEY_PATH
echo "APPLE_API_KEY_PATH=$APPLE_API_KEY_PATH" >> $GITHUB_ENV
echo "API_PRIVATE_KEYS_DIR=$RUNNER_TEMP" >> $GITHUB_ENV
- name: Install bun
uses: oven-sh/setup-bun@v2
- name: build Tauri app for iOS
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_DEVELOPMENT_TEAM:
run: |
bun install
bun run tauri ios build --export-method app-store-connect
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
publish:
needs: [build_desktop, build_android, build_ios]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
# Taurify
import { Tabs, TabItem } from "@astrojs/starlight/components";
The following workflow is specifically tailored to [Taurify](/taurify) applications.
## Versionining
The release version number is automatically extracted from [Taurify configuration file (`taurify.json`)](/taurify/configuration#version).
## Workflow Triggers
For testing and developing purposes it may be useful to set a `workflow_dispatch` trigger, so the workflow can be initiated from the GitHub UI.
```yaml
run-name: triggered by ${{ github.actor }}.
on: workflow_dispatch
```
Once testing is done, it's recommended to use Continuous Deployment.
```yaml
on:
push:
branches:
- main
```
## Action Environment
The actual packaging of your application is done on the Taurify servers, so you can use the `ubuntu-latest` GitHub Actions runner.
When deploying you might desire to cancel ongoing processes when a new workflow starts.
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
```
## Jobs
The following section snippets must be added in the `jobs` map.
```yaml
jobs:
:
```
Note that the indentation is important.
### Trigger Release
To trigger a new release, you must set up the Taurify secrets and run [`taurify build`](/taurify/cli#build).
Fore more information on how to set up secrets such as your Taurify signing keypair, CrabNebula Cloud API key and application signing keys,
see the [Taurify distribution guide](/taurify/distribute/).
```yaml
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: install dependencies
run: npm install
- name: trigger release
env:
CN_API_KEY: ${{ secrets.CN_API_KEY }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
run: npm exec taurify build
```
```yaml
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
- name: install dependencies
run: pnpm install
- name: trigger release
env:
CN_API_KEY: ${{ secrets.CN_API_KEY }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
run: pnpm taurify build
```
```yaml
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: install dependencies
run: yarn install
- name: trigger release
env:
CN_API_KEY: ${{ secrets.CN_API_KEY }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
run: yarn taurify build
```
```yaml
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install bun
uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v4
- name: install dependencies
run: bun install
- name: trigger release
env:
CN_API_KEY: ${{ secrets.CN_API_KEY }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
run: bun run taurify build
```
When this job is completed, your Taurify release is available on the CrabNebula Cloud platform.
## Full Workflow
```yaml
name: Taurify Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: install dependencies
run: npm install
- name: trigger release
env:
CN_API_KEY: ${{ secrets.CN_API_KEY }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
run: npm exec taurify build
```
```yaml
name: Taurify Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
- name: install dependencies
run: pnpm install
- name: trigger release
env:
CN_API_KEY: ${{ secrets.CN_API_KEY }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
run: pnpm taurify build
```
```yaml
name: Taurify Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: install dependencies
run: yarn install
- name: trigger release
env:
CN_API_KEY: ${{ secrets.CN_API_KEY }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
run: yarn taurify build
```
```yaml
name: Taurify Release Process
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install bun
uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v4
- name: install dependencies
run: bun install
- name: trigger release
env:
CN_API_KEY: ${{ secrets.CN_API_KEY }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
run: bun run taurify build
```
# Bootstrap
import { Steps } from "@astrojs/starlight/components";
The CrabNebula Cloud CLI offers a `bootstrap` command that helps you prepare your application to be distributed using Cloud.
It performs the following tasks:
- ensure your organization and application exists in the CrabNebula Cloud platform
- set up your Tauri application with support to auto-updates via Cloud
- create a CrabNebula Cloud API key
- optionally set up a release GitHub Action workflow for [Tauri v1](/cloud/ci/tauri-v1-workflow) or [Tauri v2](/cloud/ci/tauri-v2-workflow).
## Usage
After [installing the CLI](/cloud/cli/install), you can simply run the bootstrap command inside a Tauri app project:
```sh
cd path/to/app
cn bootstrap
```
The bootstrap CLI command must sign-in to CrabNebula Cloud to ensure your organization, application and API key are set up.
When you execute `cn bootstrap`, it opens the browser to authenticate with `https://web.crabnebula.cloud`.
After signing in, switch back to the terminal to complete the following bootstrap steps:
1. Choose a CrabNebula Cloud application to upload releases to by either:
- Creating your first organization and application.
- Selecting an existing organization and application.
2. (Optional) Create a new CrabNebula Cloud API key to upload releases unless you already have one set up.
3. If a Tauri project can be found in the current working directory, the CLI will set up the Tauri updater with CrabNebula Cloud support.
- The `tauri.conf.json` file will be updated to include the required Tauri updater configuration
- A new updater signing key is generated
- For tauri v2 the updater plugin is added to the application
4. Additionally the bootstrap command generates a basic GitHub action release workflow that uploads assets to CrabNebula Cloud.
# Create a Release Draft
The first step in creating a new release for your app is to create a draft. You will need:
- The Application's slug (example: `devtools-desktop`)
- The Organization's slug (example: `crabnebula`)
- The version number for this draft (example: `1.0.0`)
When combined like `crabnebula/devtools-desktop` this is referred to as a "fully qualified" application slug.
The slugs can be found on the Application's details page.
:::tip
Be sure to follow the [instructions to setup the CrabNebula Cloud CLI](/cloud/cli/install) before continuing.
:::
Create a draft by running the following command:
```sh
cn release draft {org-slug/app-slug} {version-number}
```
:::tip
When using Tauri or cargo-packager, you can automatically draft a release with your app's version by running
`cn release draft {org-slug/app-slug} --framework [tauri|packager]`.
:::
Note that the version number can be any string that represents the version of the application so that any versioning scheme is supported.
For example, if wanting to create the 1.0.0 release for an application with the fully qualified slug `crabnebula/devtools-desktop` you would run the following command:
```sh
cn release draft crabnebula/devtools-desktop "1.0.0"
```
You will now see a new draft in the Cloud Platform for the specified application. Take note of the `id` value output from the `cn release draft` command as it will be needed when uploading assets in the next step.
## Release notes
You can also add notes to a release by including the `--notes` flag when running `cn release draft`. Alternatively, a file containing the notes can be specified with the `--notes-file` argument.
Release notes would typically become part of your CI workflow (like GitHub Actions) to obtain or generate release notes first. Then you can provide it as part of the `cn release draft` command.
```sh
# Generating your release notes as release-notes.txt
cn release draft crabnebula/devtools-desktop "1.0.0" \
--notes-file release-notes.txt
```
The same can be done when you're using the `--framework [tauri|packager]` argument.
```sh
# Generating your release notes as release-notes.txt
cn release draft crabnebula/devtools-desktop --framework tauri \
--notes-file release-notes.txt
```
## Release Channels
Release channels are a mechanism that allows you to deploy assets to different environments such as beta releases or QA builds. To draft a release on a specific channel, use the `--channel ` CLI argument. If no channel is set, it is assumed to be the default/production channel which does **NOT** have an actual name, so no value provided as channel name matches it.
:::note
The `--channel ` CLI argument must also be provided to the `release show`, `release purge`, `release upload` and `release publish` commands.
:::
:::caution
Release channels are NOT visible on your application's public page, but they are still publicly accessible. Consider the channels "public, but not advertised".
:::
#### Release Creation
Create a draft release on a specific channel (such as `beta`) by running the following command:
```sh
cn release draft crabnebula/devtools-desktop "1.0.0" --channel beta
```
#### App Download
To utilize this channel in download links such as in our Download Button Snippet generator, use the `channel` query parameter. For example, to download the latest release of an application under a specific channel, you would use the following URL format:
`https://cdn.crabnebula.app/download///latest/?channel=`
Where you must replace ``, ``, ``, and `` with your organization's slug, the application slug, the release asset file name, and the channel, respectively.
#### (Tauri) App Updates
To utilize this channel in the Tauri Updater links, the `channel` query parameter is also used. For example, the following URL format could be used in your `tauri.conf.json` file:
```json
"endpoints": [
"https://cdn.crabnebula.app/update///{{target}}-{{arch}}/{{current_version}}?channel="
],
```
Where you must replace each of the `<..>` pieces with with your data. Visit your application's 'Configure Tauri Updates' page to get the correct URL for your application, and just add the `channel` parameter.
##### Changing Release Channel at Runtime
If you would like to offer app users the ability to switch between channels, you must clear the configured endpoints and check for updates on the Rust side. See [AppHandle::updater](https://docs.rs/tauri/latest/tauri/struct.AppHandle.html#method.updater) and [UpdateBuilder::endpoints](https://docs.rs/tauri/latest/tauri/updater/struct.UpdateBuilder.html#method.endpoints) for Tauri v1 and [UpdaterExt::updater_builder](https://docs.rs/tauri-plugin-updater/2/tauri_plugin_updater/trait.UpdaterExt.html#tymethod.updater_builder) and [UpdaterBuilder::endpoints](https://docs.rs/tauri-plugin-updater/2/tauri_plugin_updater/struct.UpdaterBuilder.html#method.endpoints) for Tauri v2.
For a complete example application that manages release channels at runtime, see the [cloud-release-channels-demo repository](https://github.com/crabnebula-dev/cloud-release-channels-demo).
## Delete a Release Draft
If you need to delete a release draft, you can do so from the Cloud Platform. Go to the applications page and find the unpublished draft. Click on the _"View"_ button on the right and then select _"Delete draft"_ from the Danger Zone. Note that this cannot be undone.
Next, [upload assets for the release](/cloud/cli/upload-assets).
# Fetch Latest Release
The latest release assets are available via the Cloud's Content Delivery Network (CDN). Additionally you can display the metadata of any release from the [CLI](/cloud/cli/install).
## View release metadata from [CLI](/cloud/cli/install)
You can view the metadata of any release by running:
```sh
cn release show {org-slug/app-slug} {release-id or version}
```
:::note
You have to specify the channel name as well using `--channel ` if using a release channel. For more information, see the [Release Draft](/cloud/cli/create-draft/#release-channels) page.
:::
This will print the metadata of the release in JSON format. For example:
```json
{
"id": "01JSGWMMTRBTD4YSBEVE3W5B7V",
"status": "Published",
"appId": "01JDSTGXKDNHCQJV3MAM4R6RVT",
"version": "0.1.0-quick.1",
"notes": null,
"createdAt": "2025-04-23T08:36:11.736Z",
"pubDate": "2025-04-23T08:36:12.101Z",
"purgedAt": null,
"assets": [
{
"id": "01JSGWMMZ7NE042DHJVAP520KN",
"updatePlatform": null,
"publicPlatform": null,
"filename": "nova.webp",
"signature": null,
"size": "5060",
"createdAt": "2025-04-23T08:36:11.956293524Z"
}
],
"channel": null
}
```
## Download Assets by File Name
Each asset in the latest release can be downloaded with the following CDN URL:
`https://cdn.crabnebula.app/download///latest/`
Where you must replace ``, `` and `` with your organization's slug, the application slug and the release asset file name, respectively. This endpoint is useful when you want to allow your users to download your application's latest installer, for instance.
:::tip
To fetch the latest asset of a particular release channel you can append the `?channel=` query string to the URL.
:::
## Download Assets by Public Platform
The CDN exposes an endpoint that can be used to fetch an asset in the latest release by its public platform instead of its filename:
`https://cdn.crabnebula.app/download///latest/platform/`
Where you must replace ``, `` and `` with your organization's slug, the application slug and the executable's public platform key, respectively.
Public platform keys that are automatically set by the CLI when using the `--framework` option are:
- Linux:
- `deb-$arch`
- `rpm-$arch`
- `appimage-$arch`
- `pacman-$arch`
- `linux-$arch` (for custom formats e.g. plain executable)
- macOS:
- `dmg-$arch`
- `macos-$arch` (for custom formats e.g. plain executable)
- Windows:
- `nsis-$arch`
- `wix-$arch`
- `windows-$arch` (for custom formats e.g. plain executable)
:::tip
To fetch the latest asset of a particular release channel you can append the `?channel=` query string to the URL.
:::
## Asset Metadata by Update Platform
The CDN additionally exposes an endpoint that can be used by your application to check for updates by taking a version number and update platform and producing a JSON object containing the update data if the version does not match the latest. The update metadata can be fetched with the following CDN URL:
`https://cdn.crabnebula.app/update////`
Where you must replace ``, ``, `` and `` with your organization's slug, the application slug, the executable's update platform key and the current version, respectively. A list of update platform keys can be found on the [Upload Assets](/cloud/cli/upload-assets/#update-platform---update-platform) page.
:::tip
To fetch the latest asset of a particular release channel you can append the `?channel=` query string to the URL.
:::
For instance when uploading the following `linux-x86_64` and `darwin-aarch64` assets:
```sh
cn release draft "crabnebula/devtools-desktop" "0.2.0"
cn release upload "crabnebula/devtools-desktop" "" \
--update-platform linux-x86_64 \
--file \
--signature
cn release upload "crabnebula/devtools-desktop" "" \
--update-platform darwin-aarch64 \
--file \
--signature
cn release publish "crabnebula/devtools-desktop" ""
```
For the `https://cdn.crabnebula.app/update/crabnebula/devtools-desktop/linux-x86_64/0.2.0` request, the current version matches latest so the response status code is 204.
For the `https://cdn.crabnebula.app/update/crabnebula/devtools-desktop/linux-x86_64/0.1.0` request, the response status code is 200 with the following JSON body:
```json
{
"version": "0.2.0",
"pub_date": "2024-03-19T02:35:10.440Z",
"notes": "...",
"url": "",
"signature": ""
}
```
For the `https://cdn.crabnebula.app/update/crabnebula/crabnebula-devtools/darwin-aarch64/1.0.0` request, the response status code is 200 with the following JSON body:
```json
{
"version": "0.2.0",
"pub_date": "2024-03-19T02:35:10.440Z",
"notes": "...",
"url": "",
"signature": ""
}
```
:::note
In this last example the latest release version (0.2.0) is lower than the current one (1.0.0) but the CDN still returns the update data, allowing downgrades.
:::
# Install
The CrabNebula Cloud CLI can be used to create a release draft, upload assets, and then publish a release.
Creating a release involves the following steps:
1. [Create a new draft](/cloud/cli/create-draft)
2. [Upload assets to CrabNebula Cloud](/cloud/cli/upload-assets)
3. [Publish the release to users](/cloud/cli/publish-release)
## Prerequisites
:::tip
The [bootstrap](/cloud/cli/bootstrap) command ensures you have all prerequites to start distributing with CrabNebula Cloud.
[Install the CLI](#install-the-cli) and see the [bootstrap](/cloud/cli/bootstrap) documentation for more information.
:::
In order to begin using the CrabNebula Cloud CLI a few steps must first be completed:
1. Create an Application (learn how to in [Create an Application](/cloud#create-an-application))
2. Create an API key (learn how to in [Create an API Key](/cloud/org-management/create-api-key))
3. Export the API key to the environment
- Linux and macOS: `export CN_API_KEY={api-key}`
- Windows: `set CN_API_KEY={api-key}`
- Note that this will only add the API key as an environment variable for the lifetime of the current shell session. You can also pass the API key with the `--api-key` flag when executing any command.
## Install the CLI
You can download the CLI from [here](https://crabnebula.cloud/crabnebula/cn-cli/releases). It is a single binary that can be executed from anywhere on your system. In the context of this documentation we will assume that the binary is named `cn` (`cn.exe` on Windows).
### Quick Links
:::tip
The above download buttons were automatically generated by CrabNebula Cloud since the CLI is distributed over it as well. Head to the *Download Button* section on the Application details page to create your own download button (even supports automatic OS recognition).
:::
### Linux and macOS
To verify that the CLI can execute as expected open a terminal and navigate to the folder with the downloaded binary. Assuming the binary is named `cn`, running `./cn whoami` will show you the identity linked to the API key. If you get a permission denied error, you may need to make the binary executable with `chmod +x cn`.
If you want to install the CLI globally on your system, you can move the binary to a folder in your `PATH` (e.g.: `/usr/local/bin` on macOS and Linux).
### Windows
To verify that the CLI can execute as expected open a command prompt and navigate to the folder with the downloaded binary. Assuming the binary is named `cn.exe`, running `.\cn.exe whoami` will show you the identity linked to the API key.
If you want to install the CLI globally on your system, you can add the folder with the binary to your `PATH` environment variable. See [these steps from Microsoft](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/path) for instructions on how to do this.
# Publish a Release
The final step to getting an update to users is to publish the release. Be sure to first [create a draft](/cloud/cli/create-draft) then [upload assets](/cloud/cli/upload-assets) for a release before continuing.
:::tip
You can verify the release notes, version number, and assets in the "Releases" section for a given application.
:::
There are two ways to publish a release:
- [Publishing with the Cloud Platform](#publishing-with-the-cloud-platform)
- [Publishing with the CLI](#publishing-with-the-cli)
### Publishing with the Cloud Platform
After the assets have been uploaded, a release can be published by visiting the respective "Release" page on the CrabNebula Cloud platform. Clicking the "Publish draft" button in the upper-right corner will make the release available to users.
### Publishing with the CLI
In order to publish a release with the CLI you will need:
- Organization slug
- Application slug
- Release ID (output after creating a new draft with the CLI)
- _Optional_: The release channel name
:::tip
Be sure to follow the [instructions to setup the CrabNebula Cloud CLI](/cloud/cli/install) before continuing.
:::
To publish a release run the following command:
```sh
cn release publish {org-slug/app-slug} {release-id}
```
:::tip
When using Tauri or cargo-packager, you can automatically publish the release referencing your app's version by running
`cn release publish {org-slug/app-slug} --framework [tauri|packager]`.
:::
### Release channel `--channel`
If you specified the release channel while drafting the release, you must specify the same channel name again using `--channel ` argument to publish the release in the same channel. For more information, see the [Release Draft](/cloud/cli/create-draft/#release-channels) page.
### Example Usage
To publish the example of `crabnebula/devtools-desktop` with release ID `01HKA6TGC281V51NGSRJNTJQAF` the following command would be used:
```sh
cn release publish "crabnebula/devtools-desktop" "01HKA6TGC281V51NGSRJNTJQAF"
```
# Purge a Release
When an older release is not needed anymore or your latest release has an issue and you want to roll back or stop its rollout,
you can purge a release to delete all of its assets from the CrabNebula Cloud platform.
:::caution
Purging a release is an irreversible action that destroys all of its assets.
:::
:::caution
If the purged release is the latest release of a given channel the CDN updater automatically rolls back to the previous release (by publish date instead of semantic versioning). If that is not desired, you must publish a new release before purging the latest.
:::
There are two ways to purge a release:
- [Purging with the Cloud Platform](#purging-with-the-cloud-platform)
- [Purging with the CLI](#purging-with-the-cli)
### Purging with the Cloud Platform
A release can be purged by visiting the respective "Release" page on the CrabNebula Cloud platform. Clicking the "Purge release" button in the bottom-left corner will purge the release.
This action can only be done by admins.
### Purging with the CLI
In order to purge a release with the CLI you will need:
- Organization slug
- Application slug
- Release ID or version
:::tip
Be sure to follow the [instructions to setup the CrabNebula Cloud CLI](/cloud/cli/install) before continuing.
:::
To purge a release run the following command:
```sh
cn release purge {org-slug/app-slug} {release-id or version}
```
:::note
You have to specify the channel name as well using `--channel ` if using a release channel. For more information, see the [Release Draft](/cloud/cli/create-draft/#release-channels) page.
:::
# Quality reports
import { Tabs, TabItem } from "@astrojs/starlight/components";
We're constantly monitoring the Cloud Platform for [availability](https://cloud.crabnebula.online/) and possible issues.
In order to help detect such issues the CrabNebula Cloud CLI may submit quality reports.
## Privacy
Quality reports from the CLI are sent to CrabNebula Cloud at `api.crabnebula.app` and are not
processed by any third parties.
For more information, check our [general privacy policy](https://crabnebula.dev/privacy-policy/).
### Opting-Out
While we make sure that these reports are minimal and don't contain sensitive information,
you can opt-out from sending these reports by either:
- Adding the `--no-quality-reports` command line option.
- Setting the `CN_QUALITY_REPORTS=false` environment variable.
For example:
```sh frame=none
cn release upload --no-quality-reports
```
```sh frame=none
CN_QUALITY_REPORTS=false cn release upload
```
## Example Reports
Here are example of the quality reports currently being sent. Though the types of reports may
change over time, for example if we become aware of new types of issues to be monitoring for.
### Asset Upload
Because the `cn release upload` command may run into networking issues.
| key | description | type |
| ------------- | --------------------------------------------------- | -------- |
| `asset_idx` | the index of the asset, if there are multiple | integer |
| `asset_count` | the total number of assets uploaded in one CLI call | integer |
| `asset_id` | the ID of the asset | string |
| `asset_size` | the size of the asset in bytes | integer |
| `auth` | whether authentication succeeded | Status |
| `resolve` | whether the asset metadata could be resolved | Status |
| `start` | whether the upload started | Status |
| `parts` | whether all parts could be uploaded | Status |
| `finish` | whether the upload finished | Status |
| `part` | the status of each part | Status[] |
| `part_count` | the total number of parts | integer |
Where the `Status` type is `boolean | integer | null`.
- `null` for when this step hasn't started yet.
- `true` when the step succeeded.
- `integer` when the step failed due to an HTTP error, the HTTP response code.
- `false` when the step failed for any other reason.
Here is an example report where the upload encountered a server error.
```json title="Example Quality Report"
{
"asset_idx": 0,
"asset_count": 1,
"asset_id": "01JC1BV1WJJMSPR267W13S9G85",
"asset_size": 12320304,
"auth": true,
"resolve": true,
"start": true,
"parts": 500,
"finish": null,
"part": [500, null, null],
"part_count": 3
}
```
Additionally some HTTP request headers collected from the report:
```text title="HTTP Response Headers"
User-Agent: Cloud CLI/0.9.0
CF-IPCountry: NL
```
- `User-Agent`: The version of the CLI that submitted the report.
- `CF-IPCountry`: The GeoIP country that the report was submitted from.
# Upload Assets
An asset is the compiled binary that will be distributed to users. Before uploading assets be sure to [create a draft release](/cloud/cli/create-draft).
In order to upload an asset the following are needed:
- The Application's slug (example: `devtools-desktop`)
- The Organization's slug (example: `crabnebula`)
- Release ID (printed to the console when creating a new draft or can be found on the Cloud Platform page for the specific release)
- The application asset file
- _Optional_: The signature file for the asset
- _Optional_: The public platform name
- _Optional_: The update platform name
- _Optional_: The release channel name
:::tip
Be sure to follow the [instructions to setup the CrabNebula Cloud CLI](/cloud/cli/install) before continuing.
:::
:::tip
When using Tauri or cargo-packager, you can automatically upload all application bundles to Cloud by running
`cn release upload {org-slug/app-slug} {release-id} --framework [tauri|packager]`.
:::
To upload an asset run the following command:
```sh
cn release upload {org-slug/app-slug} {release-id} \
--public-platform {public-platform-name} \
--update-platform {update-platform-name} \
--file {asset-file-path} \
--signature {signature-file-path}
```
### Public Platform `--public-platform`
The public platform is referenced in your application market page, download buttons and can be used to fetch the asset in the latest release via the CDN. For more information, see the [Fetch Latest Release](/cloud/cli/fetch-latest-release/#download-assets-by-public-platform) page.
Common **public** platform names for Tauri and cargo-packager are listed below:
| Bundle Format | Public platform names |
| ------------- | ------------------------------------------------------------------------ |
| Debian | `deb-x86_64`, `deb-aarch64`, `deb-i686`, `deb-armv7` |
| RPM | `rpm-x86_64`, `rpm-aarch64`, `rpm-i686`, `rpm-armv7` |
| AppImage | `appimage-x86_64`, `appimage-aarch64`, `appimage-i686`, `appimage-armv7` |
| Pacman | `pacman-x86_64`, `pacman-aarch64`, `pacman-i686`, `pacman-armv7` |
| DMG | `dmg-x86_64`, `dmg-aarch64` |
| NSIS | `nsis-x86_64`, `nsis-aarch64`, `nsis-i686` |
| WiX | `wix-x86_64`, `wix-aarch64`, `wix-i686` |
### Update Platform `--update-platform`
The update platform is used to check for updates by taking a version number and update platform and producing a JSON object containing the update data which can be used by application updaters such as the [Tauri updater](https://tauri.app/plugin/updater/) and the [cargo packager auto updater](/packager/updater/). For more information, see the [Fetch Latest Release](/cloud/cli/fetch-latest-release/#asset-metadata-by-update-platform) page.
The `--update-platform` flag is not needed if the asset is for example platform-independent (e.g.: a web app). If no platform is specified, the asset will be presented as a generic asset on the Cloud Platform.
Common **update** platform names for Tauri and cargo-packager are listed below:
| Operating System | Tauri | cargo-packager |
| ---------------- | ----------------------------------------------------------- | ---------------------------------------------------------- |
| Linux | `linux-x86_64`, `linux-aarch64`, `linux-i686`, `linux-armv7` | `linux-x86_64`, `linux-aarch64`, `linux-i686`, `linux-armv7` |
| macOS | `darwin-x86_64`, `darwin-aarch64` | `macos-x86_64`, `macos-aarch64` |
| Windows | `windows-x86_64`, `windows-aarch64`, `windows-i686` | `windows-x86_64`, `windows-aarch64`, `windows-i686` |
Only the macOS prefix differs between the two tools: Tauri uses `darwin-`, while cargo-packager uses `macos-`. Linux and Windows names are identical for both.
Tauri update assets may additionally include the bundle type as a suffix, for example `linux-aarch64-appimage`. The suffix corresponds to the [Tauri bundle type](https://v2.tauri.app/reference/config/#bundletype) (e.g. `appimage`, `deb`, `rpm`, `nsis`, `msi`), excluding `dmg`.
The `--signature` flag is required if `--update-platform` is set. If a `.sig` file with the same name as the asset file exists, the CLI will use it by default.
### Release channel `--channel`
If you specified the release channel while drafting the release, you must specify the same channel name again using `--channel ` argument to upload the assets to the same channel. For more information, see the [Release Draft](/cloud/cli/create-draft/#release-channels) page.
### Example Usage
Here is an example of uploading a `linux-x86_64` binary for the `crabnebula/devtools-desktop` application with a release ID of `01HKA6TGC281V51NGSRJNTJQAF`:
```sh
cn release upload "crabnebula/devtools-desktop" "01HKA6TGC281V51NGSRJNTJQAF" \
--update-platform linux-x86_64 \
--file path_to_binary \
--signature path_to_signature
```
After an asset is uploaded it will then show up on the Cloud Platform under the "Releases" section for an application. Repeat this command for each platform and its respective asset to be distributed.
Next, [publish the release](/cloud/cli/publish-release).
# Tauri v2 with Auto-Updater
import { Tabs, TabItem } from "@astrojs/starlight/components";
import CommandTabs from "@components/CommandTabs.astro";
Let's setup auto-updates with Tauri v2. For this guide, you will need a working Tauri project (v2), in a GitHub repository and integrated with **CrabNebula Cloud**. If you haven't done that yet, the [Publish Tauri with GitHub Actions](/cloud/guides/publish-cloud-github) guide will help you.
:::caution[Tauri v2 only]
Though similar, APIs have changed between Tauri v1 and Tauri v2. This guide is for Tauri v2 only.
:::
## Required Dependencies
| crate name | description | version |
| ---------------------- | ----------------------------------------------------- | -------- |
| `tauri-plugin-updater` | Tauri plugin for auto-updates | `^2.0.0` |
| `tauri-plugin-dialog` | Tauri plugin for dialogs | `^2.0.0` |
| `tauri-plugin-process` | Tauri plugin for handling processes like app relaunch | `^2.0.0` |
To add them with `cargo` you can run:
```bash frame="none"
cargo add tauri-plugin-updater tauri-plugin-dialog
```
## Tauri Capabilities
Before starting to implement auto-updates, some capabilities must be enabled in your app. Usually capabilities are under `/src-tauri/capabilities/main.json`, adjust accordingly if your setup diverged from the defaults. Finally, add the necessary permissions so they match the JSON below:
```json title="/src-tauri/capabilities/main.json"
{
"identifier": "main",
"description": "permissions for desktop app",
"local": true,
"windows": ["main"],
"permissions": [
"dialog:default",
"updater:default",
"process:default",
"process:allow-restart"
]
}
```
## Secret and Public Keys
To secure auto-updates, you need to generate a secret and public key pair. You can use the `tauri-plugin-updater` CLI to generate them:
The above commands will generate a prompt to add a password to your key, make note of that for a while.
:::note[Official Tauri Docs]
To know more, [check the official Tauri documentation](https://tauri.app/plugin/updater/#signing-updates).
:::
The stdout will yield back:
```text title="terminal"
Please enter a password to protect the secret key.
Password:
Password (one more time):
Deriving a key from the password in order to encrypt the secret key... done
Your keypair was generated successfully
Private: /path/.tauri/myapp.key (Keep it secret!)
Public: /path/.tauri/myapp.key.pub
---------------------------
Environment variables used to sign:
`TAURI_SIGNING_PRIVATE_KEY` Path or String of your private key
`TAURI_SIGNING_PRIVATE_KEY_PASSWORD` Your private key password (optional)
ATTENTION:
If you lose your private key OR password, you'll not be able to sign your
update package and updates will not work.
---------------------------
```
In your CI integration, you must add 2 environment variable secrets:
- `TAURI_SIGNING_PRIVATE_KEY` with the content of `myapp.key`.
- `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` with the password you set.
And the contents of `myapp.key.pub` must be added to your `tauri.conf.json`:
```json title="/src-tauri/tauri.conf.json"
"bundle": {
"createUpdaterArtifacts": true
},
"plugins": {
"updater": {
"active": true,
"endpoints": [
"CrabNebula Cloud updater endpoint"
],
"dialog": true,
"pubkey": "contents of myapp.key.pub"
}
}
```
:::caution
Note that the `createUpdaterArtifacts` value must be set to `true` for new applications,
but set to `"v1Compatible"` when updating from a Tauri v1 application.
:::
## Get Updater Endpoint from CrabNebula Cloud
Navigate to [CrabNebula Cloud](https://crabnebula.cloud) and login. At the **Get started** section you will find the **Configure Tauri Updates** card. Clicking on "Configure" will offer you a snippet with the endpoint.

The endpoint URL follows this template:
```text frame="none"
https://cdn.crabnebula.app/update/your-org/your-app/{{target}}-{{arch}}/{{current_version}}
```
**Do not replace the curly brackets**, those are variables that will be used by Tauri itself when defining the right endpoint to hit. CrabNebula will take care of the rest.
## Add the Plugins to Your App
Now it's time to wire things up and use it within your app. The infrastructure is in place, we need to connect to it and to provide a decent user experience. First, we will add the plugins to our Tauri app.
```rust title="/src-tauri/src/lib.rs"
use tauri_plugin_dialog;
pub fn run() {
builder
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_dialog::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
And now it's time to make use of that from the front-end side. We will create a method that will ping the endpoint for updates. If a new version is available it will download it and gracefully restart the app.
```ts title="/src/updater.ts"
import { check } from "@tauri-apps/plugin-updater";
import { ask, message } from "@tauri-apps/plugin-dialog";
import { relaunch } from "@tauri-apps/plugin-process";
export async function checkForAppUpdates() {
const update = await check();
if (update?.available) {
const yes = await ask(
`
Update to ${update.version} is available!
Release notes: ${update.body}
`,
{
title: "Update Now!",
kind: "info",
okLabel: "Update",
cancelLabel: "Cancel",
}
);
if (yes) {
await update.downloadAndInstall();
await relaunch();
}
}
}
```
Lastly, we let this run early and non-blocking.
```tsx frame="none"
import { checkForAppUpdates } from "./updater";
function App() {
onMount(async () => {
await checkForAppUpdates();
});
return Hello world
;
}
```
```tsx frame="none"
import { checkForAppUpdates } from "./updater";
function App() {
useEffect(async () => {
await checkForAppUpdates();
}, []);
return Hello world
;
}
```
```vue
Hello world
```
```js
import { Component, OnInit } from "@angular/core";
import { checkForAppUpdates } from "./updater";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
})
export class AppComponent implements OnInit {
constructor() {}
async ngOnInit() {
await checkForAppUpdates();
}
}
```
```js
import { component$, useMount$ } from "@builder.io/qwik";
import { checkForAppUpdates } from "./updater";
export const App = component$(() => {
useMount$(async () => {
await checkForAppUpdates();
});
return Hello world
;
});
```
```svelte
Hello world
```
```js
import { checkForAppUpdates } from "./updater";
document.addEventListener("DOMContentLoaded", async () => {
await checkForAppUpdates();
});
```
## Final Thoughts
With this setup, you now have auto-updates and CI/CD in your app through [CrabNebula Cloud](https://crabnebula.dev/cloud). This is recommended to make sure your users always have the best and most secure experience. If you have any issues, feel free to reach out at the [CrabNebula Discord](https://discord.gg/W2MNdXVgjD) or the [Tauri Discord](https://discord.gg/tauri).
# Packager with Auto-Updater
In this guide we will cover setting up [Packager](/packager)'s auto-updater with CrabNebula Cloud.
We will use a sample [Slint](https://slint.dev) app to demonstrate the process. However, the process is very similar for any other app built with Cargo.
## Prerequisites
To get started, you will need the following:
- [Rust](https://www.rust-lang.org/tools/install) installed on your machine
- [CrabNebula Cloud](https://crabnebula.dev/cloud) account
Additionally, you will need to install Cargo packager itself. You can do this by running the following command:
```sh frame="none"
cargo install cargo-packager --locked
```
## Download and Configure the Sample App
The Slint sample app is provided within the [cargo packager repository](https://github.com/crabnebula-dev/cargo-packager/tree/main/examples/slint). All the necessary zipped files can be [downloaded](https://cdn.crabnebula.app/download/crabnebula/super-slint-app/latest/super-slint-app.zip). Should you want to use a different app, the guide is relatively easy to adapt. There are other sample apps for other GUI frameworks available in the repo as well. For Tauri apps, however, we feature a separate [guide](/cloud/guides/publish-cloud-github).
:::tip
All the code files which need to be adjusted in the course of this guide are available [for download](https://web.crabnebula.cloud/crabnebula/super-slint-app/releases) from CrabNebula Cloud.
:::
### Customize the Sample App
Navigate into the just downloaded folder and open the `Cargo.toml` file. You will need to adjust the `name` to `super-slint-app` and the `version` to `2.0.0`.
The `Cargo.toml` file should look like this:
```toml frame="none"
[package]
name = "super-slint-app"
version = "2.0.0"
edition = "2021"
publish = false
[dependencies]
slint = "1.0"
[build-dependencies]
slint-build = "1.0"
[package.metadata.packager]
before-packaging-command = "cargo build --release"
product-name = "Slint example"
identifier = "com.slint.example"
resources = ["Cargo.toml", "src", "32x32.png"]
icons = ["32x32.png"]
```
The `before-packaging-command` key is set to `cargo build --release` to build the app before packaging it. If your app requires a different command to build, you can adjust it here.
### Add the Packager Auto Updater
Now we need to add the packager auto updater as a dependency. Open a Terminal and navigate to the app's root folder. Run the following command to add the packager auto updater as a dependency:
```sh frame="none"
cargo add cargo-packager-updater
```
:::note
Make sure that your app folder is not part of a Cargo workspace as this might interfere with all `cargo` commands. If you e.g. have a `Cargo.toml` file in a parent folder, you should move the app folder to a different location.
:::
### Generate a Signing Key Pair
In order to later ship updates, we need our application to be signed so that the auto updater can verify the integrity of the updates. Hence, we need to generate a signing key pair:
```sh frame="none"
cargo packager signer generate
```
After setting a password, you will see two keys generated: a private key and a public key. The private key will be used to sign the updates, and the public key will be used to verify the updates. The private key should be kept secret and not shared with anyone.
In order to sign the updates, we need to set the private key and its password as environment variables. Run the following commands to do so for the current terminal session:
```sh frame="none"
export CARGO_PACKAGER_SIGN_PRIVATE_KEY=YOUR_PRIVATE_KEY
```
```sh frame="none"
export CARGO_PACKAGER_SIGN_PRIVATE_KEY_PASSWORD=YOUR_PASSWORD
```
You will need the public key later when setting up the auto updater in the app.
## Add the App to Your CrabNebula Cloud Organization
Go to [crabnebula.cloud](https://crabnebula.cloud) and sign-in with your GitHub or GitLab account. You will be asked to [set up an organization](/cloud#set-up-an-organization) and to [create your app](/cloud#create-an-application).
Call it **Super-Slint-App** and leave the generated slug as is. You will then need to select `packager` as application type. Make sure to note the organization slug and the app slug as you will need them later. Finally you'll have it as the image below.

After creating the app, you will be redirected to the app's [application overview page](/cloud/org-management/application-pages/#application-overview-page). Here you can adjust the app's metadata, such as the website, description, and repo link. For now we will focus on creating an initial release. Start by clicking on _Create release_ in the releases section which will show us some of the commands we need to run.
Before we can execute the commands, we need to [download the Cloud CLI](https://web.crabnebula.cloud/crabnebula/cn-cli/releases). Make sure that the CLI is executable and available in your PATH. Additionally, the binary should be named `cn`. Should you need assistance with this, please refer to the [CLI installation guide](/cloud/cli/install/#install-the-cli).
Confirm that the CLI is installed by checking the CLI version:
```sh frame="none"
cn --version
```
:::note
The minimum required version of the CLI is `0.6.0`.
:::
### Generate an API key
Now we will need to generate an API key which has read and write access to the app and allows the CLI to be authenticated. To achieve this, the key will be set as an environment variable for the CLI to use. Generate the key by clicking _New_, set a name, expiry date and the necessary read/write scope and then copy the command which should include your key. Run the command in your terminal to set the key as an environment variable for the current terminal session:
```sh frame="none"
export CN_API_KEY=YOUR_API_KEY
```

### Draft a new release
Make sure that your terminal context is in the app's root folder and draft a new release:
```sh frame="none"
cn release draft YOUR_ORG_SLUG/YOUR_APP_SLUG --framework packager
```
Make sure to replace `YOUR_ORG_SLUG` with the organization's slug. While for `YOUR_APP_SLUG` be sure to use `super-slint-app` as that was the application slug created in a previous step.
The relevant release info will be extracted from the app's `Cargo.toml` file automatically and you should see a JSON response with the release's ID and the line `"version": "2.0.0"`.
### Include Auto Updater and Version
Open the `src/main.rs` file and add the following code to include the auto updater:
Include the following imports at the top of the file:
```rust frame="none"
use cargo_packager_updater::{semver::Version, url::Url};
```
Add the following code at the beginning of the `main` function:
```rust frame="none"
let config = cargo_packager_updater::Config {
endpoints: vec![Url::parse("https://cdn.crabnebula.app/update/YOUR_ORG_SLUG/YOUR_APP_SLUG/{{target}}-{{arch}}/{{current_version}}").expect("Failed to parse URL")], // REPLACE: YOUR_ORG_SLUG and YOUR_APP_SLUG of the app in CN Cloud
pubkey: String::from("YOUR_PUBLIC_KEY"), // REPLACE: YOUR_PUBLIC_KEY generated by the signer
..Default::default()
};
let current_version =
Version::parse(env!("CARGO_PKG_VERSION")).expect("Failed to parse version");
println!("Current version: {}", current_version);
if let Some(update) = cargo_packager_updater::check_update(current_version.clone(), config)
.expect("Failed to check for update")
{
update
.download_and_install()
.expect("Failed to download and install update");
println!("Update installed")
} else {
println!("No update available")
}
```
Make sure to replace `YOUR_ORG_SLUG`, `YOUR_APP_SLUG` and `YOUR_PUBLIC_KEY` with the respective values. This tells the app to check for updates at the specified URL and to verify the updates with the public key.
In order to later verify the version of the app we want to display it in the app window. Add the following line after the initialization of the `ui` object in the `main` function (after `let ui = AppWindow::new()?;`):
```rust frame="none"
ui.set_app_version(current_version.to_string().into());
```
Now open `ui/appwindow.slint` and add the following property at the top of the `AppWindow` component:
```txt
in property app_version: "0.0.0";
```
Then add the following code at the top of the `VerticalBox` to display the version in the window:
```txt
Text {
text: "App Version: \{root.app_version}";
}
```
### Build and Upload Release Assets
To build the release assets, execute packager:
```sh frame="none"
cargo packager --release
```
Since we have set the `before-packaging-command` key in the `Cargo.toml` file to `cargo build --release`, the app will be built before packaging. The release assets will be generated in the `target/release` folder.
Copy the Cargo.toml file temporarily to the `target/release` folder and navigate there:
```sh frame="none"
cp Cargo.toml target/release && cd target/release
```
Now you can upload the release assets to the draft release:
```sh frame="none"
cn release upload YOUR_ORG_SLUG/YOUR_APP_SLUG --framework packager
```
Afterwards you should see them appearing in the Assets section of the release page on CrabNebula Cloud.
### Publish Release
Now you can go ahead and publish the release:
```sh frame="none"
cn release publish YOUR_ORG_SLUG/YOUR_APP_SLUG --framework packager
```
In CN Cloud, if you go back to the app's [application overview page](/cloud/org-management/application-pages/#application-overview-page), you will see the published release. Make the app public by clicking on the _Make it public_ button in the Danger zone at the bottom of the page.
Now users will be able to download the app from the app's public [market page](/cloud/org-management/application-pages/#application-market-page) (linked at the top of the overview page) on CrabNebula Cloud.
## Test the Auto Updater
To test the auto updater, you can decrement the version in the `Cargo.toml` file to `1.0.0` to simulate an older version. Afterwards we need to clear the `target/release` folder and rerun the packager:
```sh frame="none"
rm -rf target/release/* && cargo packager --release
```
Navigate to `target/release` and run the app. You should see the app window with the version `1.0.0` displayed. The app will check for updates and since an update is available (our initial `2.0.0` version), it will download and install it in the background.
If you restart the app you should see the updated version `2.0.0` displayed in the app window.

# Tauri with GitHub Actions
import { Tabs, TabItem } from "@astrojs/starlight/components";
This guide will walk you through creating a [Tauri](https://tauri.app) app from scratch and setting up a release workflow that leverages CrabNebula Cloud from a GitHub Action. This enables you to automatically build and release your app to CrabNebula Cloud every time you push to `main` and to trigger it manually whenever convenient. Cloud is a great way to distribute your app to your users, providing:
- Global asset distribution resulting in faster downloads.
- [Automatic application updates](/cloud/guides/auto-updates-tauri): CrabNebula Cloud has **first-class integration** with the Tauri updater to ensure secure delivery of updates automatically to your users.
- Nightly application builds/prerelease versions: with this GitHub action, you can ship different application versions to your users, including pre-release variants for staging/trial purposes.
## Requirements
To follow this guide you will need:
- Rust and Node.js **installed** on your machine
- [CrabNebula Cloud](https://crabnebula.dev/cloud) account
- [GitHub](https://github.com) account
## Create Your App and Upload to GitHub
The first step is to have an app which can be as complex or simple as you wish. If you're not sure where/how to begin, [Tauri](https://tauri.app) is a great place to start. The [Tauri docs](https://tauri.app/start/prerequisites/) list multiple ways of getting started and preparing your app with your Web Framework of choice. Additionally, there are multiple community based templates which can be found in the [Awesome Tauri repository](https://github.com/tauri-apps/awesome-tauri) and at Tauri's Discord _#showcase_ channel.
For this guide we will create a new Tauri app. Start from scratch by running the following command:
```sh frame="none"
npm create tauri@latest
```
You will be taken through a series of questions to set up your app. If you are unsure about an option, stick to the default settings. In the context of this guide we will call our app `super-tauri-app`. When it comes to choosing a package manager, choose `npm` as it is the package manager we adapted the following GitHub Actions workflow for.
Once the app is created, you will see a new directory with the app's name. Change into that directory and you wil find the typical folder structure of a Tauri app.
Now we need to make some minor configuration changes to the app. Edit `src-tauri/tauri.conf.json` and change the `version` in the `package` section to `0.1.0`. Also, modify the `identifier` in the `bundle` section to match your app's name and organization. See the following configuration snippets for reference.
```json frame="none"
"package": {
"productName": "super-tauri-app",
"version": "0.1.0"
},
```
```json frame="none"
"bundle": {
"active": true,
"targets": "all",
"identifier": "demo.super-tauri-app",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
```
:::tip
Now you can directly test out your newly ceated app by running the following command:
```sh frame="none"
npm install && npm exec tauri dev
```
You should see a window pop up with your app running.
:::
Finally initialize a new Git repository which you will then have to push to GitHub. If you are not familiar with the process, check out the [GitHub docs](https://docs.github.com/en/migrations/importing-source-code/using-the-command-line-to-import-source-code/adding-locally-hosted-code-to-github#initializing-a-git-repository).
## Set up your app in CrabNebula Cloud
After your app is uploaded to your GitHub repo, head over to [CrabNebula Cloud](https://crabnebula.cloud) and sign-in with your GitHub account. You will be asked to [set up an organization](/cloud#set-up-an-organization) and to [create your app](/cloud#create-an-application).

Now it's time to prepare an API key for your GitHub Action. In the organizaion navigation on the top right, click on the **API keys** tab and then on **New API key**.

Make sure that you enable Read/Write permissions for the API key. Also note that this key will only be shown once, so make sure to save it for the next step.
:::tip
Remember to fill in the application's description, website and repo on the [application overview page](/cloud/org-management/application-pages/#application-overview-page). This will be shown on the application's [public market page](/cloud/org-management/application-pages/#application-market-page) and will create a better experience for your users.
:::
## Add Cloud API Key to GitHub repo
With the CrabNebula Cloud application set up, it's time to add the necessary secrets to your GitHub repository. In GitHub go to your repository settings, and click on the **Secrets and variables** tab in the sidebar and then choose the **Actions** tab right underneath.

:::danger
Environment Secrets will show in your logs as plain text. Add your tokens as **repository secrets**.
:::
Now add a secret called `CN_API_KEY` to the **Repository Secrets** and paste your previously generated CrabNebula Cloud API key. If you have any issues creating or updating the secrets, you can check out the [GitHub documentation](https://docs.github.com/en/actions/reference/encrypted-secrets).
### GitHub Action Setup
:::tip
For more information on how to set up your CI for Cloud with GitHub Actions and tailored workflows for other application types, check out our [CI section](/cloud/ci/overview).
:::
Now we are ready to set up the GitHub Action that will build and release your app to CrabNebula Cloud. In your GitHub repository, create a new directory `.github/workflows` and add a new file called `release.yml`. Alternatively you can create a new workflow via the GitHub GUI.
```text
.github/
└── workflows/
└── release.yml
```
The `release.yml` is where we are going to add our GitHub Action code. The first block will determine the name and triggers for this action. We want to release automatically everytime `main` is updated, but it's also possible to manually trigger the workflow and to define on-the-fly which app we are working with. The `env` block will set the app slug to the input value or the default value if not provided. Adjust your app slug accordingly.
```yaml title="release.yml"
name: "Publish Release"
on:
push:
branches:
- main
workflow_dispatch:
inputs:
application:
description: "The fully qualified slug of your app on CrabNebula Cloud"
required: true
default: "my-org/super-tauri-app"
env:
CN_APPLICATION: ${{ github.event.inputs.application || 'my-org/super-tauri-app' }}
```
The `concurrency` block will prevent multiple releases from happening at the same time.
```yaml title="release.yml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
```
Time to define the actual build jobs. We will name them, give them write permissions, and establish a matrix of environments they will run on. The environments will determine which platforms our app will be built for, in this example we're selecting all desktop platforms supported by Tauri (MacOS, Linux, and Windows).
First, we create a [release draft](/cloud/cli/create-draft/) job. Thanks to `crabnebula-dev/cloud-release` we just need to call the release command and pass the `api-key` secret we previously set.
```yaml title="release.yml"
jobs:
draft:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
With a draft done, the task can move on to actually build the app. Let's make sure the dependency is explicit in our workflow and establish the strategy and matrix for this pipeline.
```yaml title="release.yml"
build:
needs: draft
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
```
The above snippet ensures we're building respectively for Linux, MacOS, and Windows, but only after the **draft** job is concluded. The steps will be the same for all platforms and so we can define them only once:
```yaml title="release.yml"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.1
- name: build tauri app
run: |
npm ci
npm exec tauri build
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
path: ./src-tauri
```
With the builds successfully concluded and the [build assets uploaded to CrabNebula Cloud](/cloud/cli/upload-assets/), we can trigger the publishing workflow. This will run only in `ubuntu-latest` since we don't need the multi-system matrix for this task. And it will have only one step, calling the [`release publish`](/cloud/cli/publish-release/) command from the `crabnebula-dev/cloud-release` action.
```yaml title="release.yml"
publish:
needs: build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
With this, our code is ready to be deployed to [CrabNebula Cloud](https://crabnebula.dev/cloud). Merging to `main` will trigger the release and in a few minutes your app will have the correct binaries built and a public changelog including ready-to-share download links available.
Check the complete code snippet for the GitHub Action workflow below:
```yaml title="release.yml"
name: Publish Release
on:
push:
branches:
- main
workflow_dispatch:
inputs:
application:
description: "The fully qualified slug of your app on CrabNebula Cloud"
required: true
default: "my-org/super-tauri-app"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CN_APPLICATION: ${{ github.event.inputs.application || 'my-org/super-tauri-app' }}
jobs:
draft:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: create draft release
uses: crabnebula-dev/cloud-release@v0
with:
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
build:
needs: draft
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Install stable toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
cache: true
- name: install Linux dependencies
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.1
- name: build tauri app
run: |
npm ci
npm exec tauri build
- name: upload assets
uses: crabnebula-dev/cloud-release@v0
with:
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
path: ./src-tauri
publish:
needs: build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: publish release
uses: crabnebula-dev/cloud-release@v0
with:
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
api-key: ${{ secrets.CN_API_KEY }}
```
## Testing the GitHub Action
Just by committing and pushing to `main` you will trigger the GitHub Action. You can also manually trigger the workflow by going to the Actions tab in your repository and selecting the workflow you want to run. You will be prompted to enter the app slug, which you can leave unmodified if you want to use the default value.
After you trigger the workflow, you can check the progress in the Actions tab on GitHub. If everything goes well, you will see a new release in your CrabNebula Cloud [Application Overview Page](/cloud/org-management/application-pages/#application-overview-page). You can check the release status and download the binaries from the [Releases](/cloud/org-management/application-pages/#releases) tab.
Choose the right format for your platform, download the binary and run it. Now in order to test the automatic release process, make a change to your app, adjust the version number in `src-tauri/tauri.conf.json` and push the changes to `main`. After a few minutes, you will see a new release in CrabNebula Cloud.
For example you could change the _Welcome to Tauri!_ heading in `index.html` and version number in `src-tauri/tauri.conf.json` to `0.1.1`.
After pushing and letting the CI pipeline finish, redownload the app from CrabNebula Cloud and you should see the updated heading.
## Final Thoughts
With this setup, you can now have your app automatically built and released to [CrabNebula Cloud](https://crabnebula.dev/cloud). This is a great way to keep your app up-to-date and easily shareable with your users. If you have any issues, feel free to reach out at the [CrabNebula Discord](https://discord.gg/W2MNdXVgjD) or the [Tauri Discord](https://discord.gg/tauri).
# Application Pages
This section provides an overview of the two application pages in CrabNebula Cloud: the private [application overview page](#application-overview-page) and the public [application market page](#application-market-page).
## Application Overview Page
The overview page of an application allows you to manage the application and its releases.
At the very top right you can catch a glimpse of the applications status which includes:
- Asset count
- Download count
- Visibility: Either _public_ or _private_
If the application is public, a link to the market page is also provided just beneath the applications title.
The application overview page is divided into the following sections:
### Get Started
Depending on what kind of application type you configured when creating the application, you will see a different set of tiles at the top of the page. This section is meant to provide you with a quick overview of steps you can take to get the most out of CrabNebula Cloud.
#### Releasing
For example, depending on whether you want to create a release manually or automate the process, you can choose between the following options:
- **Publish Manually**: If you want to create a release manually, you will be taken to a step by step guide with the commands outlined in the release process. For further in-depth explanations, you can follow the steps described in the Release Process starting with the [Create a Release](/cloud/cli/create-draft) page.
- **Setup your CI/CD**: If you want to automate the release process, the tile will take you to the [Continuous Integration section](/cloud/ci/overview) of this documentation.
#### Share your Application
Once you [published a release](/cloud/cli/publish-release), you will be able to share your application with end users. CrabNebula Cloud allows you generate a download button which can be embedded into any website and detects the users OS to provide the correct download link for the respective asset.
After clicking on the _Share your app_ tile, you are prompted to complete the applications metadata and description. Once you have done that, you will have to make the entire application public, so that it can be accessed by end users and a market page is created.
Afterwards you just need to select the respective asset for each OS.
:::note
Your asset filename or public platform must be stable across releases!
:::
CrabNebula Cloud will provide you with a code snippet that you can embed in your website to allow users to download your application directly from your website. We provide templates for Vanilla CSS and Tailwind CSS.
#### Tauri Updater
If you created a [Tauri app](https://tauri.app/), a tile which shows you how to configure Tauri updater is shown.
You will need to generate signing keys first. CrabNebula Cloud provides you with a configuration snippet where you have to insert your public key. Include this snippet in your `src-tauri/tauri.conf.json` file.
For more information on how to use the updater, see the [Tauri updater](https://tauri.app/plugin/updater/) docs.
:::tip
Should you be new to Tauri, get started right away by clicking on the _Bootstrap you application_ tile which shows you [how to build your first Tauri application](https://tauri.app/start/prerequisites/).
:::
### About
This section includes the following information:
- **Description**: Used on the Market page for public applications. Supports markdown styling which can be previewed from the Web UI.
- **Website**: A link to the application's website.
- **Repository**: A link to the application's repository.
### Releases
The releases section consists of a list of drafts and published releases of the app. For starting of with a new release click the button at the top right of the page.
Clicking on an existing release will take you to the an overview page where you can manage the release, download the release assets and delete the release if it has not been published yet.
### Danger Zone
Here you are able to delete the application or change its visibility.
:::note
Changes to the visibility of an application will affect the visibility of the market page. If an application is made private after being public, the market page will no longer display the applications metadata. However, the market page will still provide download options for users who have the direct asset links or CDN URLs.
:::
:::danger
Deletions are permanent and cannot be reversed.
Deleting an application will also delete all of its releases and assets.
:::
## Application Market Page
When an application is set to public, the market page for end users is created. It provides users with information about the application and gives them the ability to download the application.
### Downloads
In the left sidebar users see a downloads section which matches the OS bundle types with the current user's operating system:
- **Linux users** see a button for `deb`, `rpm`, `appimage` or `pacman` bundles.
- **macOS users** have a button for `.dmg` files.
- **Windows users** see `nsis` or `wix` installers.
:::note
The format for _Tauri_ and _cargo-packager_ applications is `$bundle-$arch` where `$bundle` is one of `deb`, `rpm`, `appimage`, `pacman`, `dmg`, `nsis` and `wix` and `$arch` is either `x86_64` or `aarch64`.
:::
:::tip
For applications with custom public platform formats, we also display a dedicated download button if the public_platform starts with `linux`, `darwin`, `macos`, or `windows`.
:::
Below the download section users see information about the latest release of the app including the version number and release date.
### Description
On the right side of the page, users can see the applications description in rendered Markdown styling and the applications metadata. This includes the applications website and repository.
# Billing & Usage
On this page you can find information on managing your CrabNebula Cloud usage, fair-use policies, and invoices. Since June 19th, CrabNebula Cloud is free for everyone, with advanced features unlocked at no cost.
:::tip[Welcome to Free]
CrabNebula Cloud is now free for everyone. There are no monthly fees, no subscription tiers, and no credit card required to start using the platform.
:::
We removed the paywall so you can focus on building. For details on how this works and the limits that keep the system fast for everyone, read on.
## How It Works Now
Unlike before, there are no subscription plans to select. Every account automatically receives our top-tier features—including advanced insights and full [DevTools](/cloud/org-management/invite-member/#devtools-access) access—starting immediately.
You only need to worry about billing if:
1. You are a large-scale user whose traffic significantly exceeds standard patterns.
2. You specifically request a custom enterprise arrangement.
If neither of these applies to you, you can skip straight to the **Usage** section below.
## Usage Guidelines
To ensure the platform remains fast and reliable for the entire Tauri community, we apply two simple fair-use rules. These are designed to prevent abuse, not to limit normal development work.
:::note[Storage Cleanup]
**Inactive releases are cleaned up.** A release that sees no downloads for 90 days will be removed to save space. However, your *latest* release on every channel is always protected. This rule starts counting on **July 1st**, meaning no deletions will occur before the end of September.
:::
:::caution[Traffic Limits]
**High-traffic patterns are monitored.** We don't set a fixed number for downloads, but we watch for traffic that is well outside ordinary usage (e.g., sudden, massive spikes). If your account crosses into this zone, we will contact you first to discuss what we're seeing before taking any action like throttling.
:::
If your project is growing and you anticipate pushing past these standard limits, please [contact us](https://crabnebula.dev/contact/) so we can work out a custom arrangement that fits your scale.
### What Happens If You Hit Limits?
In the rare event that you exceed fair use, we won't cut you off without warning. Our process is:
1. **Notification:** We contact you to explain the traffic or storage anomaly.
2. **Discussion:** We talk through your usage patterns.
3. **Resolution:** We either adjust your specific case or move you to a tailored enterprise plan.
For 99% of users, these limits will never be an issue.
## Billing Details
Since the service is free, most users will never see a billing page. However, if you have an existing paid account transitioning to the new model, or if you require a custom plan, here is how billing works.
### No Credit Card Required
You do **not** need to enter payment details to create an account, upload releases, or use DevTools. The barrier to entry has been removed.
### Invoices
Even though the service is free, you may still need invoices for internal accounting records or for custom enterprise arrangements.
- If you have a custom plan, all invoices will appear at the bottom of your dashboard.
- You can download them as PDF by clicking the button next to each entry.
:::note[Legacy Accounts]
If you were previously on a paid plan, your subscription has been converted to the free tier automatically. You will receive a confirmation email regarding your billing changes, but no further action is required on your part.
:::
## Frequently Asked Questions
### Do I need to cancel my old subscription?
No. On **June 19th**, all accounts were automatically upgraded to the free tier. Your existing subscription was cancelled on our end, and you will no longer be charged. Check your email for a final billing notification confirming this change.
### Is the "Open Source Plan" still available?
Yes, but in a different way. Previously, open-source projects could apply for special discounts. Now, *everyone* gets those benefits for free. You don't need to apply; the plan is active by default.
### What if I'm a huge company with millions of downloads?
We love seeing Tauri scale! If your usage is far beyond typical developer needs (think millions of updates per day), please reach out via our [contact form](https://crabnebula.dev/contact/). We'd love to build a partnership that supports your specific infrastructure needs.
### Can I still get support?
Absolutely. Whether you are a solo developer or a large team, our support channels remain open. If you encounter issues with your builds or the platform, just let us know.
# Create API Key
An API key is used to authenticate to the Cloud Platform when using the [CLI](/cloud/cli/install). To create an API key:
1. Open "Settings" in the Cloud Platform.
2. Select "New API key".
3. Give the key a name, an expiration, and select the scope. A "Read, write" scope is required for creating drafts, uploading assets, and publishing releases from the CrabNebula Cloud CLI.
# Member Management
Organizations allow you to collaborate with others on your applications. In order to achieve this you can invite anyone to become a member of your organization via email.
There are two types of roles with different permissions:
- **Member**
- Ability to edit applications (includes deleting them and changing their visibility)
- Ability to create new applications within the organization
- **Admin**
- Includes all of the permissions of a _member_
- Ability to modify the organization's members, settings, and billing
After you [created an organization](/cloud/#set-up-an-organization), go to the _Members_ section in the _Organization_ menu. You will see all the current members including their roles as well as the pending member invitations below.
Click the _Invite new member_ button at the top right and enter the email address and choose the role of the person you want to invite. After confirming, the user will receive an email with a link to accept the invitation.
:::note
Invitations are valid for 7 days and can be revoked during that time from the _Pending Invitations_ section. Should you need to resend the invitation email, you can do so from here as well.
:::
If the user does not have a CrabNebula Cloud account yet, they will be prompted to sign up with GitHub before accepting the invitation.
## Modifying Members
If you are an admin of the organization, you can modify its members. This includes changing their role and removing them from the organization.
To achieve this, go to the _Members_ section in the _Organization_ menu. At the top you will see a list of all the current members followed by pending member invitations. Here you can change the role of a member or remove them from the organization at any time.
### DevTools Access
DevTools Premium is an enhanced version of [DevTools](https://crabnebula.dev/devtools/). Every member of your organization can be granted access to DevTools Premium individually, at no cost — it is included for everyone on CrabNebula Cloud.
Below the members list there is a _DevTools Seats_ section where you can find the list of members that has a DevTools seat assigned.
In the _Search Members without seats_ input you can select the members to grant access to DevTools Premium. After assigning the seat, members will be able to sign in to DevTools Premium with their CrabNebula Cloud account.
# Architecture
At the time of writing, we currently do not offer a publicly available architecture diagram. While we work to develop
one that is accessible without requiring significant investment from the team as things evolve, we've chosen to
highlight some of the key systems involved.
import { Image } from "astro:assets";
## Cloud Providers
Cloud providers underpin most software as a service offerings today. When developing the cloud, we chose to leverage
Amazon Web Services (AWS) as our control plane and Cloudflare as our edge (or data) plane.
import aws from "@assets/cloud/architecture/aws.svg";
import cloudflare from "@assets/cloud/architecture/cloudflare.svg";
## Notable Open-Source Projects
Like most companies out there, much of our operations stack is composed of open source tooling. This includes
everything from our certificate management system, to our network mesh, and metrics store.
import kubernetes from "@assets/cloud/architecture/kubernetes.svg";
import certManager from "@assets/cloud/architecture/cert-manager.svg";
import linkerd from "@assets/cloud/architecture/linkerd.svg";
import ory from "@assets/cloud/architecture/ory.png";
import loki from "@assets/cloud/architecture/loki.svg";
import grafana from "@assets/cloud/architecture/grafana.svg";
import grafanaTempo from "@assets/cloud/architecture/grafana-tempo.svg";
import prometheus from "@assets/cloud/architecture/prometheus.svg";
import traefik from "@assets/cloud/architecture/traefik.svg";
## Languages
Finally, the services that we write and deploy are written using one of two languages. Rust is used to write and deploy
several of our backend services including our authentication and billing systems. NodeJS is used for our web and any
Cloudflare Worker processes. Some of our Cloudflare Workers may eventually be written in Rust as that integration becomes
more supported.
import rust from "@assets/cloud/architecture/rust.png";
import nodeJs from "@assets/cloud/architecture/nodejs.svg";
# Third-Party Libraries
Most software today leverages open source software to some extent. In the table found below, you will find the various
third-party software libraries that were used to help develop our private platform. This table also includes which
version of the software was used, as well as the license associated with that piece of software.
This table is periodically generated using the SBOM export from GitHub's Dependency Graph (found under insights). The
downloaded JSON file is then passed through `spdx-fmt` to render the table.
### GitHub Actions
| Library | Version | License |
| ------------------------------------------------ | ------------------------------------------ | ------- |
| `actions:1password/install-cli-action` | `143a85f84a90555d121cde2ff5872e393a47ab9f` | `` |
| `actions:1password/load-secrets-action` | `1.*.*` | `` |
| `actions:AnimMouse/setup-rclone` | `1a535c480a89e3990d2a0015ea21f6fa3eb1fdc4` | `` |
| `actions:Swatinem/rust-cache` | `2.*.*` | `` |
| `actions:actions-rust-lang/setup-rust-toolchain` | `1.*.*` | `` |
| `actions:actions/cache` | `4.*.*` | `` |
| `actions:actions/cache` | `3.*.*` | `` |
| `actions:actions/checkout` | `4.*.*` | `` |
| `actions:actions/checkout` | `3.*.*` | `` |
| `actions:actions/download-artifact` | `4.*.*` | `` |
| `actions:actions/github-script` | `7.*.*` | `` |
| `actions:actions/setup-node` | `3.*.*` | `` |
| `actions:actions/setup-node` | `4.*.*` | `` |
| `actions:actions/upload-artifact` | `4.*.*` | `` |
| `actions:amannn/action-semantic-pull-request` | `5.*.*` | `` |
| `actions:ataylorme/eslint-annotate-action` | `3.*.*` | `` |
| `actions:aws-actions/amazon-ecr-login` | `1.*.*` | `` |
| `actions:aws-actions/configure-aws-credentials` | `2.*.*` | `` |
| `actions:cloudflare/wrangler-action` | `3.*.*` | `` |
| `actions:crabnebula-dev/codesign-action` | `main` | `` |
| `actions:docker/build-push-action` | `4.*.*` | `` |
| `actions:docker/metadata-action` | `4.*.*` | `` |
| `actions:docker/setup-buildx-action` | `2.*.*` | `` |
| `actions:dorny/paths-filter` | `3.*.*` | `` |
| `actions:hoverkraft-tech/compose-action` | `2.0.1` | `` |
| `actions:mamezou-tech/setup-helmfile` | `03233e1cd9b19b2ba320e431f7bcc0618db4248d` | `` |
| `actions:mshick/add-pr-comment` | `2.*.*` | `` |
| `actions:pascalgn/automerge-action` | `0.16.3` | `` |
| `actions:peter-evans/create-pull-request` | `c5a7806660adbe173f04e3e038b0ccdcd758773c` | `` |
| `actions:pnpm/action-setup` | `4.*.*` | `` |
| `actions:rustsec/audit-check` | `2.0.0` | `` |
### JavaScript
| Library | Version | License |
| ------------------------------------- | ---------------- | -------------- |
| `npm:@chargebee/chargebee-js-types` | `^ 1.0.1` | `` |
| `npm:@cloudflare/vitest-pool-workers` | `0.4.26` | `MIT` |
| `npm:@cloudflare/workers-types` | `^ 4.20231121.0` | `` |
| `npm:@fabien0102/tailwind-aria` | `^ 1.0.0` | `` |
| `npm:@felte/common` | `^ 1.1.8` | `` |
| `npm:@felte/reporter-tippy` | `^ 1.1.9` | `` |
| `npm:@felte/solid` | `^ 1.2.13` | `` |
| `npm:@kobalte/core` | `^ 0.13.3` | `` |
| `npm:@kobalte/tailwindcss` | `^ 0.9.0` | `` |
| `npm:@microlabs/otel-cf-workers` | `1.0.0-rc.45` | `BSD-3-Clause` |
| `npm:@opentelemetry/api` | `1.9.0` | `Apache-2.0` |
| `npm:@ory/keto-namespace-types` | `0.11.1-alpha.0` | `` |
| `npm:@rspc/client` | `0.2.4` | `MIT` |
| `npm:@rspc/solid-query` | `^ 0.2.4` | `` |
| `npm:@serenity-js/assertions` | `^ 3.25.1` | `` |
| `npm:@serenity-js/console-reporter` | `^ 3.25.1` | `` |
| `npm:@serenity-js/core` | `^ 3.25.1` | `` |
| `npm:@serenity-js/mocha` | `^ 3.25.1` | `` |
| `npm:@serenity-js/rest` | `^ 3.25.1` | `` |
| `npm:@serenity-js/serenity-bdd` | `^ 3.25.1` | `` |
| `npm:@serenity-js/web` | `^ 3.25.1` | `` |
| `npm:@serenity-js/webdriverio` | `^ 3.25.1` | `` |
| `npm:@solid-primitives/script-loader` | `^ 2.2.0` | `` |
| `npm:@solid-primitives/storage` | `^ 2.1.4` | `` |
| `npm:@solidjs/router` | `^ 0.14.1` | `` |
| `npm:@solidjs/testing-library` | `^ 0.8.8` | `` |
| `npm:@tanstack/solid-query` | `^ 5.51.2` | `` |
| `npm:@tanstack/solid-query-devtools` | `^ 5.51.2` | `` |
| `npm:@tanstack/solid-table` | `^ 8.19.3` | `` |
| `npm:@testing-library/jest-dom` | `^ 6.4.6` | `` |
| `npm:@types/hast` | `^ 3.0.4` | `` |
| `npm:@types/jest` | `^ 29.5.11` | `` |
| `npm:@types/jquery` | `^ 3.5.30` | `` |
| `npm:@types/js-cookie` | `^ 3.0.6` | `` |
| `npm:@types/mocha` | `^ 10.0.7` | `` |
| `npm:@types/node` | `^ 20.14.10` | `` |
| `npm:@vitest/runner` | `~> 1.5.0` | `` |
| `npm:@vitest/snapshot` | `~> 1.5.0` | `` |
| `npm:@wdio/cli` | `^ 8.39.1` | `` |
| `npm:@wdio/dot-reporter` | `^ 8.39.0` | `` |
| `npm:@wdio/globals` | `^ 8.39.1` | `` |
| `npm:@wdio/local-runner` | `^ 8.39.1` | `` |
| `npm:@wdio/spec-reporter` | `^ 8.39.0` | `` |
| `npm:@wdio/types` | `^ 8.39.0` | `` |
| `npm:autoprefixer` | `^ 10.4.19` | `` |
| `npm:case` | `^ 1.6.3` | `` |
| `npm:chromedriver` | `^ 123.0.4` | `` |
| `npm:clsx` | `^ 2.1.1` | `` |
| `npm:commander` | `^ 11.1.0` | `` |
| `npm:eslint` | `^ 8.57.0` | `` |
| `npm:eslint-plugin-solid` | `^ 0.14.1` | `` |
| `npm:eslint-plugin-tailwindcss` | `^ 3.17.4` | `` |
| `npm:glob` | `^ 10.3.10` | `` |
| `npm:hono` | `^ 4.5.0` | `` |
| `npm:jest` | `^ 29.7.0` | `` |
| `npm:jose` | `^ 4.15.5` | `` |
| `npm:jsdom` | `^ 22.1.0` | `` |
| `npm:mocha` | `^ 10.6.0` | `` |
| `npm:node-fetch` | `^ 3.3.2` | `` |
| `npm:npm-failsafe` | `^ 1.2.1` | `` |
| `npm:npm-run-all2` | `^ 5.0.0` | `` |
| `npm:postcss` | `^ 8.4.39` | `` |
| `npm:randomstring` | `^ 1.3.0` | `` |
| `npm:rehype-raw` | `^ 6.1.1` | `` |
| `npm:rehype-sanitize` | `^ 6.0.0` | `` |
| `npm:remark-gfm` | `3.0.1` | `MIT` |
| `npm:rimraf` | `^ 5.0.9` | `` |
| `npm:shiki` | `^ 1.10.3` | `` |
| `npm:solid-confetti-explosion` | `^ 1.1.8` | `` |
| `npm:solid-js` | `^ 1.8.18` | `` |
| `npm:solid-markdown` | `^ 2.0.13` | `` |
| `npm:tailwind-scrollbar` | `^ 3.1.0` | `` |
| `npm:tailwindcss` | `^ 3.4.4` | `` |
| `npm:tippy.js` | `^ 6.3.7` | `` |
| `npm:ts-jest` | `^ 29.1.1` | `` |
| `npm:ts-morph` | `^ 20.0.0` | `` |
| `npm:ts-node` | `^ 10.9.2` | `` |
| `npm:ts-pattern` | `^ 5.2.0` | `` |
| `npm:typescript` | `^ 5.3.3` | `` |
| `npm:ulidx` | `^ 2.2.1` | `` |
| `npm:vite` | `^ 5.4.7` | `` |
| `npm:vite-plugin-solid` | `^ 2.10.2` | `` |
| `npm:vitest` | `^ 1.6.0` | `` |
| `npm:vitest` | `1.5.3` | `MIT` |
| `npm:vitest-github-actions-reporter` | `^ 0.11.1` | `` |
| `npm:wrangler` | `^ 3.32.0` | `` |
| `npm:zod` | `^ 3.22.4` | `` |
### Rust
| Library | Version | License |
| ------------------------------------------------ | ------------------------------- | ------------------------------------------------------- |
| `rust:Inflector` | `0.11.4` | `BSD-2-Clause` |
| `rust:addr2line` | `0.22.0` | `Apache-2.0 OR MIT` |
| `rust:adler` | `1.0.2` | `0BSD AND Apache-2.0 AND MIT` |
| `rust:ahash` | `0.8.11` | `MIT OR Apache-2.0` |
| `rust:aho-corasick` | `1.1.3` | `Unlicense OR MIT` |
| `rust:allocator-api2` | `0.2.18` | `MIT OR Apache-2.0` |
| `rust:android-tzdata` | `0.1.1` | `MIT OR Apache-2.0` |
| `rust:android_system_properties` | `0.1.5` | `MIT OR Apache-2.0` |
| `rust:anstream` | `0.6.14` | `MIT OR Apache-2.0` |
| `rust:anstyle` | `1.0.7` | `MIT OR Apache-2.0` |
| `rust:anstyle-parse` | `0.2.4` | `MIT OR Apache-2.0` |
| `rust:anstyle-query` | `1.1.0` | `MIT OR Apache-2.0` |
| `rust:anstyle-wincon` | `3.0.3` | `MIT OR Apache-2.0` |
| `rust:anyhow` | `1.0.86` | `MIT OR Apache-2.0` |
| `rust:arrayref` | `0.3.7` | `BSD-2-Clause` |
| `rust:arrayvec` | `0.7.4` | `MIT OR Apache-2.0` |
| `rust:assert-json-diff` | `2.0.2` | `MIT` |
| `rust:async-channel` | `1.9.0` | `Apache-2.0 OR MIT` |
| `rust:async-once-cell` | `0.5.3` | `MIT OR Apache-2.0` |
| `rust:async-stream` | `0.3.5` | `MIT` |
| `rust:async-stream-impl` | `0.3.5` | `MIT` |
| `rust:async-trait` | `0.1.80` | `MIT OR Apache-2.0` |
| `rust:atomic` | `0.6.0` | `Apache-2.0 OR MIT` |
| `rust:atomic-waker` | `1.1.2` | `Apache-2.0 OR MIT` |
| `rust:autocfg` | `1.3.0` | `Apache-2.0 OR MIT` |
| `rust:axum` | `0.6.20` | `MIT` |
| `rust:axum` | `0.7.5` | `MIT` |
| `rust:axum-core` | `0.3.4` | `MIT` |
| `rust:axum-core` | `0.4.3` | `MIT` |
| `rust:axum-extra` | `>= 0.9.3,< 0.10.0` | `` |
| `rust:axum-extra` | `0.9.3` | `MIT` |
| `rust:axum-tracing-opentelemetry` | `0.18.1` | `CC0-1.0` |
| `rust:backtrace` | `0.3.73` | `MIT OR Apache-2.0` |
| `rust:base16ct` | `0.2.0` | `Apache-2.0 OR MIT` |
| `rust:base64` | `0.22.1` | `MIT OR Apache-2.0` |
| `rust:base64` | `0.13.1` | `MIT OR Apache-2.0` |
| `rust:base64` | `0.21.7` | `MIT OR Apache-2.0` |
| `rust:base64ct` | `1.6.0` | `Apache-2.0 OR MIT` |
| `rust:bitflags` | `1.3.2` | `MIT OR Apache-2.0` |
| `rust:bitflags` | `2.5.0` | `MIT OR Apache-2.0` |
| `rust:bitvec` | `1.0.1` | `MIT` |
| `rust:blake3` | `>= 1.4.1,< 2.0.0` | `` |
| `rust:blake3` | `1.5.1` | `CC0-1.0 OR Apache-2.0` |
| `rust:block-buffer` | `0.10.4` | `MIT OR Apache-2.0` |
| `rust:bson` | `2.11.0` | `MIT` |
| `rust:bumpalo` | `3.16.0` | `MIT OR Apache-2.0` |
| `rust:bytecount` | `0.6.8` | `Apache-2.0 OR MIT` |
| `rust:bytemuck` | `1.16.0` | `Zlib OR (Apache-2.0 OR MIT)` |
| `rust:byteorder` | `1.5.0` | `Unlicense OR MIT` |
| `rust:bytes` | `1.7.1` | `MIT` |
| `rust:bytes` | `>= 1.7.0,< 2.0.0` | `` |
| `rust:cc` | `1.0.99` | `MIT OR Apache-2.0` |
| `rust:cfg-if` | `1.0.0` | `Apache-2.0 OR MIT` |
| `rust:chrono` | `>= 0.4.0,< 0.5.0` | `` |
| `rust:chrono` | `0.4.38` | `MIT OR Apache-2.0` |
| `rust:chumsky` | `0.9.3` | `MIT` |
| `rust:clap` | `4.5.7` | `MIT OR Apache-2.0` |
| `rust:clap_builder` | `4.5.7` | `MIT OR Apache-2.0` |
| `rust:clap_derive` | `4.5.5` | `MIT OR Apache-2.0` |
| `rust:clap_lex` | `0.7.1` | `MIT OR Apache-2.0` |
| `rust:colorchoice` | `1.0.1` | `MIT OR Apache-2.0` |
| `rust:concurrent-queue` | `2.5.0` | `Apache-2.0 OR MIT` |
| `rust:const-oid` | `0.9.6` | `Apache-2.0 OR MIT` |
| `rust:constant_time_eq` | `0.3.0` | `CC0-1.0 OR (MIT-0 OR Apache-2.0)` |
| `rust:convert_case` | `0.4.0` | `MIT` |
| `rust:cookie` | `0.18.1` | `MIT OR Apache-2.0` |
| `rust:core-foundation` | `0.9.4` | `MIT OR Apache-2.0` |
| `rust:core-foundation-sys` | `0.8.6` | `MIT OR Apache-2.0` |
| `rust:cpufeatures` | `0.2.12` | `MIT OR Apache-2.0` |
| `rust:crossbeam-channel` | `0.5.13` | `MIT OR Apache-2.0` |
| `rust:crossbeam-utils` | `0.8.20` | `MIT OR Apache-2.0` |
| `rust:crossterm` | `0.25.0` | `MIT` |
| `rust:crossterm_winapi` | `0.9.1` | `MIT` |
| `rust:crypto-bigint` | `0.5.5` | `Apache-2.0 OR MIT` |
| `rust:crypto-common` | `0.1.6` | `MIT OR Apache-2.0` |
| `rust:curve25519-dalek` | `4.1.3` | `BSD-3-Clause` |
| `rust:curve25519-dalek-derive` | `0.1.1` | `MIT OR Apache-2.0` |
| `rust:darling` | `0.20.9` | `MIT` |
| `rust:darling` | `0.13.4` | `MIT` |
| `rust:darling_core` | `0.20.9` | `MIT` |
| `rust:darling_core` | `0.13.4` | `MIT` |
| `rust:darling_macro` | `0.20.9` | `MIT` |
| `rust:darling_macro` | `0.13.4` | `MIT` |
| `rust:dashmap` | `5.5.3` | `MIT` |
| `rust:data-encoding` | `2.6.0` | `MIT` |
| `rust:deadpool` | `0.9.5` | `MIT OR Apache-2.0` |
| `rust:deadpool-runtime` | `0.1.4` | `MIT OR Apache-2.0` |
| `rust:der` | `0.7.9` | `Apache-2.0 OR MIT` |
| `rust:deranged` | `0.3.11` | `MIT OR Apache-2.0` |
| `rust:derivative` | `2.2.0` | `Apache-2.0 AND MIT` |
| `rust:derive_more` | `0.99.17` | `MIT` |
| `rust:digest` | `0.10.7` | `MIT OR Apache-2.0` |
| `rust:dirs` | `>= 5.0.1,< 6.0.0` | `` |
| `rust:dirs` | `5.0.1` | `MIT OR Apache-2.0` |
| `rust:dirs-sys` | `0.4.1` | `MIT OR Apache-2.0` |
| `rust:displaydoc` | `0.2.4` | `MIT OR Apache-2.0` |
| `rust:document-features` | `0.2.8` | `MIT OR Apache-2.0` |
| `rust:dyn-clone` | `1.0.17` | `MIT OR Apache-2.0` |
| `rust:ecdsa` | `0.16.9` | `Apache-2.0 OR MIT` |
| `rust:ed25519` | `2.2.3` | `Apache-2.0 OR MIT` |
| `rust:ed25519-dalek` | `2.1.1` | `BSD-3-Clause` |
| `rust:either` | `1.12.0` | `MIT OR Apache-2.0` |
| `rust:elliptic-curve` | `0.13.8` | `Apache-2.0 OR MIT` |
| `rust:email-encoding` | `0.3.0` | `MIT OR Apache-2.0` |
| `rust:email_address` | `0.2.4` | `MIT` |
| `rust:encoding_rs` | `0.8.34` | `(Apache-2.0 OR MIT) AND BSD-3-Clause` |
| `rust:enum-as-inner` | `0.4.0` | `MIT OR Apache-2.0` |
| `rust:equivalent` | `1.0.1` | `Apache-2.0 OR MIT` |
| `rust:errno` | `0.3.9` | `MIT OR Apache-2.0` |
| `rust:event-listener` | `2.5.3` | `Apache-2.0 OR MIT` |
| `rust:fastrand` | `2.1.0` | `Apache-2.0 OR MIT` |
| `rust:fastrand` | `1.9.0` | `Apache-2.0 OR MIT` |
| `rust:ff` | `0.13.0` | `MIT OR Apache-2.0` |
| `rust:fiat-crypto` | `0.2.9` | `MIT OR Apache-2.0 OR BSD-1-Clause` |
| `rust:figment` | `0.10.19` | `MIT OR Apache-2.0` |
| `rust:fnv` | `1.0.7` | `Apache-2.0 AND MIT` |
| `rust:foreign-types` | `0.3.2` | `MIT OR Apache-2.0` |
| `rust:foreign-types-shared` | `0.1.1` | `MIT OR Apache-2.0` |
| `rust:form_urlencoded` | `1.2.1` | `MIT OR Apache-2.0` |
| `rust:funty` | `2.0.0` | `MIT` |
| `rust:futures` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:futures-channel` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:futures-core` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:futures-executor` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:futures-io` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:futures-lite` | `1.13.0` | `Apache-2.0 OR MIT` |
| `rust:futures-macro` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:futures-sink` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:futures-task` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:futures-timer` | `3.0.3` | `MIT OR Apache-2.0` |
| `rust:futures-util` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:futures-util` | `>= 0.3.30,< 0.4.0` | `` |
| `rust:generic-array` | `0.14.7` | `MIT` |
| `rust:getrandom` | `0.2.15` | `MIT OR Apache-2.0` |
| `rust:getrandom` | `0.1.16` | `MIT OR Apache-2.0` |
| `rust:gimli` | `0.29.0` | `MIT OR Apache-2.0` |
| `rust:glob` | `>= 0.3.0,< 0.4.0` | `` |
| `rust:glob` | `0.3.1` | `MIT OR Apache-2.0` |
| `rust:group` | `0.13.0` | `MIT OR Apache-2.0` |
| `rust:h2` | `0.3.26` | `MIT` |
| `rust:h2` | `0.4.5` | `MIT` |
| `rust:hashbrown` | `0.14.5` | `MIT OR Apache-2.0` |
| `rust:hashbrown` | `0.12.3` | `MIT OR Apache-2.0` |
| `rust:heck` | `0.4.1` | `MIT OR Apache-2.0` |
| `rust:heck` | `0.5.0` | `MIT OR Apache-2.0` |
| `rust:hermit-abi` | `0.3.9` | `MIT OR Apache-2.0` |
| `rust:hex` | `0.4.3` | `MIT OR Apache-2.0` |
| `rust:hex` | `>= 0.4.0,< 0.5.0` | `` |
| `rust:hex-literal` | `>= 0.4.1,< 0.5.0` | `` |
| `rust:hex-literal` | `0.4.1` | `MIT OR Apache-2.0` |
| `rust:hkdf` | `0.12.4` | `MIT OR Apache-2.0` |
| `rust:hmac` | `0.12.1` | `MIT OR Apache-2.0` |
| `rust:hostname` | `0.4.0` | `MIT` |
| `rust:hostname` | `0.3.1` | `MIT` |
| `rust:http` | `1.1.0` | `MIT OR Apache-2.0` |
| `rust:http` | `0.2.12` | `MIT OR Apache-2.0` |
| `rust:http-body` | `1.0.0` | `MIT` |
| `rust:http-body` | `0.4.6` | `MIT` |
| `rust:http-body-util` | `0.1.2` | `MIT` |
| `rust:http-serde` | `2.1.1` | `Apache-2.0 OR MIT` |
| `rust:http-serde` | `>= 2.1.0,< 3.0.0` | `` |
| `rust:http-types` | `2.12.0` | `MIT OR Apache-2.0` |
| `rust:httparse` | `1.9.3` | `MIT OR Apache-2.0` |
| `rust:httpdate` | `1.0.3` | `MIT OR Apache-2.0` |
| `rust:humantime` | `2.1.0` | `Apache-2.0 OR (Apache-2.0 AND MIT)` |
| `rust:hyper` | `1.3.1` | `MIT` |
| `rust:hyper` | `0.14.29` | `MIT` |
| `rust:hyper-rustls` | `0.24.2` | `Apache-2.0 OR (ISC OR MIT)` |
| `rust:hyper-rustls` | `0.26.0` | `Apache-2.0 OR (ISC OR MIT)` |
| `rust:hyper-timeout` | `0.4.1` | `Apache-2.0 OR MIT` |
| `rust:hyper-tls` | `0.6.0` | `MIT OR Apache-2.0` |
| `rust:hyper-tls` | `0.5.0` | `MIT OR Apache-2.0` |
| `rust:hyper-util` | `0.1.5` | `MIT` |
| `rust:iana-time-zone` | `0.1.60` | `MIT OR Apache-2.0` |
| `rust:iana-time-zone-haiku` | `0.1.2` | `MIT OR Apache-2.0` |
| `rust:icu_collections` | `1.5.0` | `Unicode-3.0` |
| `rust:icu_locid` | `1.5.0` | `Unicode-3.0` |
| `rust:icu_locid_transform` | `1.5.0` | `Unicode-3.0` |
| `rust:icu_locid_transform_data` | `1.5.0` | `` |
| `rust:icu_normalizer` | `1.5.0` | `` |
| `rust:icu_normalizer_data` | `1.5.0` | `` |
| `rust:icu_properties` | `1.5.0` | `` |
| `rust:icu_properties_data` | `1.5.0` | `Unicode-3.0` |
| `rust:icu_provider` | `1.5.0` | `Unicode-3.0` |
| `rust:icu_provider_macros` | `1.5.0` | `Unicode-3.0` |
| `rust:ident_case` | `1.0.1` | `MIT OR Apache-2.0` |
| `rust:idna` | `0.5.0` | `MIT OR Apache-2.0` |
| `rust:idna` | `1.0.0` | `MIT OR Apache-2.0` |
| `rust:idna` | `0.4.0` | `MIT OR Apache-2.0` |
| `rust:idna` | `0.2.3` | `MIT OR Apache-2.0` |
| `rust:indexmap` | `1.9.3` | `Apache-2.0 OR MIT` |
| `rust:indexmap` | `2.2.6` | `Apache-2.0 OR MIT` |
| `rust:indoc` | `1.0.9` | `MIT OR Apache-2.0` |
| `rust:infer` | `0.2.3` | `MIT` |
| `rust:inlinable_string` | `0.1.15` | `Apache-2.0 OR MIT` |
| `rust:inquire` | `0.6.2` | `MIT` |
| `rust:inquire` | `>= 0.6.0,< 0.7.0` | `` |
| `rust:instant` | `0.1.13` | `BSD-3-Clause` |
| `rust:ipconfig` | `0.3.2` | `MIT OR Apache-2.0` |
| `rust:ipnet` | `2.9.0` | `MIT OR Apache-2.0` |
| `rust:is_terminal_polyfill` | `1.70.0` | `MIT OR Apache-2.0` |
| `rust:itertools` | `0.10.5` | `MIT OR Apache-2.0` |
| `rust:itertools` | `0.12.1` | `MIT OR Apache-2.0` |
| `rust:itoa` | `1.0.11` | `MIT OR Apache-2.0` |
| `rust:js-sys` | `0.3.69` | `MIT OR Apache-2.0` |
| `rust:json-patch` | `1.4.0` | `MIT OR Apache-2.0` |
| `rust:json-patch` | `>= 1.2.0,< 2.0.0` | `` |
| `rust:jsonwebtoken` | `8.3.0` | `MIT` |
| `rust:lazy_static` | `1.4.0` | `Apache-2.0 AND MIT` |
| `rust:lettre` | `0.11.7` | `MIT` |
| `rust:lettre` | `>= 0.11.0,< 0.12.0` | `` |
| `rust:libc` | `0.2.155` | `MIT OR Apache-2.0` |
| `rust:libm` | `0.2.8` | `MIT OR Apache-2.0` |
| `rust:libredox` | `0.1.3` | `MIT` |
| `rust:linked-hash-map` | `0.5.6` | `MIT OR Apache-2.0` |
| `rust:linux-raw-sys` | `0.4.14` | `Apache-2.0 WITH LLVM-exception OR (Apache-2.0 OR MIT)` |
| `rust:litemap` | `0.7.3` | `` |
| `rust:litrs` | `0.4.1` | `` |
| `rust:lock_api` | `0.4.12` | `MIT OR Apache-2.0` |
| `rust:log` | `0.4.21` | `MIT OR Apache-2.0` |
| `rust:lru-cache` | `0.1.2` | `MIT OR Apache-2.0` |
| `rust:match_cfg` | `0.1.0` | `MIT OR Apache-2.0` |
| `rust:matchers` | `0.1.0` | `MIT` |
| `rust:matches` | `0.1.10` | `MIT` |
| `rust:matchit` | `0.7.3` | `MIT AND BSD-3-Clause` |
| `rust:md-5` | `0.10.6` | `MIT OR Apache-2.0` |
| `rust:md-5` | `>= 0.10.0,< 0.11.0` | `` |
| `rust:md5` | `>= 0.5.0,< 0.6.0` | `` |
| `rust:md5` | `0.5.0` | `Apache-2.0 OR MIT` |
| `rust:memchr` | `2.7.2` | `Unlicense OR MIT` |
| `rust:mime` | `0.3.17` | `MIT OR Apache-2.0` |
| `rust:mime_guess` | `2.0.4` | `MIT` |
| `rust:minimal-lexical` | `0.2.1` | `MIT OR Apache-2.0` |
| `rust:miniz_oxide` | `0.7.3` | `MIT OR (Zlib OR Apache-2.0)` |
| `rust:mio` | `0.8.11` | `MIT` |
| `rust:mongodb` | `2.8.2` | `Apache-2.0` |
| `rust:native-tls` | `0.2.12` | `MIT OR Apache-2.0` |
| `rust:newline-converter` | `0.2.2` | `MIT` |
| `rust:nom` | `7.1.3` | `MIT` |
| `rust:nu-ansi-term` | `0.46.0` | `MIT` |
| `rust:num-bigint` | `0.4.5` | `MIT OR Apache-2.0` |
| `rust:num-bigint-dig` | `0.8.4` | `MIT OR Apache-2.0` |
| `rust:num-conv` | `0.1.0` | `MIT OR Apache-2.0` |
| `rust:num-integer` | `0.1.46` | `MIT OR Apache-2.0` |
| `rust:num-iter` | `0.1.45` | `MIT OR Apache-2.0` |
| `rust:num-traits` | `0.2.19` | `MIT OR Apache-2.0` |
| `rust:num_cpus` | `1.16.0` | `MIT OR Apache-2.0` |
| `rust:oauth2` | `4.4.2` | `MIT OR Apache-2.0` |
| `rust:object` | `0.36.0` | `Apache-2.0 OR MIT` |
| `rust:once_cell` | `1.19.0` | `MIT OR Apache-2.0` |
| `rust:openidconnect` | `>= 3.5.0,< 4.0.0` | `` |
| `rust:openidconnect` | `3.5.0` | `MIT` |
| `rust:openssl` | `0.10.66` | `Apache-2.0` |
| `rust:openssl-macros` | `0.1.1` | `MIT OR Apache-2.0` |
| `rust:openssl-probe` | `0.1.5` | `MIT OR Apache-2.0` |
| `rust:openssl-sys` | `0.9.103` | `MIT` |
| `rust:opentelemetry` | `0.22.0` | `Apache-2.0` |
| `rust:opentelemetry` | `>= 0.22.0,< 0.23.0` | `` |
| `rust:opentelemetry-jaeger-propagator` | `0.1.0` | `Apache-2.0` |
| `rust:opentelemetry-otlp` | `0.15.0` | `Apache-2.0` |
| `rust:opentelemetry-prometheus` | `0.15.0` | `Apache-2.0` |
| `rust:opentelemetry-proto` | `0.5.0` | `Apache-2.0` |
| `rust:opentelemetry-semantic-conventions` | `0.14.0` | `Apache-2.0` |
| `rust:opentelemetry_sdk` | `0.22.1` | `Apache-2.0` |
| `rust:option-ext` | `0.2.0` | `MPL-2.0` |
| `rust:ordered-float` | `2.10.1` | `MIT` |
| `rust:ordered-float` | `4.2.0` | `MIT` |
| `rust:ory-hydra-client` | `2.2.0` | `Apache-2.0` |
| `rust:overload` | `0.1.1` | `MIT` |
| `rust:p256` | `0.13.2` | `Apache-2.0 OR MIT` |
| `rust:p384` | `0.13.0` | `Apache-2.0 OR MIT` |
| `rust:papergrid` | `0.10.0` | `MIT` |
| `rust:parking` | `2.2.0` | `Apache-2.0 OR MIT` |
| `rust:parking_lot` | `0.11.2` | `Apache-2.0 OR MIT` |
| `rust:parking_lot` | `0.12.3` | `MIT OR Apache-2.0` |
| `rust:parking_lot_core` | `0.8.6` | `Apache-2.0 OR MIT` |
| `rust:parking_lot_core` | `0.9.10` | `MIT OR Apache-2.0` |
| `rust:paste` | `1.0.15` | `MIT OR Apache-2.0` |
| `rust:pbkdf2` | `0.11.0` | `MIT OR Apache-2.0` |
| `rust:pear` | `0.2.9` | `MIT OR Apache-2.0` |
| `rust:pear_codegen` | `0.2.9` | `MIT OR Apache-2.0` |
| `rust:pem` | `1.1.1` | `MIT` |
| `rust:pem-rfc7468` | `0.7.0` | `Apache-2.0 OR MIT` |
| `rust:percent-encoding` | `2.3.1` | `MIT OR Apache-2.0` |
| `rust:pin-project` | `1.1.5` | `Apache-2.0 OR MIT` |
| `rust:pin-project-internal` | `1.1.5` | `Apache-2.0 OR MIT` |
| `rust:pin-project-lite` | `0.2.14` | `Apache-2.0 OR MIT` |
| `rust:pin-utils` | `0.1.0` | `MIT OR Apache-2.0` |
| `rust:pkcs1` | `0.7.5` | `Apache-2.0 OR MIT` |
| `rust:pkcs8` | `0.10.2` | `Apache-2.0 OR MIT` |
| `rust:pkg-config` | `0.3.30` | `MIT OR Apache-2.0` |
| `rust:powerfmt` | `0.2.0` | `MIT OR Apache-2.0` |
| `rust:ppv-lite86` | `0.2.17` | `MIT OR Apache-2.0` |
| `rust:primeorder` | `0.13.6` | `Apache-2.0 OR MIT` |
| `rust:proc-macro-error` | `1.0.4` | `MIT OR Apache-2.0` |
| `rust:proc-macro-error-attr` | `1.0.4` | `Apache-2.0 AND MIT` |
| `rust:proc-macro2` | `1.0.85` | `MIT OR Apache-2.0` |
| `rust:proc-macro2` | `>= 1.0.0,< 2.0.0` | `` |
| `rust:proc-macro2-diagnostics` | `0.10.1` | `MIT OR Apache-2.0` |
| `rust:prometheus` | `0.13.4` | `Apache-2.0` |
| `rust:prost` | `0.12.6` | `Apache-2.0` |
| `rust:prost-derive` | `0.12.6` | `Apache-2.0` |
| `rust:protobuf` | `2.28.0` | `MIT` |
| `rust:psm` | `0.1.21` | `MIT OR Apache-2.0` |
| `rust:quick-error` | `1.2.3` | `MIT OR Apache-2.0` |
| `rust:quote` | `1.0.36` | `MIT OR Apache-2.0` |
| `rust:quote` | `>= 1.0.0,< 2.0.0` | `` |
| `rust:quoted_printable` | `0.5.0` | `0BSD` |
| `rust:radium` | `0.7.0` | `MIT` |
| `rust:rand` | `0.8.5` | `MIT OR Apache-2.0` |
| `rust:rand` | `0.7.3` | `MIT OR Apache-2.0` |
| `rust:rand` | `>= 0.8.0,< 0.9.0` | `` |
| `rust:rand_chacha` | `0.2.2` | `MIT OR Apache-2.0` |
| `rust:rand_chacha` | `0.3.1` | `MIT OR Apache-2.0` |
| `rust:rand_core` | `0.6.4` | `MIT OR Apache-2.0` |
| `rust:rand_core` | `0.5.1` | `MIT OR Apache-2.0` |
| `rust:rand_hc` | `0.2.0` | `MIT OR Apache-2.0` |
| `rust:redox_syscall` | `0.5.1` | `MIT` |
| `rust:redox_syscall` | `0.2.16` | `MIT` |
| `rust:redox_users` | `0.4.5` | `MIT` |
| `rust:regex` | `>= 1.10.2,< 2.0.0` | `` |
| `rust:regex` | `1.10.5` | `MIT OR Apache-2.0` |
| `rust:regex-automata` | `0.1.10` | `MIT OR (MIT AND Unlicense)` |
| `rust:regex-automata` | `0.4.7` | `MIT OR Apache-2.0` |
| `rust:regex-syntax` | `0.8.4` | `MIT OR Apache-2.0` |
| `rust:regex-syntax` | `0.6.29` | `MIT OR Apache-2.0` |
| `rust:reqwest` | `>= 0.12.3,< 0.13.0` | `` |
| `rust:reqwest` | `0.12.4` | `MIT OR Apache-2.0` |
| `rust:reqwest` | `0.11.27` | `MIT OR Apache-2.0` |
| `rust:reqwest-middleware` | `>= 0.3.0,< 0.4.0` | `` |
| `rust:reqwest-middleware` | `0.3.3` | `MIT OR Apache-2.0` |
| `rust:reqwest-retry` | `>= 0.6.0,< 0.7.0` | `` |
| `rust:reqwest-retry` | `0.6.1` | `MIT OR Apache-2.0` |
| `rust:resolv-conf` | `0.7.0` | `MIT OR Apache-2.0` |
| `rust:retain_mut` | `0.1.9` | `MIT` |
| `rust:retry-policies` | `0.4.0` | `MIT OR Apache-2.0` |
| `rust:rfc6979` | `0.4.0` | `Apache-2.0 OR MIT` |
| `rust:ring` | `0.17.8` | `` |
| `rust:ring` | `0.16.20` | `ISC` |
| `rust:rsa` | `0.9.6` | `MIT OR Apache-2.0` |
| `rust:rspc` | `0.2.0` | `MIT` |
| `rust:rspc-axum` | `0.1.1` | `MIT` |
| `rust:rustc-demangle` | `0.1.24` | `MIT OR Apache-2.0` |
| `rust:rustc_version` | `0.2.3` | `MIT OR Apache-2.0` |
| `rust:rustc_version` | `0.4.0` | `MIT OR Apache-2.0` |
| `rust:rustc_version_runtime` | `0.2.1` | `MIT` |
| `rust:rustix` | `0.38.34` | `Apache-2.0 WITH LLVM-exception OR (Apache-2.0 OR MIT)` |
| `rust:rustls` | `0.21.12` | `Apache-2.0 OR (ISC OR MIT)` |
| `rust:rustls` | `0.22.4` | `Apache-2.0 OR (ISC OR MIT)` |
| `rust:rustls-native-certs` | `0.7.0` | `Apache-2.0 OR (ISC OR MIT)` |
| `rust:rustls-native-certs` | `0.6.3` | `Apache-2.0 OR (ISC OR MIT)` |
| `rust:rustls-pemfile` | `2.1.2` | `Apache-2.0 OR (ISC OR MIT)` |
| `rust:rustls-pemfile` | `1.0.4` | `Apache-2.0 OR (ISC OR MIT)` |
| `rust:rustls-pki-types` | `1.7.0` | `MIT OR Apache-2.0` |
| `rust:rustls-webpki` | `0.102.4` | `ISC` |
| `rust:rustls-webpki` | `0.101.7` | `ISC` |
| `rust:rustversion` | `1.0.17` | `MIT OR Apache-2.0` |
| `rust:ryu` | `1.0.18` | `Apache-2.0 OR BSL-1.0` |
| `rust:scc` | `2.1.1` | `Apache-2.0` |
| `rust:schannel` | `0.1.23` | `MIT` |
| `rust:scopeguard` | `1.2.0` | `MIT OR Apache-2.0` |
| `rust:sct` | `0.7.1` | `Apache-2.0 OR (ISC OR MIT)` |
| `rust:sdd` | `0.2.0` | `Apache-2.0` |
| `rust:sec1` | `0.7.3` | `Apache-2.0 OR MIT` |
| `rust:security-framework` | `2.11.0` | `MIT OR Apache-2.0` |
| `rust:security-framework-sys` | `2.11.0` | `MIT OR Apache-2.0` |
| `rust:semver` | `0.9.0` | `MIT OR Apache-2.0` |
| `rust:semver` | `1.0.23` | `MIT OR Apache-2.0` |
| `rust:semver` | `>= 1.0.0,< 2.0.0` | `` |
| `rust:semver-parser` | `0.7.0` | `MIT OR Apache-2.0` |
| `rust:serde` | `1.0.203` | `MIT OR Apache-2.0` |
| `rust:serde` | `>= 1.0.0,< 2.0.0` | `` |
| `rust:serde-value` | `0.7.0` | `MIT` |
| `rust:serde_bytes` | `0.11.14` | `MIT OR Apache-2.0` |
| `rust:serde_derive` | `1.0.203` | `MIT OR Apache-2.0` |
| `rust:serde_json` | `>= 1.0.0,< 2.0.0` | `` |
| `rust:serde_json` | `1.0.117` | `MIT OR Apache-2.0` |
| `rust:serde_path_to_error` | `0.1.16` | `MIT OR Apache-2.0` |
| `rust:serde_plain` | `1.0.2` | `MIT OR Apache-2.0` |
| `rust:serde_qs` | `0.8.5` | `MIT OR Apache-2.0` |
| `rust:serde_qs` | `0.12.0` | `MIT OR Apache-2.0` |
| `rust:serde_spanned` | `0.6.6` | `MIT OR Apache-2.0` |
| `rust:serde_urlencoded` | `0.7.1` | `MIT OR Apache-2.0` |
| `rust:serde_with` | `3.8.1` | `MIT OR Apache-2.0` |
| `rust:serde_with` | `>= 3.8.0,< 4.0.0` | `` |
| `rust:serde_with` | `1.14.0` | `MIT OR Apache-2.0` |
| `rust:serde_with_macros` | `1.5.2` | `MIT OR Apache-2.0` |
| `rust:serde_with_macros` | `3.8.1` | `MIT OR Apache-2.0` |
| `rust:serde_yaml` | `0.9.34+deprecated` | `MIT OR Apache-2.0` |
| `rust:serde_yaml` | `>= 0.9.27,< 0.10.0` | `` |
| `rust:serial_test` | `>= 3.0.0,< 4.0.0` | `` |
| `rust:serial_test` | `2.0.0` | `MIT` |
| `rust:serial_test` | `3.1.1` | `MIT` |
| `rust:serial_test_derive` | `2.0.0` | `MIT` |
| `rust:serial_test_derive` | `3.1.1` | `MIT` |
| `rust:sha-1` | `0.10.1` | `MIT OR Apache-2.0` |
| `rust:sha2` | `>= 0.10.7,< 0.11.0` | `` |
| `rust:sha2` | `0.10.8` | `MIT OR Apache-2.0` |
| `rust:sharded-slab` | `0.1.7` | `MIT` |
| `rust:signal-hook` | `0.3.17` | `Apache-2.0 OR MIT` |
| `rust:signal-hook-mio` | `0.2.3` | `Apache-2.0 OR MIT` |
| `rust:signal-hook-registry` | `1.4.2` | `Apache-2.0 OR MIT` |
| `rust:signature` | `2.2.0` | `Apache-2.0 OR MIT` |
| `rust:simple_asn1` | `0.6.2` | `ISC` |
| `rust:slab` | `0.4.9` | `MIT` |
| `rust:slugify` | `>= 0.1.0,< 0.2.0` | `` |
| `rust:slugify` | `0.1.0` | `MIT` |
| `rust:smallvec` | `1.13.2` | `MIT OR Apache-2.0` |
| `rust:socket2` | `0.4.10` | `MIT OR Apache-2.0` |
| `rust:socket2` | `0.5.7` | `MIT OR Apache-2.0` |
| `rust:specta` | `1.0.5` | `MIT` |
| `rust:specta-macros` | `1.0.5` | `MIT` |
| `rust:spin` | `0.5.2` | `MIT` |
| `rust:spin` | `0.9.8` | `MIT` |
| `rust:spki` | `0.7.3` | `Apache-2.0 OR MIT` |
| `rust:stable_deref_trait` | `1.2.0` | `MIT OR Apache-2.0` |
| `rust:stacker` | `0.1.15` | `MIT OR Apache-2.0` |
| `rust:stringprep` | `0.1.5` | `MIT OR Apache-2.0` |
| `rust:strsim` | `0.11.1` | `MIT` |
| `rust:strsim` | `0.10.0` | `MIT` |
| `rust:strum` | `0.26.2` | `MIT` |
| `rust:strum_macros` | `0.26.4` | `MIT` |
| `rust:subtle` | `2.5.0` | `BSD-3-Clause` |
| `rust:syn` | `>= 2.0.0,< 3.0.0` | `` |
| `rust:syn` | `1.0.109` | `MIT OR Apache-2.0` |
| `rust:syn` | `2.0.66` | `MIT OR Apache-2.0` |
| `rust:sync_wrapper` | `0.1.2` | `Apache-2.0` |
| `rust:sync_wrapper` | `1.0.1` | `Apache-2.0` |
| `rust:synstructure` | `0.13.1` | `MIT` |
| `rust:system-configuration` | `0.5.1` | `MIT OR Apache-2.0` |
| `rust:system-configuration-sys` | `0.5.0` | `MIT OR Apache-2.0` |
| `rust:tabled` | `0.14.0` | `MIT` |
| `rust:tabled` | `>= 0.14.0,< 0.15.0` | `` |
| `rust:tabled_derive` | `0.6.0` | `MIT` |
| `rust:take_mut` | `0.2.2` | `MIT` |
| `rust:tap` | `1.0.1` | `MIT` |
| `rust:tempfile` | `3.10.1` | `MIT OR Apache-2.0` |
| `rust:termcolor` | `1.4.1` | `Unlicense OR MIT` |
| `rust:thiserror` | `1.0.61` | `MIT OR Apache-2.0` |
| `rust:thiserror` | `>= 1.0.0,< 2.0.0` | `` |
| `rust:thiserror-impl` | `1.0.61` | `MIT OR Apache-2.0` |
| `rust:thread_local` | `1.1.8` | `MIT OR Apache-2.0` |
| `rust:time` | `0.3.36` | `MIT OR Apache-2.0` |
| `rust:time-core` | `0.1.2` | `MIT OR Apache-2.0` |
| `rust:time-humanize` | `0.1.3` | `MIT` |
| `rust:time-humanize` | `>= 0.1.0,< 0.2.0` | `` |
| `rust:time-macros` | `0.2.18` | `MIT OR Apache-2.0` |
| `rust:tinystr` | `0.7.6` | `` |
| `rust:tinyvec` | `1.6.0` | `Zlib OR (Apache-2.0 OR MIT)` |
| `rust:tinyvec_macros` | `0.1.1` | `MIT OR (Apache-2.0 OR Zlib)` |
| `rust:tokio` | `1.38.0` | `MIT` |
| `rust:tokio-io-timeout` | `1.2.0` | `MIT OR Apache-2.0` |
| `rust:tokio-macros` | `2.3.0` | `MIT` |
| `rust:tokio-native-tls` | `0.3.1` | `MIT` |
| `rust:tokio-rustls` | `0.24.1` | `MIT OR Apache-2.0` |
| `rust:tokio-rustls` | `0.25.0` | `MIT OR Apache-2.0` |
| `rust:tokio-stream` | `0.1.15` | `MIT` |
| `rust:tokio-util` | `>= 0.7.8,< 0.8.0` | `` |
| `rust:tokio-util` | `0.7.11` | `MIT` |
| `rust:toml` | `>= 0.8.0,< 0.9.0` | `` |
| `rust:toml` | `0.7.8` | `MIT OR Apache-2.0` |
| `rust:toml` | `0.8.14` | `MIT OR Apache-2.0` |
| `rust:toml_datetime` | `0.6.6` | `MIT OR Apache-2.0` |
| `rust:toml_edit` | `0.19.15` | `MIT OR Apache-2.0` |
| `rust:toml_edit` | `0.22.14` | `MIT OR Apache-2.0` |
| `rust:tonic` | `0.11.0` | `MIT` |
| `rust:tower` | `0.4.13` | `MIT` |
| `rust:tower` | `>= 0.4.13,< 0.5.0` | `` |
| `rust:tower-http` | `0.5.2` | `MIT` |
| `rust:tower-layer` | `0.3.2` | `MIT` |
| `rust:tower-service` | `0.3.2` | `MIT` |
| `rust:tower-service` | `>= 0.3.2,< 0.4.0` | `` |
| `rust:tracing` | `0.1.40` | `MIT` |
| `rust:tracing` | `>= 0.1.0,< 0.2.0` | `` |
| `rust:tracing-attributes` | `0.1.27` | `MIT` |
| `rust:tracing-core` | `0.1.32` | `MIT` |
| `rust:tracing-log` | `0.2.0` | `MIT` |
| `rust:tracing-opentelemetry` | `0.23.0` | `MIT` |
| `rust:tracing-opentelemetry` | `>= 0.23.0,< 0.24.0` | `` |
| `rust:tracing-opentelemetry-instrumentation-sdk` | `0.18.1` | `CC0-1.0` |
| `rust:tracing-serde` | `0.1.3` | `MIT` |
| `rust:tracing-subscriber` | `0.3.18` | `MIT` |
| `rust:trust-dns-proto` | `0.21.2` | `MIT OR Apache-2.0` |
| `rust:trust-dns-resolver` | `0.21.2` | `MIT OR Apache-2.0` |
| `rust:try-lock` | `0.2.5` | `MIT` |
| `rust:trybuild` | `>= 1.0.0,< 2.0.0` | `` |
| `rust:trybuild` | `1.0.96` | `MIT OR Apache-2.0` |
| `rust:typed-builder` | `0.10.0` | `MIT OR Apache-2.0` |
| `rust:typenum` | `1.17.0` | `MIT OR Apache-2.0` |
| `rust:ulid` | `1.1.2` | `MIT` |
| `rust:uncased` | `0.9.10` | `MIT OR Apache-2.0` |
| `rust:unicase` | `2.7.0` | `MIT OR Apache-2.0` |
| `rust:unicode-bidi` | `0.3.15` | `MIT OR Apache-2.0` |
| `rust:unicode-ident` | `1.0.12` | `(MIT OR Apache-2.0) AND Unicode-DFS-2016` |
| `rust:unicode-normalization` | `0.1.23` | `MIT OR Apache-2.0` |
| `rust:unicode-properties` | `0.1.1` | `MIT OR Apache-2.0` |
| `rust:unicode-segmentation` | `1.11.0` | `MIT OR Apache-2.0` |
| `rust:unicode-width` | `0.1.13` | `MIT OR Apache-2.0` |
| `rust:unidecode` | `0.3.0` | `BSD-3-Clause` |
| `rust:unsafe-libyaml` | `0.2.11` | `MIT` |
| `rust:untrusted` | `0.9.0` | `ISC` |
| `rust:untrusted` | `0.7.1` | `ISC` |
| `rust:url` | `>= 2.5.0,< 3.0.0` | `` |
| `rust:url` | `2.5.1` | `MIT OR Apache-2.0` |
| `rust:urlencoding` | `2.1.3` | `MIT` |
| `rust:utf16_iter` | `1.0.5` | `Apache-2.0 OR MIT` |
| `rust:utf8_iter` | `1.0.4` | `Apache-2.0 OR MIT` |
| `rust:utf8parse` | `0.2.2` | `Apache-2.0 OR MIT` |
| `rust:uuid` | `>= 1.8.0,< 2.0.0` | `` |
| `rust:uuid` | `1.8.0` | `Apache-2.0 OR MIT` |
| `rust:validator` | `0.16.1` | `MIT` |
| `rust:validator` | `>= 0.16.0,< 0.17.0` | `` |
| `rust:valuable` | `0.1.0` | `MIT` |
| `rust:vcpkg` | `0.2.15` | `MIT OR Apache-2.0` |
| `rust:version_check` | `0.9.4` | `MIT OR Apache-2.0` |
| `rust:waker-fn` | `1.2.0` | `Apache-2.0 OR MIT` |
| `rust:want` | `0.3.1` | `MIT` |
| `rust:wasi` | `0.11.0+wasi-snapshot-preview1` | `Apache-2.0 WITH LLVM-exception OR (Apache-2.0 OR MIT)` |
| `rust:wasi` | `0.9.0+wasi-snapshot-preview1` | `Apache-2.0 WITH LLVM-exception OR (Apache-2.0 OR MIT)` |
| `rust:wasm-bindgen` | `0.2.92` | `MIT OR Apache-2.0` |
| `rust:wasm-bindgen-backend` | `0.2.92` | `MIT OR Apache-2.0` |
| `rust:wasm-bindgen-futures` | `0.4.42` | `MIT OR Apache-2.0` |
| `rust:wasm-bindgen-macro` | `0.2.92` | `MIT OR Apache-2.0` |
| `rust:wasm-bindgen-macro-support` | `0.2.92` | `MIT OR Apache-2.0` |
| `rust:wasm-bindgen-shared` | `0.2.92` | `MIT OR Apache-2.0` |
| `rust:wasm-streams` | `0.4.0` | `MIT OR Apache-2.0` |
| `rust:wasm-timer` | `0.2.5` | `MIT` |
| `rust:web-sys` | `0.3.69` | `MIT OR Apache-2.0` |
| `rust:web-time` | `1.1.0` | `MIT OR Apache-2.0` |
| `rust:webpki-roots` | `0.25.4` | `MPL-2.0` |
| `rust:widestring` | `1.1.0` | `MIT OR Apache-2.0` |
| `rust:winapi` | `0.3.9` | `MIT OR Apache-2.0` |
| `rust:winapi-i686-pc-windows-gnu` | `0.4.0` | `MIT OR Apache-2.0` |
| `rust:winapi-util` | `0.1.8` | `Unlicense OR MIT` |
| `rust:winapi-x86_64-pc-windows-gnu` | `0.4.0` | `MIT OR Apache-2.0` |
| `rust:windows` | `0.52.0` | `MIT OR Apache-2.0` |
| `rust:windows-core` | `0.52.0` | `MIT OR Apache-2.0` |
| `rust:windows-sys` | `0.52.0` | `MIT OR Apache-2.0` |
| `rust:windows-sys` | `0.48.0` | `MIT OR Apache-2.0` |
| `rust:windows-targets` | `0.48.5` | `MIT OR Apache-2.0` |
| `rust:windows-targets` | `0.52.5` | `MIT OR Apache-2.0` |
| `rust:windows_aarch64_gnullvm` | `0.48.5` | `MIT OR Apache-2.0` |
| `rust:windows_aarch64_gnullvm` | `0.52.5` | `MIT OR Apache-2.0` |
| `rust:windows_aarch64_msvc` | `0.48.5` | `MIT OR Apache-2.0` |
| `rust:windows_aarch64_msvc` | `0.52.5` | `MIT OR Apache-2.0` |
| `rust:windows_i686_gnu` | `0.48.5` | `MIT OR Apache-2.0` |
| `rust:windows_i686_gnu` | `0.52.5` | `MIT OR Apache-2.0` |
| `rust:windows_i686_gnullvm` | `0.52.5` | `MIT OR Apache-2.0` |
| `rust:windows_i686_msvc` | `0.52.5` | `MIT OR Apache-2.0` |
| `rust:windows_i686_msvc` | `0.48.5` | `MIT OR Apache-2.0` |
| `rust:windows_x86_64_gnu` | `0.48.5` | `MIT OR Apache-2.0` |
| `rust:windows_x86_64_gnu` | `0.52.5` | `MIT OR Apache-2.0` |
| `rust:windows_x86_64_gnullvm` | `0.52.5` | `MIT OR Apache-2.0` |
| `rust:windows_x86_64_gnullvm` | `0.48.5` | `MIT OR Apache-2.0` |
| `rust:windows_x86_64_msvc` | `0.48.5` | `MIT OR Apache-2.0` |
| `rust:windows_x86_64_msvc` | `0.52.5` | `MIT OR Apache-2.0` |
| `rust:winnow` | `0.5.40` | `MIT` |
| `rust:winnow` | `0.6.13` | `MIT` |
| `rust:winreg` | `0.50.0` | `MIT` |
| `rust:winreg` | `0.52.0` | `MIT` |
| `rust:wiremock` | `>= 0.5.19,< 0.6.0` | `` |
| `rust:wiremock` | `0.5.22` | `MIT OR Apache-2.0` |
| `rust:write16` | `1.0.0` | `Apache-2.0 OR MIT` |
| `rust:writeable` | `0.5.5` | `Unicode-3.0` |
| `rust:wyz` | `0.5.1` | `MIT` |
| `rust:yansi` | `1.0.1` | `MIT OR Apache-2.0` |
| `rust:yoke` | `0.7.4` | `Unicode-3.0` |
| `rust:yoke-derive` | `0.7.4` | `` |
| `rust:zerocopy` | `0.7.34` | `BSD-2-Clause OR (Apache-2.0 OR MIT)` |
| `rust:zerocopy-derive` | `0.7.34` | `BSD-2-Clause OR (Apache-2.0 OR MIT)` |
| `rust:zerofrom` | `0.1.4` | `Unicode-3.0` |
| `rust:zerofrom-derive` | `0.1.4` | `Unicode-3.0` |
| `rust:zeroize` | `1.8.1` | `Apache-2.0 OR MIT` |
| `rust:zerovec` | `0.10.4` | `Unicode-3.0` |
| `rust:zerovec-derive` | `0.10.3` | `Unicode-3.0` |
# Security
At CrabNebula we take security topics into account when designing
a product and during it's whole lifecycle. We have internal manual and
automated security testing in place but, as it is impossible to discover
all bugs in a code base, we encourage reporting security relevant
bugs in a coordinated way.
:::tip
If you're reporting vulnerabilities related to code in a GitHub repo then please use the respective disclosure in that repo. [Learn more about GitHub Coordinated Disclosures](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/about-coordinated-disclosure-of-security-vulnerabilities).
:::
## Vulnerability Disclosure
**Do not report security vulnerabilities through public channels.**
Please contact us via email at [security@crabnebula.dev](mailto:security@crabnebula.dev).
You can encrypt your mail using GnuPG if you want.
See the [security.txt](https://crabnebula.dev/.well-known/security.txt) at crabnebula.dev:
```
Contact: mailto:security@crabnebula.dev
Expires: 2025-01-30T06:30:00.000Z
Encryption: https://crabnebula.dev/.well-known/pgp.txt
Preferred-Languages: en,de,fr
Canonical: https://crabnebula.dev/.well-known/security.txt
```
Include as much of the following information as possible in the security report:
- Type of issue (e.g. code execution, privilege escalation, information leak etc.)
- The location of the affected feature (URL/Code)
- Any special configuration required to reproduce the issue
- The distribution affected or used for reproduction.
- Step-by-step instructions to reproduce the issue, ideally a reproduction repository
- Impact of the issue, including how an attacker might exploit the issue
We prefer to receive reports in English. If necessary, we also understand French and German.
We currently have no paid bug bounty system in place but consider rewards on an individual basis.
# Updater Configuration
import { Tabs, TabItem } from "@astrojs/starlight/components";
On this page you will find an overview of how to configure supported updater services and frameworks to work with CrabNebula Cloud. This will allow you to automatically update your application as soon as you publish a new release on Cloud without having to manually handle the update process.
Right now we support the following options:
- [Tauri v1](https://v1.tauri.app)
- [Tauri v2](https://tauri.app)
- [Cargo Packager](https://github.com/crabnebula-dev/cargo-packager)
## Tauri
:::tip
A more in depth explanation for Tauri v2 can be found in this [guide](/cloud/guides/auto-updates-tauri/).
For more details on how to configure Tauri updater, please refer to the Tauri documentation for [Tauri v1](https://v1.tauri.app/v1/guides/distribution/updater/) and [Tauri v2](https://tauri.app/plugin/updater/) respectively.
:::
Before you can adjust your `tauri.conf.json` file to configure the update endpoint, you need to generate a cryptographic key pair for your application which will be used to check if the update is valid or might have been tampered with.
The public key will be used to verify the update (needs to be put in the `tauri.conf.json` file) and the private key (has to be kept secret!) will be used to sign the new release when you publish it.
Run the following command to generate a key pair for your application:
```bash
cargo tauri signer generate -w ~/.tauri/myapp.key
```
```bash
cargo tauri signer generate -w $HOME/.tauri/myapp.key
```
You should now see the two keyfiles `~/.tauri/myapp.key` and `~/.tauri/myapp.key.pub`.
Now you need to add the following configuration to your `tauri.conf.json` file:
```json
"tauri": {
"updater": {
"active": true,
"endpoints": [
"https://cdn.crabnebula.app/update/ORG_NAME/APP_NAME/{{target}}-{{arch}}/{{current_version}}"
],
"dialog": true,
"pubkey": "PUBKEY"
},
},
```
Before you can configure the update endpoint, you need to install the `updater` plugin:
```bash
cargo tauri add updater
```
Now you need to add the following configuration to your `tauri.conf.json` file:
```json
"bundle": {
"createUpdaterArtifacts": true
},
"plugins": {
"updater": {
"endpoints": [
"https://cdn.crabnebula.app/update/ORG_NAME/APP_NAME/{{target}}-{{arch}}/{{current_version}}"
],
"pubkey": "PUBKEY"
}
}
```
:::caution
Note that the `createUpdaterArtifacts` value must be set to `true` for new applications,
but set to `"v1Compatible"` when updating from a Tauri v1 application.
:::
Make sure to replace `ORG_NAME` with your organizations name on Cloud, `APP_NAME` with the apps name on Cloud and `PUBKEY` with the public key from `~/.tauri/myapp.key.pub`.
:::caution
It is important to sign the app with the private key from `~/.tauri/myapp.key` before you publish a new release as otherwise the update will not be valid.
:::
## Cargo Packager
:::tip
A more in depth explanation for Cargo Packager can be found in this [guide](/cloud/guides/packager-auto-updater/).
Detailed documentation for the updater can be found in the [docs](/packager/updater/) and the [GitHub repository](https://github.com/crabnebula-dev/cargo-packager/tree/main/crates/updater).
:::
Packager includes a built-in updater which can be configured to automatically update your application as soon as you publish a new release on Cloud.
Start off by adding the `cargo-packager-updater` dependency to your project:
```bash
cargo add cargo-packager-updater
```
Afterwards you need to generate a cryptographic key pair which will be used to verify the integrity of the update. New updates will be signed with the private key and the public key will be used to confirm the integrity of the update.
```bash
cargo packager signer generate
```
Save the private key in a secure location as it will be used to sign the new release when you publish it. For the configuration of the updater code you will only need the public key.
In your Rust project navigate to the specific file where you want to add the updater code and add the following imports:
```rust
use cargo_packager_updater::{semver::Version, url::Url};
```
Now add the following code:
```rust
let config = cargo_packager_updater::Config {
endpoints: vec![Url::parse("https://cdn.crabnebula.app/update/YOUR_ORG_SLUG/YOUR_APP_SLUG/{{target}}-{{arch}}/{{current_version}}").expect("Failed to parse URL")], // REPLACE: YOUR_ORG_SLUG and YOUR_APP_SLUG of the app in CN Cloud
pubkey: String::from("YOUR_PUBLIC_KEY"), // REPLACE: YOUR_PUBLIC_KEY generated by the signer
..Default::default()
};
let current_version =
Version::parse(env!("CARGO_PKG_VERSION")).expect("Failed to parse version");
println!("Current version: {}", current_version);
if let Some(update) = cargo_packager_updater::check_update(current_version.clone(), config)
.expect("Failed to check for update")
{
update
.download_and_install()
.expect("Failed to download and install update");
println!("Update installed")
} else {
println!("No update available")
}
```
Make sure to replace `YOUR_ORG_SLUG` and `YOUR_APP_SLUG` with the slug of your organization and app on Cloud. Also replace `YOUR_PUBLIC_KEY` with the public key generated by the signer.
Now as soon as that code is run, the updater will check for updates and if a new update is available, it will be downloaded and installed automatically.
# Prevent Vendor Lock-In
:::tip[What is lock-in?]
Vendor lock-in occurs when individuals are unable to switch away from a specific product or service, regardless of its quality, due to the impracticality of transitioning away from it.
:::
At CrabNebula, we prioritize addressing this concern and remain transparent with our customers about off-boarding strategies. We recommend considering these strategies as they may provide valuable options, regardless of your Cloud usage.
This is not an exhaustive list, but rather some suggestions to help you find the best solution:
- (Full control with minimal effort) Set up a redirect from your own domain to the [public updater JSON served by Cloud](/cloud/cli/fetch-latest-release). Ensure that your updater system follows redirects (the Tauri and Packager updater system follows HTTP redirects (`301` response status code).
- (Some control with minimal effort) Each release dictates the source of the next update, allowing you to put out a new version pointing to the new update location.
- (A backup strategy with considerable effort) Build a notification system in-app. This system can publish announcements to your users, providing a link to re-download the new app version. While less about vendor lock-in, it serves as a backup plan for any significant issues!
# Taurify
# Get Started
import CommandTabs from "@components/CommandTabs.astro";
Taurify is a system that simplifies the process of Web-based desktop and mobile application development and distribution.
## Installation
The Taurify CLI is all you need to turn your web application into a desktop and mobile app. The CLI is distributed on [NPM](https://npm.io/package/taurify), you can install it with your preferred package manager:
## Initializing
To start developing your application, you must initialize the Taurify configuration. Run `taurify init` and the CLI will guide you through the options that you must configure.
## Developing
The `taurify dev` command starts your application in development mode.
See the [developing guide](/taurify/developing) for more information on how to develop your application for desktop and mobile.
## Distributing
The `taurify build` command triggers a new release of your application. Our servers take care of the distribution for all platforms,
but you must prepare your application and configure the distribution first. See the [distribution documentation](/taurify/distribute).
To handle auto-updates you must configure your application to check and install them. See the [updater guide](/taurify/updater) for more information.
# @crabnebula/taurify-api
The Taurify API allows you to interface with the backend layer.
This module exposes all other modules as an object where the key is the module name, and the value is the module exports.
## Example
```typescript
import { event, window, path } from '@crabnebula/taurify-api'
```
## Functions
### isDev()
```ts
function isDev(): Promise
```
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\>
## Namespaces
- [app](/taurify/api/namespaceapp/)
- [barcodeScanner](/taurify/api/namespacebarcodescanner/)
- [biometric](/taurify/api/namespacebiometric/)
- [cli](/taurify/api/namespacecli/)
- [clipboardManager](/taurify/api/namespaceclipboardmanager/)
- [core](/taurify/api/namespacecore/)
- [deepLink](/taurify/api/namespacedeeplink/)
- [dialog](/taurify/api/namespacedialog/)
- [dpi](/taurify/api/namespacedpi/)
- [event](/taurify/api/namespaceevent/)
- [fs](/taurify/api/namespacefs/)
- [geolocation](/taurify/api/namespacegeolocation/)
- [globalShortcut](/taurify/api/namespaceglobalshortcut/)
- [haptics](/taurify/api/namespacehaptics/)
- [http](/taurify/api/namespacehttp/)
- [image](/taurify/api/namespaceimage/)
- [log](/taurify/api/namespacelog/)
- [menu](/taurify/api/namespacemenu/)
- [nfc](/taurify/api/namespacenfc/)
- [notification](/taurify/api/namespacenotification/)
- [opener](/taurify/api/namespaceopener/)
- [os](/taurify/api/namespaceos/)
- [path](/taurify/api/namespacepath/)
- [process](/taurify/api/namespaceprocess/)
- [shell](/taurify/api/namespaceshell/)
- [store](/taurify/api/namespacestore/)
- [tray](/taurify/api/namespacetray/)
- [updater](/taurify/api/namespaceupdater/)
- [webview](/taurify/api/namespacewebview/)
- [webviewWindow](/taurify/api/namespacewebviewwindow/)
- [window](/taurify/api/namespacewindow/)
# app
## Type Aliases
### DataStoreIdentifier
```ts
type DataStoreIdentifier: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number];
```
***
### NewInstance
```ts
type NewInstance: object;
```
#### Type declaration
| Name | Type | Defined in |
| ------ | ------ | ------ |
| `args` | `string`[] | |
| `cwd` | `string` | |
## Functions
### defaultWindowIcon()
```ts
function defaultWindowIcon(): Promise
```
Get the default window icon.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Image`](/taurify/api/namespaceimage/#image) \| `null`\>
#### Example
```typescript
import { defaultWindowIcon } from '@crabnebula/taurify-api/app';
await defaultWindowIcon();
```
***
### fetchDataStoreIdentifiers()
```ts
function fetchDataStoreIdentifiers(): Promise
```
Fetches the data store identifiers on macOS and iOS.
See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`DataStoreIdentifier`](/taurify/api/namespaceapp/#datastoreidentifier)[]\>
#### Example
```typescript
import { fetchDataStoreIdentifiers } from '@crabnebula/taurify-api/app';
const ids = await fetchDataStoreIdentifiers();
```
***
### getIdentifier()
```ts
function getIdentifier(): Promise
```
Gets the application identifier.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string`\>
The application identifier as configured in `tauri.conf.json`.
#### Example
```typescript
import { getIdentifier } from '@crabnebula/taurify-api/app';
const identifier = await getIdentifier();
```
***
### getName()
```ts
function getName(): Promise
```
Gets the application name.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string`\>
#### Example
```typescript
import { getName } from '@crabnebula/taurify-api/app';
const appName = await getName();
```
***
### getTauriVersion()
```ts
function getTauriVersion(): Promise
```
Gets the Tauri version.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string`\>
#### Example
```typescript
import { getTauriVersion } from '@crabnebula/taurify-api/app';
const tauriVersion = await getTauriVersion();
```
***
### getVersion()
```ts
function getVersion(): Promise
```
Gets the application version.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string`\>
#### Example
```typescript
import { getVersion } from '@crabnebula/taurify-api/app';
const appVersion = await getVersion();
```
***
### hide()
```ts
function hide(): Promise
```
Hides the application on macOS.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { hide } from '@crabnebula/taurify-api/app';
await hide();
```
***
### onNewInstance()
```ts
function onNewInstance(cb): Promise
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `cb` | (`instance`) => `void` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### removeDataStore()
```ts
function removeDataStore(uuid): Promise
```
Removes the data store with the given identifier.
Note that any webview using this data store should be closed before running this API.
See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `uuid` | [`DataStoreIdentifier`](/taurify/api/namespaceapp/#datastoreidentifier) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`DataStoreIdentifier`](/taurify/api/namespaceapp/#datastoreidentifier)[]\>
#### Example
```typescript
import { fetchDataStoreIdentifiers, removeDataStore } from '@crabnebula/taurify-api/app';
for (const id of (await fetchDataStoreIdentifiers())) {
await removeDataStore(id);
}
```
***
### setDockVisibility()
```ts
function setDockVisibility(visible): Promise
```
Sets the dock visibility for the application on macOS.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `visible` | `boolean` | whether the dock should be visible or not |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### setTheme()
```ts
function setTheme(theme?): Promise
```
Set app's theme, pass in `null` or `undefined` to follow system theme
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `theme`? | `null` \| [`Theme`](/taurify/api/namespacewindow/#theme-2) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { setTheme } from '@crabnebula/taurify-api/app';
await setTheme('dark');
```
#### Platform-specific
- **iOS / Android:** Unsupported.
***
### show()
```ts
function show(): Promise
```
Shows the application on macOS. This function does not automatically focus any specific app window.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { show } from '@crabnebula/taurify-api/app';
await show();
```
# barcodeScanner
## References
### PermissionState
Re-exports [PermissionState](/taurify/api/namespacecore/#permissionstate)
## Enumerations
### Format
#### Enumeration Members
##### Aztec
```ts
Aztec: "AZTEC";
```
##### Codabar
```ts
Codabar: "CODABAR";
```
##### Code128
```ts
Code128: "CODE_128";
```
##### Code39
```ts
Code39: "CODE_39";
```
##### Code93
```ts
Code93: "CODE_93";
```
##### DataMatrix
```ts
DataMatrix: "DATA_MATRIX";
```
##### EAN13
```ts
EAN13: "EAN_13";
```
##### EAN8
```ts
EAN8: "EAN_8";
```
##### ITF
```ts
ITF: "ITF";
```
##### PDF417
```ts
PDF417: "PDF_417";
```
##### QRCode
```ts
QRCode: "QR_CODE";
```
##### UPC\_A
```ts
UPC_A: "UPC_A";
```
##### UPC\_E
```ts
UPC_E: "UPC_E";
```
## Interfaces
### Scanned
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `bounds` | `unknown` | |
| `content` | `string` | |
| `format` | [`Format`](/taurify/api/namespacebarcodescanner/#format) | |
***
### ScanOptions
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `cameraDirection?` | `"back"` \| `"front"` | |
| `formats?` | [`Format`](/taurify/api/namespacebarcodescanner/#format)[] | |
| `windowed?` | `boolean` | |
## Functions
### cancel()
```ts
function cancel(): Promise
```
Cancel the current scan process.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### checkPermissions()
```ts
function checkPermissions(): Promise
```
Get permission state.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`PermissionState`\>
***
### openAppSettings()
```ts
function openAppSettings(): Promise
```
Open application settings. Useful if permission was denied and the user must manually enable it.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### requestPermissions()
```ts
function requestPermissions(): Promise
```
Request permissions to use the camera.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`PermissionState`\>
***
### scan()
```ts
function scan(options?): Promise
```
Start scanning.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `options`? | [`ScanOptions`](/taurify/api/namespacebarcodescanner/#scanoptions) | |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Scanned`](/taurify/api/namespacebarcodescanner/#scanned)\>
# biometric
## Enumerations
### BiometryType
#### Enumeration Members
##### FaceID
```ts
FaceID: 2;
```
##### Iris
```ts
Iris: 3;
```
##### None
```ts
None: 0;
```
##### TouchID
```ts
TouchID: 1;
```
## Interfaces
### AuthOptions
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `allowDeviceCredential?` | `boolean` | |
| `cancelTitle?` | `string` | |
| `confirmationRequired?` | `boolean` | |
| `fallbackTitle?` | `string` | |
| `maxAttemps?` | `number` | |
| `subtitle?` | `string` | |
| `title?` | `string` | |
***
### Status
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `biometryType` | [`BiometryType`](/taurify/api/namespacebiometric/#biometrytype) | |
| `error?` | `string` | |
| `errorCode?` | \| `"appCancel"` \| `"authenticationFailed"` \| `"invalidContext"` \| `"notInteractive"` \| `"passcodeNotSet"` \| `"systemCancel"` \| `"userCancel"` \| `"userFallback"` \| `"biometryLockout"` \| `"biometryNotAvailable"` \| `"biometryNotEnrolled"` | |
| `isAvailable` | `boolean` | |
## Functions
### authenticate()
```ts
function authenticate(reason, options?): Promise
```
Prompts the user for authentication using the system interface (touchID, faceID or Android Iris).
Rejects if the authentication fails.
```javascript
import { authenticate } from "@crabnebula/taurify-api/biometric";
await authenticate('Open your wallet');
```
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `reason` | `string` | |
| `options`? | [`AuthOptions`](/taurify/api/namespacebiometric/#authoptions) | |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### checkStatus()
```ts
function checkStatus(): Promise
```
Checks if the biometric authentication is available.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Status`](/taurify/api/namespacebiometric/#status)\>
a promise resolving to an object containing all the information about the status of the biometry.
# cli
Parse arguments from your Command Line Interface.
## Interfaces
### ArgMatch
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `occurrences` | `number` | Number of occurrences | |
| `value` | `null` \| `string` \| `boolean` \| `string`[] | string if takes value boolean if flag string[] or null if takes multiple values | |
***
### CliMatches
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `args` | [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, [`ArgMatch`](/taurify/api/namespacecli/#argmatch)\> | |
| `subcommand` | `null` \| [`SubcommandMatch`](/taurify/api/namespacecli/#subcommandmatch) | |
***
### SubcommandMatch
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `matches` | [`CliMatches`](/taurify/api/namespacecli/#climatches) | |
| `name` | `string` | |
## Functions
### getMatches()
```ts
function getMatches(): Promise
```
Parse the arguments provided to the current process and get the matches using the configuration defined [`tauri.cli`](https://tauri.app/v1/api/config/#tauriconfig.cli) in `tauri.conf.json`
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`CliMatches`](/taurify/api/namespacecli/#climatches)\>
#### Example
```typescript
import { getMatches } from '@crabnebula/taurify-api/cli';
const matches = await getMatches();
if (matches.subcommand?.name === 'run') {
// `./your-app run $ARGS` was executed
const args = matches.subcommand?.matches.args
if ('debug' in args) {
// `./your-app run --debug` was executed
}
} else {
const args = matches.args
// `./your-app $ARGS` was executed
}
```
# clipboardManager
Read and write to the system clipboard.
## Functions
### clear()
```ts
function clear(): Promise
```
Clears the clipboard.
#### Platform-specific
- **Android:** Only supported on SDK 28+. For older releases we write an empty string to the clipboard instead.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { clear } from '@crabnebula/taurify-api/clipboard-manager';
await clear();
```
***
### readImage()
```ts
function readImage(): Promise
```
Gets the clipboard content as Uint8Array image.
#### Platform-specific
- **Android / iOS:** Not supported.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Image`](/taurify/api/namespaceimage/#image)\>
#### Example
```typescript
import { readImage } from '@crabnebula/taurify-api/clipboard-manager';
const clipboardImage = await readImage();
const blob = new Blob([await clipboardImage.rgba()], { type: 'image' })
const url = URL.createObjectURL(blob)
```
***
### readText()
```ts
function readText(): Promise
```
Gets the clipboard content as plain text.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string`\>
#### Example
```typescript
import { readText } from '@crabnebula/taurify-api/clipboard-manager';
const clipboardText = await readText();
```
***
### writeHtml()
```ts
function writeHtml(html, altText?): Promise
```
* Writes HTML or fallbacks to write provided plain text to the clipboard.
#### Platform-specific
- **Android / iOS:** Not supported.
#### Parameters
| Parameter | Type |
| ---------- | -------- |
| `html` | `string` |
| `altText`? | `string` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
A promise indicating the success or failure of the operation.
#### Example
```typescript
import { writeHtml } from '@crabnebula/taurify-api/clipboard-manager';
await writeHtml('Tauri is awesome!
', 'plaintext');
// The following will write "Tauri is awesome
" as plain text
await writeHtml('Tauri is awesome!
', 'Tauri is awesome
');
// we can read html data only as a string so there's just readText(), no readHtml()
assert(await readText(), 'Tauri is awesome!
');
```
***
### writeImage()
```ts
function writeImage(image): Promise
```
Writes image buffer to the clipboard.
#### Platform-specific
- **Android / iOS:** Not supported.
#### Parameters
| Parameter | Type |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `image` | \| `string` \| `number`[] \| [`ArrayBuffer`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) \| [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\> \| [`Image`](/taurify/api/namespaceimage/#image) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
A promise indicating the success or failure of the operation.
#### Example
```typescript
import { writeImage } from '@crabnebula/taurify-api/clipboard-manager';
const buffer = [
// A red pixel
255, 0, 0, 255,
// A green pixel
0, 255, 0, 255,
];
await writeImage(buffer);
```
***
### writeText()
```ts
function writeText(text, opts?): Promise
```
Writes plain text to the clipboard.
#### Parameters
| Parameter | Type |
| ------------- | -------- |
| `text` | `string` |
| `opts`? | `object` |
| `opts.label`? | `string` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
A promise indicating the success or failure of the operation.
#### Example
```typescript
import { writeText, readText } from '@crabnebula/taurify-api/clipboard-manager';
await writeText('Tauri is awesome!');
assert(await readText(), 'Tauri is awesome!');
```
# core
Invoke your custom commands.
This package is also accessible with `window.__TAURIFY__.core`.
## Classes
### Channel\
#### Type Parameters
| Type Parameter | Default type |
| ------ | ------ |
| `T` | `unknown` |
#### Constructors
##### new Channel()
```ts
new Channel(onmessage?): Channel
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `onmessage`? | (`response`) => `void` |
###### Returns
[`Channel`](/taurify/api/namespacecore/#channelt)\<`T`\>
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `id` | `number` | The callback id returned from [`transformCallback`](/taurify/api/namespacecore/#transformcallback) | |
#### Accessors
##### onmessage
###### Get Signature
```ts
get onmessage(): (response) => void
```
###### Returns
`Function`
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `response` | `T` |
###### Returns
`void`
###### Set Signature
```ts
set onmessage(handler): void
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `handler` | (`response`) => `void` |
###### Returns
`void`
#### Methods
##### \_\_TAURI\_TO\_IPC\_KEY\_\_()
```ts
__TAURI_TO_IPC_KEY__(): string
```
###### Returns
`string`
##### toJSON()
```ts
toJSON(): string
```
###### Returns
`string`
***
### PluginListener
#### Constructors
##### new PluginListener()
```ts
new PluginListener(
plugin,
event,
channelId): PluginListener
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `plugin` | `string` |
| `event` | `string` |
| `channelId` | `number` |
###### Returns
[`PluginListener`](/taurify/api/namespacecore/#pluginlistener)
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `channelId` | `number` | |
| `event` | `string` | |
| `plugin` | `string` | |
#### Methods
##### unregister()
```ts
unregister(): Promise
```
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### Resource
A rust-backed resource.
The resource lives in the main process and does not exist
in the Javascript world, and thus will not be cleaned up automatiacally
except on application exit. If you want to clean it up early, call [`Resource.close`](/taurify/api/namespacecore/#close)
#### Example
```typescript
import { Resource, invoke } from '@crabnebula/taurify-api/core';
export class DatabaseHandle extends Resource {
static async open(path: string): Promise {
const rid: number = await invoke('open_db', { path });
return new DatabaseHandle(rid);
}
async execute(sql: string): Promise {
await invoke('execute_sql', { rid: this.rid, sql });
}
}
```
#### Extended by
- [`TrayIcon`](/taurify/api/namespacetray/#trayicon)
- [`Image`](/taurify/api/namespaceimage/#image)
- [`FileHandle`](/taurify/api/namespacefs/#filehandle)
- [`Store`](/taurify/api/namespacestore/#store)
- [`Update`](/taurify/api/namespaceupdater/#update)
#### Constructors
##### new Resource()
```ts
new Resource(rid): Resource
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `rid` | `number` |
###### Returns
[`Resource`](/taurify/api/namespacecore/#resource)
#### Accessors
##### rid
###### Get Signature
```ts
get rid(): number
```
###### Returns
`number`
#### Methods
##### close()
```ts
close(): Promise
```
Destroys and cleans up this resource from memory.
**You should not call any method on this object anymore and should drop any reference to it.**
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
## Interfaces
### InvokeOptions
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `headers` | `HeadersInit` | |
## Type Aliases
### InvokeArgs
```ts
type InvokeArgs: Record | number[] | ArrayBuffer | Uint8Array;
```
Command arguments.
***
### PermissionState
```ts
type PermissionState: "granted" | "denied" | "prompt" | "prompt-with-rationale";
```
## Variables
### SERIALIZE\_TO\_IPC\_FN
```ts
const SERIALIZE_TO_IPC_FN: "__TAURI_TO_IPC_KEY__" = '__TAURI_TO_IPC_KEY__';
```
A key to be used to implement a special function
on your types that define how your type should be serialized
when passing across the IPC.
#### Example
Given a type in Rust that looks like this
```rs
#[derive(serde::Serialize, serde::Deserialize)
enum UserId {
String(String),
Number(u32),
}
```
`UserId::String("id")` would be serialized into `{ String: "id" }`
and so we need to pass the same structure back to Rust
```ts
import { SERIALIZE_TO_IPC_FN } from "@crabnebula/taurify-api/core"
class UserIdString {
id
constructor(id) {
this.id = id
}
[SERIALIZE_TO_IPC_FN]() {
return { String: this.id }
}
}
class UserIdNumber {
id
constructor(id) {
this.id = id
}
[SERIALIZE_TO_IPC_FN]() {
return { Number: this.id }
}
}
type UserId = UserIdString | UserIdNumber
```
## Functions
### addPluginListener()
```ts
function addPluginListener(
plugin,
event,
cb): Promise
```
Adds a listener to a plugin event.
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `plugin` | `string` |
| `event` | `string` |
| `cb` | (`payload`) => `void` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`PluginListener`](/taurify/api/namespacecore/#pluginlistener)\>
The listener object to stop listening to the events.
***
### checkPermissions()
```ts
function checkPermissions(plugin): Promise
```
Get permission state for a plugin.
This should be used by plugin authors to wrap their actual implementation.
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `plugin` | `string` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`T`\>
***
### convertFileSrc()
```ts
function convertFileSrc(filePath, protocol): string
```
Convert a device file path to an URL that can be loaded by the webview.
Note that `asset:` and `http://asset.localhost` must be added to [`app.security.csp`](https://v2.tauri.app/reference/config/#csp-1) in `tauri.conf.json`.
Example CSP value: `"csp": "default-src 'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost"` to use the asset protocol on image sources.
Additionally, `"enable" : "true"` must be added to [`app.security.assetProtocol`](https://v2.tauri.app/reference/config/#assetprotocolconfig)
in `tauri.conf.json` and its access scope must be defined on the `scope` array on the same `assetProtocol` object.
#### Parameters
| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| `filePath` | `string` | `undefined` | The file path. |
| `protocol` | `string` | `'asset'` | The protocol to use. Defaults to `asset`. You only need to set this when using a custom protocol. |
#### Returns
`string`
the URL that can be used as source on the webview.
#### Example
```typescript
import { appDataDir, join } from '@crabnebula/taurify-api/path';
import { convertFileSrc } from '@crabnebula/taurify-api/core';
const appDataDirPath = await appDataDir();
const filePath = await join(appDataDirPath, 'assets/video.mp4');
const assetUrl = convertFileSrc(filePath);
const video = document.getElementById('my-video');
const source = document.createElement('source');
source.type = 'video/mp4';
source.src = assetUrl;
video.appendChild(source);
video.load();
```
***
### invoke()
```ts
function invoke(
cmd,
args,
options?): Promise
```
Sends a message to the backend.
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `cmd` | `string` | The command name. |
| `args` | [`InvokeArgs`](/taurify/api/namespacecore/#invokeargs) | The optional arguments to pass to the command. |
| `options`? | [`InvokeOptions`](/taurify/api/namespacecore/#invokeoptions) | The request options. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`T`\>
A promise resolving or rejecting to the backend response.
#### Example
```typescript
import { invoke } from '@crabnebula/taurify-api/core';
await invoke('login', { user: 'tauri', password: 'poiwe3h4r5ip3yrhtew9ty' });
```
***
### isTauri()
```ts
function isTauri(): boolean
```
#### Returns
`boolean`
***
### requestPermissions()
```ts
function requestPermissions(plugin): Promise
```
Request permissions.
This should be used by plugin authors to wrap their actual implementation.
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `plugin` | `string` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`T`\>
***
### transformCallback()
```ts
function transformCallback(callback?, once?): number
```
Stores the callback in a known location, and returns an identifier that can be passed to the backend.
The backend uses the identifier to `eval()` the callback.
#### Type Parameters
| Type Parameter | Default type |
| ------ | ------ |
| `T` | `unknown` |
#### Parameters
| Parameter | Type | Default value |
| ------ | ------ | ------ |
| `callback`? | (`response`) => `void` | `undefined` |
| `once`? | `boolean` | `false` |
#### Returns
`number`
An unique identifier associated with the callback function.
# deepLink
## Functions
### getCurrent()
```ts
function getCurrent(): Promise
```
Get the current URLs that triggered the deep link. Use this on app load to check whether your app was started via a deep link.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string`[] \| `null`\>
#### Example
```typescript
import { getCurrent } from '@crabnebula/taurify-api/deep-link';
const urls = await getCurrent();
```
#### - **Windows / Linux**: This function reads the command line arguments and checks if there's only one value, which must be an URL with scheme matching one of the configured values.
Note that you must manually check the arguments when registering deep link schemes dynamically with [`Self::register`].
Additionally, the deep link might have been provided as a CLI argument so you should check if its format matches what you expect..
***
### isRegistered()
```ts
function isRegistered(protocol): Promise
```
Check whether the app is the default handler for the specified protocol.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `protocol` | `string` | The name of the protocol without `://`. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\>
#### Example
```typescript
import { isRegistered } from '@crabnebula/taurify-api/deep-link';
await isRegistered("my-scheme");
```
#### - **macOS / Android / iOS**: Unsupported.
***
### onOpenUrl()
```ts
function onOpenUrl(handler): Promise
```
Helper function for the `deep-link://new-url` event to run a function each time the protocol is triggered while the app is running. Use `getCurrent` on app load to check whether your app was started via a deep link.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `handler` | (`urls`) => `void` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`UnlistenFn`](/taurify/api/namespaceevent/#unlistenfn)\>
#### Example
```typescript
import { onOpenUrl } from '@crabnebula/taurify-api/deep-link';
await onOpenUrl((urls) => { console.log(urls) });
```
#### - **Windows / Linux**: Unsupported without the single-instance plugin. The OS will spawn a new app instance passing the URL as a CLI argument.
***
### register()
```ts
function register(protocol): Promise
```
Register the app as the default handler for the specified protocol.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `protocol` | `string` | The name of the protocol without `://`. For example, if you want your app to handle `tauri://` links, call this method with `tauri` as the protocol. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`null`\>
#### Example
```typescript
import { register } from '@crabnebula/taurify-api/deep-link';
await register("my-scheme");
```
#### - **macOS / Android / iOS**: Unsupported.
***
### unregister()
```ts
function unregister(protocol): Promise
```
Unregister the app as the default handler for the specified protocol.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `protocol` | `string` | The name of the protocol without `://`. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`null`\>
#### Example
```typescript
import { unregister } from '@crabnebula/taurify-api/deep-link';
await unregister("my-scheme");
```
#### - **macOS / Linux / Android / iOS**: Unsupported.
# dialog
## Interfaces
### ConfirmDialogOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `cancelLabel?` | `string` | The label of the cancel button. | |
| `kind?` | `"error"` \| `"info"` \| `"warning"` | The kind of the dialog. Defaults to `info`. | |
| `okLabel?` | `string` | The label of the confirm button. | |
| `title?` | `string` | The title of the dialog. Defaults to the app name. | |
***
### DialogFilter
Extension filters for the file dialog.
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `extensions` | `string`[] | Extensions to filter, without a `.` prefix. **Example** `extensions: ['svg', 'png']` | |
| `name` | `string` | Filter name. | |
***
### MessageDialogOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `kind?` | `"error"` \| `"info"` \| `"warning"` | The kind of the dialog. Defaults to `info`. | |
| `okLabel?` | `string` | The label of the confirm button. | |
| `title?` | `string` | The title of the dialog. Defaults to the app name. | |
***
### OpenDialogOptions
Options for the open dialog.
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `canCreateDirectories?` | `boolean` | Whether to allow creating directories in the dialog. Enabled by default. **macOS Only** | |
| `defaultPath?` | `string` | Initial directory or file path. If it's a directory path, the dialog interface will change to that folder. If it's not an existing directory, the file name will be set to the dialog's file name input and the dialog will be set to the parent folder. On mobile the file name is always used on the dialog's file name input. If not provided, Android uses `(invalid).txt` as default file name. | |
| `directory?` | `boolean` | Whether the dialog is a directory selection or not. | |
| `filters?` | [`DialogFilter`](/taurify/api/namespacedialog/#dialogfilter)[] | The filters of the dialog. | |
| `multiple?` | `boolean` | Whether the dialog allows multiple selection or not. | |
| `recursive?` | `boolean` | If `directory` is true, indicates that it will be read recursively later. Defines whether subdirectories will be allowed on the scope or not. | |
| `title?` | `string` | The title of the dialog window (desktop only). | |
***
### SaveDialogOptions
Options for the save dialog.
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `canCreateDirectories?` | `boolean` | Whether to allow creating directories in the dialog. Enabled by default. **macOS Only** | |
| `defaultPath?` | `string` | Initial directory or file path. If it's a directory path, the dialog interface will change to that folder. If it's not an existing directory, the file name will be set to the dialog's file name input and the dialog will be set to the parent folder. On mobile the file name is always used on the dialog's file name input. If not provided, Android uses `(invalid).txt` as default file name. | |
| `filters?` | [`DialogFilter`](/taurify/api/namespacedialog/#dialogfilter)[] | The filters of the dialog. | |
| `title?` | `string` | The title of the dialog window (desktop only). | |
## Type Aliases
### OpenDialogReturn\
```ts
type OpenDialogReturn: T["directory"] extends true ? T["multiple"] extends true ? string[] | null : string | null : T["multiple"] extends true ? string[] | null : string | null;
```
#### Type Parameters
| Type Parameter |
| ------ |
| `T` *extends* [`OpenDialogOptions`](/taurify/api/namespacedialog/#opendialogoptions) |
## Functions
### ask()
```ts
function ask(message, options?): Promise
```
Shows a question dialog with `Yes` and `No` buttons.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | `string` | The message to show. |
| `options`? | `string` \| [`ConfirmDialogOptions`](/taurify/api/namespacedialog/#confirmdialogoptions) | The dialog's options. If a string, it represents the dialog title. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\>
A promise resolving to a boolean indicating whether `Yes` was clicked or not.
#### Example
```typescript
import { ask } from '@crabnebula/taurify-api/dialog';
const yes = await ask('Are you sure?', 'Tauri');
const yes2 = await ask('This action cannot be reverted. Are you sure?', { title: 'Tauri', kind: 'warning' });
```
***
### confirm()
```ts
function confirm(message, options?): Promise
```
Shows a question dialog with `Ok` and `Cancel` buttons.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | `string` | The message to show. |
| `options`? | `string` \| [`ConfirmDialogOptions`](/taurify/api/namespacedialog/#confirmdialogoptions) | The dialog's options. If a string, it represents the dialog title. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\>
A promise resolving to a boolean indicating whether `Ok` was clicked or not.
#### Example
```typescript
import { confirm } from '@crabnebula/taurify-api/dialog';
const confirmed = await confirm('Are you sure?', 'Tauri');
const confirmed2 = await confirm('This action cannot be reverted. Are you sure?', { title: 'Tauri', kind: 'warning' });
```
***
### message()
```ts
function message(message, options?): Promise
```
Shows a message dialog with an `Ok` button.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | `string` | The message to show. |
| `options`? | `string` \| [`MessageDialogOptions`](/taurify/api/namespacedialog/#messagedialogoptions) | The dialog's options. If a string, it represents the dialog title. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
A promise indicating the success or failure of the operation.
#### Example
```typescript
import { message } from '@crabnebula/taurify-api/dialog';
await message('Tauri is awesome', 'Tauri');
await message('File not found', { title: 'Tauri', kind: 'error' });
```
***
### open()
```ts
function open(options): Promise>
```
Open a file/directory selection dialog.
The selected paths are added to the filesystem and asset protocol scopes.
When security is more important than the easy of use of this API,
prefer writing a dedicated command instead.
Note that the scope change is not persisted, so the values are cleared when the application is restarted.
You can save it to the filesystem using [tauri-plugin-persisted-scope](https://github.com/tauri-apps/tauri-plugin-persisted-scope).
#### Type Parameters
| Type Parameter |
| ------ |
| `T` *extends* [`OpenDialogOptions`](/taurify/api/namespacedialog/#opendialogoptions) |
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `options` | `T` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`OpenDialogReturn`](/taurify/api/namespacedialog/#opendialogreturnt)\<`T`\>\>
A promise resolving to the selected path(s)
#### Examples
```typescript
import { open } from '@crabnebula/taurify-api/dialog';
// Open a selection dialog for image files
const selected = await open({
multiple: true,
filters: [{
name: 'Image',
extensions: ['png', 'jpeg']
}]
});
if (Array.isArray(selected)) {
// user selected multiple files
} else if (selected === null) {
// user cancelled the selection
} else {
// user selected a single file
}
```
```typescript
import { open } from '@crabnebula/taurify-api/dialog';
import { appDir } from '../../path';
// Open a selection dialog for directories
const selected = await open({
directory: true,
multiple: true,
defaultPath: await appDir(),
});
if (Array.isArray(selected)) {
// user selected multiple directories
} else if (selected === null) {
// user cancelled the selection
} else {
// user selected a single directory
}
```
***
### save()
```ts
function save(options): Promise
```
Open a file/directory save dialog.
The selected path is added to the filesystem and asset protocol scopes.
When security is more important than the easy of use of this API,
prefer writing a dedicated command instead.
Note that the scope change is not persisted, so the values are cleared when the application is restarted.
You can save it to the filesystem using [tauri-plugin-persisted-scope](https://github.com/tauri-apps/tauri-plugin-persisted-scope).
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `options` | [`SaveDialogOptions`](/taurify/api/namespacedialog/#savedialogoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string` \| `null`\>
A promise resolving to the selected path.
#### Example
```typescript
import { save } from '@crabnebula/taurify-api/dialog';
const filePath = await save({
filters: [{
name: 'Image',
extensions: ['png', 'jpeg']
}]
});
```
# dpi
## Classes
### LogicalPosition
A position represented in logical pixels.
For an explanation of what logical pixels are, see description of [`LogicalSize`](/taurify/api/namespacedpi/#logicalsize).
#### Constructors
##### new LogicalPosition()
```ts
new LogicalPosition(x, y): LogicalPosition
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `x` | `number` |
| `y` | `number` |
###### Returns
[`LogicalPosition`](/taurify/api/namespacedpi/#logicalposition)
##### new LogicalPosition()
```ts
new LogicalPosition(object): LogicalPosition
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `object` | `object` |
| `object.Logical` | `object` |
| `object.Logical.x` | `number` |
| `object.Logical.y` | `number` |
###### Returns
[`LogicalPosition`](/taurify/api/namespacedpi/#logicalposition)
##### new LogicalPosition()
```ts
new LogicalPosition(object): LogicalPosition
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `object` | `object` |
| `object.x` | `number` |
| `object.y` | `number` |
###### Returns
[`LogicalPosition`](/taurify/api/namespacedpi/#logicalposition)
#### Properties
| Property | Modifier | Type | Default value | Defined in |
| ------ | ------ | ------ | ------ | ------ |
| `type` | `readonly` | `"Logical"` | `'Logical'` | |
| `x` | `public` | `number` | `undefined` | |
| `y` | `public` | `number` | `undefined` | |
#### Methods
##### \_\_TAURI\_TO\_IPC\_KEY\_\_()
```ts
__TAURI_TO_IPC_KEY__(): object
```
###### Returns
`object`
| Name | Type | Defined in |
| ------ | ------ | ------ |
| `x` | `number` | |
| `y` | `number` | |
##### toJSON()
```ts
toJSON(): object
```
###### Returns
`object`
| Name | Type | Defined in |
| ------ | ------ | ------ |
| `x` | `number` | |
| `y` | `number` | |
##### toPhysical()
```ts
toPhysical(scaleFactor): PhysicalPosition
```
Converts the logical position to a physical one.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `scaleFactor` | `number` |
###### Returns
[`PhysicalPosition`](/taurify/api/namespacedpi/#physicalposition)
###### Example
```typescript
import { LogicalPosition } from '@crabnebula/taurify-api/dpi';
import { getCurrentWindow } from '@crabnebula/taurify-api/window';
const appWindow = getCurrentWindow();
const factor = await appWindow.scaleFactor();
const position = new LogicalPosition(400, 500);
const physical = position.toPhysical(factor);
```
***
### LogicalSize
A size represented in logical pixels.
Logical pixels are scaled according to the window's DPI scale.
Most browser APIs (i.e. `MouseEvent`'s `clientX`) will return logical pixels.
For logical-pixel-based position, see [`LogicalPosition`](/taurify/api/namespacedpi/#logicalposition).
#### Constructors
##### new LogicalSize()
```ts
new LogicalSize(width, height): LogicalSize
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `width` | `number` |
| `height` | `number` |
###### Returns
[`LogicalSize`](/taurify/api/namespacedpi/#logicalsize)
##### new LogicalSize()
```ts
new LogicalSize(object): LogicalSize
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `object` | `object` |
| `object.Logical` | `object` |
| `object.Logical.height` | `number` |
| `object.Logical.width` | `number` |
###### Returns
[`LogicalSize`](/taurify/api/namespacedpi/#logicalsize)
##### new LogicalSize()
```ts
new LogicalSize(object): LogicalSize
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `object` | `object` |
| `object.height` | `number` |
| `object.width` | `number` |
###### Returns
[`LogicalSize`](/taurify/api/namespacedpi/#logicalsize)
#### Properties
| Property | Modifier | Type | Default value | Defined in |
| ------ | ------ | ------ | ------ | ------ |
| `height` | `public` | `number` | `undefined` | |
| `type` | `readonly` | `"Logical"` | `'Logical'` | |
| `width` | `public` | `number` | `undefined` | |
#### Methods
##### \_\_TAURI\_TO\_IPC\_KEY\_\_()
```ts
__TAURI_TO_IPC_KEY__(): object
```
###### Returns
`object`
| Name | Type | Defined in |
| ------ | ------ | ------ |
| `height` | `number` | |
| `width` | `number` | |
##### toJSON()
```ts
toJSON(): object
```
###### Returns
`object`
| Name | Type | Defined in |
| ------ | ------ | ------ |
| `height` | `number` | |
| `width` | `number` | |
##### toPhysical()
```ts
toPhysical(scaleFactor): PhysicalSize
```
Converts the logical size to a physical one.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `scaleFactor` | `number` |
###### Returns
[`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize)
###### Example
```typescript
import { LogicalSize } from '@crabnebula/taurify-api/dpi';
import { getCurrentWindow } from '@crabnebula/taurify-api/window';
const appWindow = getCurrentWindow();
const factor = await appWindow.scaleFactor();
const size = new LogicalSize(400, 500);
const physical = size.toPhysical(factor);
```
***
### PhysicalPosition
A position represented in physical pixels.
For an explanation of what physical pixels are, see description of [`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize).
#### Constructors
##### new PhysicalPosition()
```ts
new PhysicalPosition(x, y): PhysicalPosition
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `x` | `number` |
| `y` | `number` |
###### Returns
[`PhysicalPosition`](/taurify/api/namespacedpi/#physicalposition)
##### new PhysicalPosition()
```ts
new PhysicalPosition(object): PhysicalPosition
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `object` | `object` |
| `object.Physical` | `object` |
| `object.Physical.x` | `number` |
| `object.Physical.y` | `number` |
###### Returns
[`PhysicalPosition`](/taurify/api/namespacedpi/#physicalposition)
##### new PhysicalPosition()
```ts
new PhysicalPosition(object): PhysicalPosition
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `object` | `object` |
| `object.x` | `number` |
| `object.y` | `number` |
###### Returns
[`PhysicalPosition`](/taurify/api/namespacedpi/#physicalposition)
#### Properties
| Property | Modifier | Type | Default value | Defined in |
| ------ | ------ | ------ | ------ | ------ |
| `type` | `readonly` | `"Physical"` | `'Physical'` | |
| `x` | `public` | `number` | `undefined` | |
| `y` | `public` | `number` | `undefined` | |
#### Methods
##### \_\_TAURI\_TO\_IPC\_KEY\_\_()
```ts
__TAURI_TO_IPC_KEY__(): object
```
###### Returns
`object`
| Name | Type | Defined in |
| ------ | ------ | ------ |
| `x` | `number` | |
| `y` | `number` | |
##### toJSON()
```ts
toJSON(): object
```
###### Returns
`object`
| Name | Type | Defined in |
| ------ | ------ | ------ |
| `x` | `number` | |
| `y` | `number` | |
##### toLogical()
```ts
toLogical(scaleFactor): LogicalPosition
```
Converts the physical position to a logical one.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `scaleFactor` | `number` |
###### Returns
[`LogicalPosition`](/taurify/api/namespacedpi/#logicalposition)
###### Example
```typescript
import { PhysicalPosition } from '@crabnebula/taurify-api/dpi';
import { getCurrentWindow } from '@crabnebula/taurify-api/window';
const appWindow = getCurrentWindow();
const factor = await appWindow.scaleFactor();
const position = new PhysicalPosition(400, 500);
const physical = position.toLogical(factor);
```
***
### PhysicalSize
A size represented in physical pixels.
Physical pixels represent actual screen pixels, and are DPI-independent.
For high-DPI windows, this means that any point in the window on the screen
will have a different position in logical pixels (@linkcode LogicalSize).
For physical-pixel-based position, see [`PhysicalPosition`](/taurify/api/namespacedpi/#physicalposition).
#### Constructors
##### new PhysicalSize()
```ts
new PhysicalSize(width, height): PhysicalSize
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `width` | `number` |
| `height` | `number` |
###### Returns
[`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize)
##### new PhysicalSize()
```ts
new PhysicalSize(object): PhysicalSize
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `object` | `object` |
| `object.Physical` | `object` |
| `object.Physical.height` | `number` |
| `object.Physical.width` | `number` |
###### Returns
[`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize)
##### new PhysicalSize()
```ts
new PhysicalSize(object): PhysicalSize
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `object` | `object` |
| `object.height` | `number` |
| `object.width` | `number` |
###### Returns
[`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize)
#### Properties
| Property | Modifier | Type | Default value | Defined in |
| ------ | ------ | ------ | ------ | ------ |
| `height` | `public` | `number` | `undefined` | |
| `type` | `readonly` | `"Physical"` | `'Physical'` | |
| `width` | `public` | `number` | `undefined` | |
#### Methods
##### \_\_TAURI\_TO\_IPC\_KEY\_\_()
```ts
__TAURI_TO_IPC_KEY__(): object
```
###### Returns
`object`
| Name | Type | Defined in |
| ------ | ------ | ------ |
| `height` | `number` | |
| `width` | `number` | |
##### toJSON()
```ts
toJSON(): object
```
###### Returns
`object`
| Name | Type | Defined in |
| ------ | ------ | ------ |
| `height` | `number` | |
| `width` | `number` | |
##### toLogical()
```ts
toLogical(scaleFactor): LogicalSize
```
Converts the physical size to a logical one.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `scaleFactor` | `number` |
###### Returns
[`LogicalSize`](/taurify/api/namespacedpi/#logicalsize)
###### Example
```typescript
import { getCurrentWindow } from '@crabnebula/taurify-api/window';
const appWindow = getCurrentWindow();
const factor = await appWindow.scaleFactor();
const size = await appWindow.innerSize(); // PhysicalSize
const logical = size.toLogical(factor);
```
***
### Position
A position represented either in physical or in logical pixels.
This type is basically a union type of [`LogicalSize`](/taurify/api/namespacedpi/#logicalsize) and [`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize)
but comes in handy when using `tauri::Position` in Rust as an argument to a command, as this class
automatically serializes into a valid format so it can be deserialized correctly into `tauri::Position`
So instead of
```typescript
import { invoke } from '@crabnebula/taurify-api/core';
import { LogicalPosition, PhysicalPosition } from '@crabnebula/taurify-api/dpi';
const position: LogicalPosition | PhysicalPosition = someFunction(); // where someFunction returns either LogicalPosition or PhysicalPosition
const validPosition = position instanceof LogicalPosition
? { Logical: { x: position.x, y: position.y } }
: { Physical: { x: position.x, y: position.y } }
await invoke("do_something_with_position", { position: validPosition });
```
You can just use [`Position`](/taurify/api/namespacedpi/#position)
```typescript
import { invoke } from '@crabnebula/taurify-api/core';
import { LogicalPosition, PhysicalPosition, Position } from '@crabnebula/taurify-api/dpi';
const position: LogicalPosition | PhysicalPosition = someFunction(); // where someFunction returns either LogicalPosition or PhysicalPosition
const validPosition = new Position(position);
await invoke("do_something_with_position", { position: validPosition });
```
#### Constructors
##### new Position()
```ts
new Position(position): Position
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `position` | [`LogicalPosition`](/taurify/api/namespacedpi/#logicalposition) \| [`PhysicalPosition`](/taurify/api/namespacedpi/#physicalposition) |
###### Returns
[`Position`](/taurify/api/namespacedpi/#position)
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `position` | [`LogicalPosition`](/taurify/api/namespacedpi/#logicalposition) \| [`PhysicalPosition`](/taurify/api/namespacedpi/#physicalposition) | |
#### Methods
##### \_\_TAURI\_TO\_IPC\_KEY\_\_()
```ts
__TAURI_TO_IPC_KEY__(): object
```
###### Returns
`object`
##### toJSON()
```ts
toJSON(): object
```
###### Returns
`object`
##### toLogical()
```ts
toLogical(scaleFactor): LogicalPosition
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `scaleFactor` | `number` |
###### Returns
[`LogicalPosition`](/taurify/api/namespacedpi/#logicalposition)
##### toPhysical()
```ts
toPhysical(scaleFactor): PhysicalPosition
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `scaleFactor` | `number` |
###### Returns
[`PhysicalPosition`](/taurify/api/namespacedpi/#physicalposition)
***
### Size
A size represented either in physical or in logical pixels.
This type is basically a union type of [`LogicalSize`](/taurify/api/namespacedpi/#logicalsize) and [`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize)
but comes in handy when using `tauri::Size` in Rust as an argument to a command, as this class
automatically serializes into a valid format so it can be deserialized correctly into `tauri::Size`
So instead of
```typescript
import { invoke } from '@crabnebula/taurify-api/core';
import { LogicalSize, PhysicalSize } from '@crabnebula/taurify-api/dpi';
const size: LogicalSize | PhysicalSize = someFunction(); // where someFunction returns either LogicalSize or PhysicalSize
const validSize = size instanceof LogicalSize
? { Logical: { width: size.width, height: size.height } }
: { Physical: { width: size.width, height: size.height } }
await invoke("do_something_with_size", { size: validSize });
```
You can just use [`Size`](/taurify/api/namespacedpi/#size)
```typescript
import { invoke } from '@crabnebula/taurify-api/core';
import { LogicalSize, PhysicalSize, Size } from '@crabnebula/taurify-api/dpi';
const size: LogicalSize | PhysicalSize = someFunction(); // where someFunction returns either LogicalSize or PhysicalSize
const validSize = new Size(size);
await invoke("do_something_with_size", { size: validSize });
```
#### Constructors
##### new Size()
```ts
new Size(size): Size
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `size` | [`LogicalSize`](/taurify/api/namespacedpi/#logicalsize) \| [`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize) |
###### Returns
[`Size`](/taurify/api/namespacedpi/#size)
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `size` | [`LogicalSize`](/taurify/api/namespacedpi/#logicalsize) \| [`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize) | |
#### Methods
##### \_\_TAURI\_TO\_IPC\_KEY\_\_()
```ts
__TAURI_TO_IPC_KEY__(): object
```
###### Returns
`object`
##### toJSON()
```ts
toJSON(): object
```
###### Returns
`object`
##### toLogical()
```ts
toLogical(scaleFactor): LogicalSize
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `scaleFactor` | `number` |
###### Returns
[`LogicalSize`](/taurify/api/namespacedpi/#logicalsize)
##### toPhysical()
```ts
toPhysical(scaleFactor): PhysicalSize
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `scaleFactor` | `number` |
###### Returns
[`PhysicalSize`](/taurify/api/namespacedpi/#physicalsize)
# event
The event system allows you to emit events to the backend and listen to events from it.
## Enumerations
### TauriEvent
#### Enumeration Members
##### DRAG\_DROP
```ts
DRAG_DROP: "tauri://drag-drop";
```
##### DRAG\_ENTER
```ts
DRAG_ENTER: "tauri://drag-enter";
```
##### DRAG\_LEAVE
```ts
DRAG_LEAVE: "tauri://drag-leave";
```
##### DRAG\_OVER
```ts
DRAG_OVER: "tauri://drag-over";
```
##### WEBVIEW\_CREATED
```ts
WEBVIEW_CREATED: "tauri://webview-created";
```
##### WINDOW\_BLUR
```ts
WINDOW_BLUR: "tauri://blur";
```
##### WINDOW\_CLOSE\_REQUESTED
```ts
WINDOW_CLOSE_REQUESTED: "tauri://close-requested";
```
##### WINDOW\_CREATED
```ts
WINDOW_CREATED: "tauri://window-created";
```
##### WINDOW\_DESTROYED
```ts
WINDOW_DESTROYED: "tauri://destroyed";
```
##### WINDOW\_FOCUS
```ts
WINDOW_FOCUS: "tauri://focus";
```
##### WINDOW\_MOVED
```ts
WINDOW_MOVED: "tauri://move";
```
##### WINDOW\_RESIZED
```ts
WINDOW_RESIZED: "tauri://resize";
```
##### WINDOW\_SCALE\_FACTOR\_CHANGED
```ts
WINDOW_SCALE_FACTOR_CHANGED: "tauri://scale-change";
```
##### WINDOW\_THEME\_CHANGED
```ts
WINDOW_THEME_CHANGED: "tauri://theme-changed";
```
## Interfaces
### Event\
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `event` | [`EventName`](/taurify/api/namespaceevent/#eventname) | Event name | |
| `id` | `number` | Event identifier used to unlisten | |
| `payload` | `T` | Event payload | |
***
### Options
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `target?` | `string` \| [`EventTarget`](/taurify/api/namespaceevent/#eventtarget) | The event target to listen to, defaults to `{ kind: 'Any' }`, see [EventTarget](/taurify/api/namespaceevent/#eventtarget). If a string is provided, EventTarget.AnyLabel is used. | |
## Type Aliases
### EventCallback()\
```ts
type EventCallback: (event) => void;
```
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `event` | [`Event`](/taurify/api/namespaceevent/#eventt)\<`T`\> |
#### Returns
`void`
***
### EventName
```ts
type EventName: `${TauriEvent}` | string & Record;
```
***
### EventTarget
```ts
type EventTarget:
| object
| object
| object
| object
| object
| object;
```
***
### UnlistenFn()
```ts
type UnlistenFn: () => void;
```
#### Returns
`void`
## Functions
### emit()
```ts
function emit(event, payload?): Promise
```
Emits an event to all [targets](/taurify/api/namespaceevent/#eventtarget).
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `event` | `string` | Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. |
| `payload`? | `T` | Event payload. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { emit } from '@crabnebula/taurify-api/event';
await emit('frontend-loaded', { loggedIn: true, token: 'authToken' });
```
***
### emitTo()
```ts
function emitTo(
target,
event,
payload?): Promise
```
Emits an event to all [targets](/taurify/api/namespaceevent/#eventtarget) matching the given target.
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `target` | `string` \| [`EventTarget`](/taurify/api/namespaceevent/#eventtarget) | Label of the target Window/Webview/WebviewWindow or raw [EventTarget](/taurify/api/namespaceevent/#eventtarget) object. |
| `event` | `string` | Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. |
| `payload`? | `T` | Event payload. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { emitTo } from '@crabnebula/taurify-api/event';
await emitTo('main', 'frontend-loaded', { loggedIn: true, token: 'authToken' });
```
***
### listen()
```ts
function listen(
event,
handler,
options?): Promise
```
Listen to an emitted event to any [target](/taurify/api/namespaceevent/#eventtarget).
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `event` | [`EventName`](/taurify/api/namespaceevent/#eventname) | Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. |
| `handler` | [`EventCallback`](/taurify/api/namespaceevent/#eventcallbackt)\<`T`\> | Event handler callback. |
| `options`? | [`Options`](/taurify/api/namespaceevent/#options) | Event listening options. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`UnlistenFn`](/taurify/api/namespaceevent/#unlistenfn)\>
A promise resolving to a function to unlisten to the event.
Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
#### Example
```typescript
import { listen } from '@crabnebula/taurify-api/event';
const unlisten = await listen('error', (event) => {
console.log(`Got error, payload: ${event.payload}`);
});
// you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
unlisten();
```
***
### once()
```ts
function once(
event,
handler,
options?): Promise
```
Listens once to an emitted event to any [target](/taurify/api/namespaceevent/#eventtarget).
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `event` | [`EventName`](/taurify/api/namespaceevent/#eventname) | Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. |
| `handler` | [`EventCallback`](/taurify/api/namespaceevent/#eventcallbackt)\<`T`\> | Event handler callback. |
| `options`? | [`Options`](/taurify/api/namespaceevent/#options) | Event listening options. |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`UnlistenFn`](/taurify/api/namespaceevent/#unlistenfn)\>
A promise resolving to a function to unlisten to the event.
Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
#### Example
```typescript
import { once } from '@crabnebula/taurify-api/event';
interface LoadedPayload {
loggedIn: boolean,
token: string
}
const unlisten = await once('loaded', (event) => {
console.log(`App is loaded, loggedIn: ${event.payload.loggedIn}, token: ${event.payload.token}`);
});
// you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
unlisten();
```
# fs
Access the file system.
## Security
This module prevents path traversal, not allowing parent directory accessors to be used
(i.e. "/usr/path/to/../file" or "../path/to/file" paths are not allowed).
Paths accessed with this API must be either relative to one of the [base directories](/taurify/api/namespacepath/#basedirectory)
or created with the [path API](https://v2.tauri.app/taurify/api/namespacepath/).
The API has a scope configuration that forces you to restrict the paths that can be accessed using glob patterns.
The scope configuration is an array of glob patterns describing file/directory paths that are allowed.
For instance, this scope configuration allows **all** enabled `fs` APIs to (only) access files in the
*databases* directory of the [`$APPDATA` directory](https://v2.tauri.app/taurify/api/namespacepath/#appdatadir):
```json
{
"permissions": [
{
"identifier": "fs:scope",
"allow": [{ "path": "$APPDATA/databases/*" }]
}
]
}
```
Scopes can also be applied to specific `fs` APIs by using the API's identifier instead of `fs:scope`:
```json
{
"permissions": [
{
"identifier": "fs:allow-exists",
"allow": [{ "path": "$APPDATA/databases/*" }]
}
]
}
```
Notice the use of the `$APPDATA` variable. The value is injected at runtime, resolving to the [app data directory](https://v2.tauri.app/taurify/api/namespacepath/#appdatadir).
The available variables are:
[`$APPCONFIG`](https://v2.tauri.app/taurify/api/namespacepath/#appconfigdir),
[`$APPDATA`](https://v2.tauri.app/taurify/api/namespacepath/#appdatadir),
[`$APPLOCALDATA`](https://v2.tauri.app/taurify/api/namespacepath/#applocaldatadir),
[`$APPCACHE`](https://v2.tauri.app/taurify/api/namespacepath/#appcachedir),
[`$APPLOG`](https://v2.tauri.app/taurify/api/namespacepath/#applogdir),
[`$AUDIO`](https://v2.tauri.app/taurify/api/namespacepath/#audiodir),
[`$CACHE`](https://v2.tauri.app/taurify/api/namespacepath/#cachedir),
[`$CONFIG`](https://v2.tauri.app/taurify/api/namespacepath/#configdir),
[`$DATA`](https://v2.tauri.app/taurify/api/namespacepath/#datadir),
[`$LOCALDATA`](https://v2.tauri.app/taurify/api/namespacepath/#localdatadir),
[`$DESKTOP`](https://v2.tauri.app/taurify/api/namespacepath/#desktopdir),
[`$DOCUMENT`](https://v2.tauri.app/taurify/api/namespacepath/#documentdir),
[`$DOWNLOAD`](https://v2.tauri.app/taurify/api/namespacepath/#downloaddir),
[`$EXE`](https://v2.tauri.app/taurify/api/namespacepath/#executabledir),
[`$FONT`](https://v2.tauri.app/taurify/api/namespacepath/#fontdir),
[`$HOME`](https://v2.tauri.app/taurify/api/namespacepath/#homedir),
[`$PICTURE`](https://v2.tauri.app/taurify/api/namespacepath/#picturedir),
[`$PUBLIC`](https://v2.tauri.app/taurify/api/namespacepath/#publicdir),
[`$RUNTIME`](https://v2.tauri.app/taurify/api/namespacepath/#runtimedir),
[`$TEMPLATE`](https://v2.tauri.app/taurify/api/namespacepath/#templatedir),
[`$VIDEO`](https://v2.tauri.app/taurify/api/namespacepath/#videodir),
[`$RESOURCE`](https://v2.tauri.app/taurify/api/namespacepath/#resourcedir),
[`$TEMP`](https://v2.tauri.app/taurify/api/namespacepath/#tempdir).
Trying to execute any API with a URL not configured on the scope results in a promise rejection due to denied access.
## References
### BaseDirectory
Re-exports [BaseDirectory](/taurify/api/namespacepath/#basedirectory)
## Enumerations
### SeekMode
#### Enumeration Members
##### Current
```ts
Current: 1;
```
##### End
```ts
End: 2;
```
##### Start
```ts
Start: 0;
```
## Classes
### FileHandle
The Tauri abstraction for reading and writing files.
#### Extends
- [`Resource`](/taurify/api/namespacecore/#resource)
#### Constructors
##### new FileHandle()
```ts
new FileHandle(rid): FileHandle
```
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `rid` | `number` |
###### Returns
[`FileHandle`](/taurify/api/namespacefs/#filehandle)
###### Inherited from
[`Resource`](/taurify/api/namespacecore/#resource).[`constructor`](/taurify/api/namespacecore/#constructors-2)
#### Accessors
##### rid
###### Get Signature
```ts
get rid(): number
```
###### Returns
`number`
###### Inherited from
[`Resource`](/taurify/api/namespacecore/#resource).[`rid`](/taurify/api/namespacecore/#rid)
#### Methods
##### close()
```ts
close(): Promise
```
Destroys and cleans up this resource from memory.
**You should not call any method on this object anymore and should drop any reference to it.**
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
###### Inherited from
[`Resource`](/taurify/api/namespacecore/#resource).[`close`](/taurify/api/namespacecore/#close)
##### read()
```ts
read(buffer): Promise
```
Reads up to `p.byteLength` bytes into `p`. It resolves to the number of
bytes read (`0` < `n` <= `p.byteLength`) and rejects if any error
encountered. Even if `read()` resolves to `n` < `p.byteLength`, it may
use all of `p` as scratch space during the call. If some data is
available but not `p.byteLength` bytes, `read()` conventionally resolves
to what is available instead of waiting for more.
When `read()` encounters end-of-file condition, it resolves to EOF
(`null`).
When `read()` encounters an error, it rejects with an error.
Callers should always process the `n` > `0` bytes returned before
considering the EOF (`null`). Doing so correctly handles I/O errors that
happen after reading some bytes and also both of the allowed EOF
behaviors.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `buffer` | [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\> |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`null` \| `number`\>
###### Example
```typescript
import { open, BaseDirectory } from "@crabnebula/taurify-api/fs"
// if "$APPCONFIG/foo/bar.txt" contains the text "hello world":
const file = await open("foo/bar.txt", { baseDir: BaseDirectory.AppConfig });
const buf = new Uint8Array(100);
const numberOfBytesRead = await file.read(buf); // 11 bytes
const text = new TextDecoder().decode(buf); // "hello world"
await file.close();
```
##### seek()
```ts
seek(offset, whence): Promise
```
Seek sets the offset for the next `read()` or `write()` to offset,
interpreted according to `whence`: `Start` means relative to the
start of the file, `Current` means relative to the current offset,
and `End` means relative to the end. Seek resolves to the new offset
relative to the start of the file.
Seeking to an offset before the start of the file is an error. Seeking to
any positive offset is legal, but the behavior of subsequent I/O
operations on the underlying object is implementation-dependent.
It returns the number of cursor position.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `offset` | `number` |
| `whence` | [`SeekMode`](/taurify/api/namespacefs/#seekmode) |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`number`\>
###### Example
```typescript
import { open, SeekMode, BaseDirectory } from '@crabnebula/taurify-api/fs';
// Given hello.txt pointing to file with "Hello world", which is 11 bytes long:
const file = await open('hello.txt', { read: true, write: true, truncate: true, create: true, baseDir: BaseDirectory.AppLocalData });
await file.write(new TextEncoder().encode("Hello world"));
// Seek 6 bytes from the start of the file
console.log(await file.seek(6, SeekMode.Start)); // "6"
// Seek 2 more bytes from the current position
console.log(await file.seek(2, SeekMode.Current)); // "8"
// Seek backwards 2 bytes from the end of the file
console.log(await file.seek(-2, SeekMode.End)); // "9" (e.g. 11-2)
await file.close();
```
##### stat()
```ts
stat(): Promise
```
Returns a [`FileInfo`](/taurify/api/namespacefs/#fileinfo) for this file.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`FileInfo`](/taurify/api/namespacefs/#fileinfo)\>
###### Example
```typescript
import { open, BaseDirectory } from '@crabnebula/taurify-api/fs';
const file = await open("file.txt", { read: true, baseDir: BaseDirectory.AppLocalData });
const fileInfo = await file.stat();
console.log(fileInfo.isFile); // true
await file.close();
```
##### truncate()
```ts
truncate(len?): Promise
```
Truncates or extends this file, to reach the specified `len`.
If `len` is not specified then the entire file contents are truncated.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `len`? | `number` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
###### Example
```typescript
import { open, BaseDirectory } from '@crabnebula/taurify-api/fs';
// truncate the entire file
const file = await open("my_file.txt", { read: true, write: true, create: true, baseDir: BaseDirectory.AppLocalData });
await file.truncate();
// truncate part of the file
const file = await open("my_file.txt", { read: true, write: true, create: true, baseDir: BaseDirectory.AppLocalData });
await file.write(new TextEncoder().encode("Hello World"));
await file.truncate(7);
const data = new Uint8Array(32);
await file.read(data);
console.log(new TextDecoder().decode(data)); // Hello W
await file.close();
```
##### write()
```ts
write(data): Promise
```
Writes `data.byteLength` bytes from `data` to the underlying data stream. It
resolves to the number of bytes written from `data` (`0` <= `n` <=
`data.byteLength`) or reject with the error encountered that caused the
write to stop early. `write()` must reject with a non-null error if
would resolve to `n` < `data.byteLength`. `write()` must not modify the
slice data, even temporarily.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `data` | [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\> |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`number`\>
###### Example
```typescript
import { open, write, BaseDirectory } from '@crabnebula/taurify-api/fs';
const encoder = new TextEncoder();
const data = encoder.encode("Hello world");
const file = await open("bar.txt", { write: true, baseDir: BaseDirectory.AppLocalData });
const bytesWritten = await file.write(data); // 11
await file.close();
```
## Interfaces
### CopyFileOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `fromPathBaseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `fromPath`. | |
| `toPathBaseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `toPath`. | |
***
### CreateOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path` | |
***
### DebouncedWatchOptions
#### Extends
- [`WatchOptions`](/taurify/api/namespacefs/#watchoptions)
#### Properties
| Property | Type | Description | Inherited from | Defined in |
| ------ | ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path` | [`WatchOptions`](/taurify/api/namespacefs/#watchoptions).[`baseDir`](/taurify/api/namespacefs/#basedir-10) | |
| `delayMs?` | `number` | Debounce delay | - | |
| `recursive?` | `boolean` | Watch a directory recursively | [`WatchOptions`](/taurify/api/namespacefs/#watchoptions).[`recursive`](/taurify/api/namespacefs/#recursive-3) | |
***
### DirEntry
A disk entry which is either a file, a directory or a symlink.
This is the result of the [`readDir`](/taurify/api/namespacefs/#readdir).
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `isDirectory` | `boolean` | Specifies whether this entry is a directory or not. | |
| `isFile` | `boolean` | Specifies whether this entry is a file or not. | |
| `isSymlink` | `boolean` | Specifies whether this entry is a symlink or not. | |
| `name` | `string` | The name of the entry (file name with extension or directory name). | |
***
### ExistsOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path`. | |
***
### FileInfo
A FileInfo describes a file and is returned by `stat`, `lstat` or `fstat`.
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `atime` | `null` \| [`Date`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) | The last access time of the file. This corresponds to the `atime` field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not be available on all platforms. | |
| `birthtime` | `null` \| [`Date`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) | The creation time of the file. This corresponds to the `birthtime` field from `stat` on Mac/BSD and `ftCreationTime` on Windows. This may not be available on all platforms. | |
| `blksize` | `null` \| `number` | Blocksize for filesystem I/O. #### Platform-specific - **Windows:** Unsupported. | |
| `blocks` | `null` \| `number` | Number of blocks allocated to the file, in 512-byte units. #### Platform-specific - **Windows:** Unsupported. | |
| `dev` | `null` \| `number` | ID of the device containing the file. #### Platform-specific - **Windows:** Unsupported. | |
| `fileAttributes` | `null` \| `number` | This field contains the file system attribute information for a file or directory. For possible values and their descriptions, see [File Attribute Constants](https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants) in the Windows Dev Center #### Platform-specific - **macOS / Linux / Android / iOS:** Unsupported. | |
| `gid` | `null` \| `number` | Group ID of the owner of this file. #### Platform-specific - **Windows:** Unsupported. | |
| `ino` | `null` \| `number` | Inode number. #### Platform-specific - **Windows:** Unsupported. | |
| `isDirectory` | `boolean` | True if this is info for a regular directory. Mutually exclusive to `FileInfo.isFile` and `FileInfo.isSymlink`. | |
| `isFile` | `boolean` | True if this is info for a regular file. Mutually exclusive to `FileInfo.isDirectory` and `FileInfo.isSymlink`. | |
| `isSymlink` | `boolean` | True if this is info for a symlink. Mutually exclusive to `FileInfo.isFile` and `FileInfo.isDirectory`. | |
| `mode` | `null` \| `number` | The underlying raw `st_mode` bits that contain the standard Unix permissions for this file/directory. #### Platform-specific - **Windows:** Unsupported. | |
| `mtime` | `null` \| [`Date`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) | The last modification time of the file. This corresponds to the `mtime` field from `stat` on Linux/Mac OS and `ftLastWriteTime` on Windows. This may not be available on all platforms. | |
| `nlink` | `null` \| `number` | Number of hard links pointing to this file. #### Platform-specific - **Windows:** Unsupported. | |
| `rdev` | `null` \| `number` | Device ID of this file. #### Platform-specific - **Windows:** Unsupported. | |
| `readonly` | `boolean` | Whether this is a readonly (unwritable) file. | |
| `size` | `number` | The size of the file, in bytes. | |
| `uid` | `null` \| `number` | User ID of the owner of this file. #### Platform-specific - **Windows:** Unsupported. | |
***
### MkdirOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path` | |
| `mode?` | `number` | Permissions to use when creating the directory (defaults to `0o777`, before the process's umask). Ignored on Windows. | |
| `recursive?` | `boolean` | Defaults to `false`. If set to `true`, means that any intermediate directories will also be created (as with the shell command `mkdir -p`). | |
***
### OpenOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `append?` | `boolean` | Sets the option for the append mode. This option, when `true`, means that writes will append to a file instead of overwriting previous contents. Note that setting `{ write: true, append: true }` has the same effect as setting only `{ append: true }`. | |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path` | |
| `create?` | `boolean` | Sets the option to allow creating a new file, if one doesn't already exist at the specified path. Requires write or append access to be used. | |
| `createNew?` | `boolean` | Defaults to `false`. If set to `true`, no file, directory, or symlink is allowed to exist at the target location. Requires write or append access to be used. When createNew is set to `true`, create and truncate are ignored. | |
| `mode?` | `number` | Permissions to use if creating the file (defaults to `0o666`, before the process's umask). Ignored on Windows. | |
| `read?` | `boolean` | Sets the option for read access. This option, when `true`, means that the file should be read-able if opened. | |
| `truncate?` | `boolean` | Sets the option for truncating a previous file. If a file is successfully opened with this option set it will truncate the file to `0` size if it already exists. The file must be opened with write access for truncate to work. | |
| `write?` | `boolean` | Sets the option for write access. This option, when `true`, means that the file should be write-able if opened. If the file already exists, any write calls on it will overwrite its contents, by default without truncating it. | |
***
### ReadDirOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path` | |
***
### ReadFileOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path` | |
***
### RemoveOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path` | |
| `recursive?` | `boolean` | Defaults to `false`. If set to `true`, path will be removed even if it's a non-empty directory. | |
***
### RenameOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `newPathBaseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `newPath`. | |
| `oldPathBaseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `oldPath`. | |
***
### StatOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path`. | |
***
### TruncateOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path`. | |
***
### WatchEvent
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `attrs` | `unknown` | |
| `paths` | `string`[] | |
| `type` | [`WatchEventKind`](/taurify/api/namespacefs/#watcheventkind) | |
***
### WatchOptions
#### Extended by
- [`DebouncedWatchOptions`](/taurify/api/namespacefs/#debouncedwatchoptions)
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path` | |
| `recursive?` | `boolean` | Watch a directory recursively | |
***
### WriteFileOptions
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `append?` | `boolean` | Defaults to `false`. If set to `true`, will append to a file instead of overwriting previous contents. | |
| `baseDir?` | [`BaseDirectory`](/taurify/api/namespacepath/#basedirectory) | Base directory for `path` | |
| `create?` | `boolean` | Sets the option to allow creating a new file, if one doesn't already exist at the specified path (defaults to `true`). | |
| `createNew?` | `boolean` | Sets the option to create a new file, failing if it already exists. | |
| `mode?` | `number` | File permissions. Ignored on Windows. | |
## Type Aliases
### UnwatchFn()
```ts
type UnwatchFn: () => void;
```
#### Returns
`void`
***
### WatchEventKind
```ts
type WatchEventKind:
| "any"
| object
| object
| object
| object
| "other";
```
***
### WatchEventKindAccess
```ts
type WatchEventKindAccess: object | object | object | object;
```
***
### WatchEventKindCreate
```ts
type WatchEventKindCreate: object | object | object | object;
```
***
### WatchEventKindModify
```ts
type WatchEventKindModify:
| object
| object
| object
| object
| object;
```
***
### WatchEventKindRemove
```ts
type WatchEventKindRemove: object | object | object | object;
```
## Functions
### copyFile()
```ts
function copyFile(
fromPath,
toPath,
options?): Promise
```
Copies the contents and permissions of one file to another specified path, by default creating a new file if needed, else overwriting.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `fromPath` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `toPath` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`CopyFileOptions`](/taurify/api/namespacefs/#copyfileoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { copyFile, BaseDirectory } from '@crabnebula/taurify-api/fs';
await copyFile('app.conf', 'app.conf.bk', { fromPathBaseDir: BaseDirectory.AppConfig, toPathBaseDir: BaseDirectory.AppConfig });
```
***
### create()
```ts
function create(path, options?): Promise
```
Creates a file if none exists or truncates an existing file and resolves to
an instance of [`FileHandle`](/taurify/api/namespacefs/#filehandle).
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`CreateOptions`](/taurify/api/namespacefs/#createoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`FileHandle`](/taurify/api/namespacefs/#filehandle)\>
#### Example
```typescript
import { create, BaseDirectory } from "@crabnebula/taurify-api/fs"
const file = await create("foo/bar.txt", { baseDir: BaseDirectory.AppConfig });
await file.write(new TextEncoder().encode("Hello world"));
await file.close();
```
***
### exists()
```ts
function exists(path, options?): Promise
```
Check if a path exists.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`ExistsOptions`](/taurify/api/namespacefs/#existsoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\>
#### Example
```typescript
import { exists, BaseDirectory } from '@crabnebula/taurify-api/fs';
// Check if the `$APPDATA/avatar.png` file exists
await exists('avatar.png', { baseDir: BaseDirectory.AppData });
```
***
### lstat()
```ts
function lstat(path, options?): Promise
```
Resolves to a [`FileInfo`](/taurify/api/namespacefs/#fileinfo) for the specified `path`. If `path` is a
symlink, information for the symlink will be returned instead of what it
points to.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`StatOptions`](/taurify/api/namespacefs/#statoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`FileInfo`](/taurify/api/namespacefs/#fileinfo)\>
#### Example
```typescript
import { lstat, BaseDirectory } from '@crabnebula/taurify-api/fs';
const fileInfo = await lstat("hello.txt", { baseDir: BaseDirectory.AppLocalData });
console.log(fileInfo.isFile); // true
```
***
### mkdir()
```ts
function mkdir(path, options?): Promise
```
Creates a new directory with the specified path.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`MkdirOptions`](/taurify/api/namespacefs/#mkdiroptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { mkdir, BaseDirectory } from '@crabnebula/taurify-api/fs';
await mkdir('users', { baseDir: BaseDirectory.AppLocalData });
```
***
### open()
```ts
function open(path, options?): Promise
```
Open a file and resolve to an instance of [`FileHandle`](/taurify/api/namespacefs/#filehandle). The
file does not need to previously exist if using the `create` or `createNew`
open options. It is the callers responsibility to close the file when finished
with it.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`OpenOptions`](/taurify/api/namespacefs/#openoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`FileHandle`](/taurify/api/namespacefs/#filehandle)\>
#### Example
```typescript
import { open, BaseDirectory } from "@crabnebula/taurify-api/fs"
const file = await open("foo/bar.txt", { read: true, write: true, baseDir: BaseDirectory.AppLocalData });
// Do work with file
await file.close();
```
***
### readDir()
```ts
function readDir(path, options?): Promise
```
Reads the directory given by path and returns an array of `DirEntry`.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`ReadDirOptions`](/taurify/api/namespacefs/#readdiroptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`DirEntry`](/taurify/api/namespacefs/#direntry)[]\>
#### Example
```typescript
import { readDir, BaseDirectory } from '@crabnebula/taurify-api/fs';
import { join } from '../../path';
const dir = "users"
const entries = await readDir('users', { baseDir: BaseDirectory.AppLocalData });
processEntriesRecursively(dir, entries);
async function processEntriesRecursively(parent, entries) {
for (const entry of entries) {
console.log(`Entry: ${entry.name}`);
if (entry.isDirectory) {
const dir = await join(parent, entry.name);
processEntriesRecursively(dir, await readDir(dir, { baseDir: BaseDirectory.AppLocalData }))
}
}
}
```
***
### readFile()
```ts
function readFile(path, options?): Promise
```
Reads and resolves to the entire contents of a file as an array of bytes.
TextDecoder can be used to transform the bytes to string if required.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`ReadFileOptions`](/taurify/api/namespacefs/#readfileoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\>
#### Example
```typescript
import { readFile, BaseDirectory } from '@crabnebula/taurify-api/fs';
const contents = await readFile('avatar.png', { baseDir: BaseDirectory.Resource });
```
***
### readTextFile()
```ts
function readTextFile(path, options?): Promise
```
Reads and returns the entire contents of a file as UTF-8 string.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`ReadFileOptions`](/taurify/api/namespacefs/#readfileoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string`\>
#### Example
```typescript
import { readTextFile, BaseDirectory } from '@crabnebula/taurify-api/fs';
const contents = await readTextFile('app.conf', { baseDir: BaseDirectory.AppConfig });
```
***
### readTextFileLines()
```ts
function readTextFileLines(path, options?): Promise>
```
Returns an async AsyncIterableIterator over the lines of a file as UTF-8 string.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`ReadFileOptions`](/taurify/api/namespacefs/#readfileoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`AsyncIterableIterator`\<`string`\>\>
#### Example
```typescript
import { readTextFileLines, BaseDirectory } from '@crabnebula/taurify-api/fs';
const lines = await readTextFileLines('app.conf', { baseDir: BaseDirectory.AppConfig });
for await (const line of lines) {
console.log(line);
}
```
You could also call AsyncIterableIterator.next to advance the
iterator so you can lazily read the next line whenever you want.
***
### remove()
```ts
function remove(path, options?): Promise
```
Removes the named file or directory.
If the directory is not empty and the `recursive` option isn't set to true, the promise will be rejected.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`RemoveOptions`](/taurify/api/namespacefs/#removeoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { remove, BaseDirectory } from '@crabnebula/taurify-api/fs';
await remove('users/file.txt', { baseDir: BaseDirectory.AppLocalData });
await remove('users', { baseDir: BaseDirectory.AppLocalData });
```
***
### rename()
```ts
function rename(
oldPath,
newPath,
options?): Promise
```
Renames (moves) oldpath to newpath. Paths may be files or directories.
If newpath already exists and is not a directory, rename() replaces it.
OS-specific restrictions may apply when oldpath and newpath are in different directories.
On Unix, this operation does not follow symlinks at either path.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `oldPath` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `newPath` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`RenameOptions`](/taurify/api/namespacefs/#renameoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { rename, BaseDirectory } from '@crabnebula/taurify-api/fs';
await rename('avatar.png', 'deleted.png', { oldPathBaseDir: BaseDirectory.App, newPathBaseDir: BaseDirectory.AppLocalData });
```
***
### size()
```ts
function size(path): Promise
```
Get the size of a file or directory. For files, the `stat` functions can be used as well.
If `path` is a directory, this function will recursively iterate over every file and every directory inside of `path` and therefore will be very time consuming if used on larger directories.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`number`\>
#### Example
```typescript
import { size, BaseDirectory } from '@crabnebula/taurify-api/fs';
// Get the size of the `$APPDATA/tauri` directory.
const dirSize = await size('tauri', { baseDir: BaseDirectory.AppData });
console.log(dirSize); // 1024
```
***
### stat()
```ts
function stat(path, options?): Promise
```
Resolves to a [`FileInfo`](/taurify/api/namespacefs/#fileinfo) for the specified `path`. Will always
follow symlinks but will reject if the symlink points to a path outside of the scope.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `options`? | [`StatOptions`](/taurify/api/namespacefs/#statoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`FileInfo`](/taurify/api/namespacefs/#fileinfo)\>
#### Example
```typescript
import { stat, BaseDirectory } from '@crabnebula/taurify-api/fs';
const fileInfo = await stat("hello.txt", { baseDir: BaseDirectory.AppLocalData });
console.log(fileInfo.isFile); // true
```
***
### truncate()
```ts
function truncate(
path,
len?,
options?): Promise
```
Truncates or extends the specified file, to reach the specified `len`.
If `len` is `0` or not specified, then the entire file contents are truncated.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `len`? | `number` |
| `options`? | [`TruncateOptions`](/taurify/api/namespacefs/#truncateoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { truncate, readTextFile, writeTextFile, BaseDirectory } from '@crabnebula/taurify-api/fs';
// truncate the entire file
await truncate("my_file.txt", 0, { baseDir: BaseDirectory.AppLocalData });
// truncate part of the file
const filePath = "file.txt";
await writeTextFile(filePath, "Hello World", { baseDir: BaseDirectory.AppLocalData });
await truncate(filePath, 7, { baseDir: BaseDirectory.AppLocalData });
const data = await readTextFile(filePath, { baseDir: BaseDirectory.AppLocalData });
console.log(data); // "Hello W"
```
***
### watch()
```ts
function watch(
paths,
cb,
options?): Promise
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `paths` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) \| `string`[] \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL)[] |
| `cb` | (`event`) => `void` |
| `options`? | [`DebouncedWatchOptions`](/taurify/api/namespacefs/#debouncedwatchoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`UnwatchFn`](/taurify/api/namespacefs/#unwatchfn)\>
***
### watchImmediate()
```ts
function watchImmediate(
paths,
cb,
options?): Promise
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `paths` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) \| `string`[] \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL)[] |
| `cb` | (`event`) => `void` |
| `options`? | [`WatchOptions`](/taurify/api/namespacefs/#watchoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`UnwatchFn`](/taurify/api/namespacefs/#unwatchfn)\>
***
### writeFile()
```ts
function writeFile(
path,
data,
options?): Promise
```
Write `data` to the given `path`, by default creating a new file if needed, else overwriting.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `data` | [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\> \| [`ReadableStream`](https://developer.mozilla.org/docs/Web/API/ReadableStream)\<[`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\>\> |
| `options`? | [`WriteFileOptions`](/taurify/api/namespacefs/#writefileoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { writeFile, BaseDirectory } from '@crabnebula/taurify-api/fs';
let encoder = new TextEncoder();
let data = encoder.encode("Hello World");
await writeFile('file.txt', data, { baseDir: BaseDirectory.AppLocalData });
```
***
### writeTextFile()
```ts
function writeTextFile(
path,
data,
options?): Promise
```
Writes UTF-8 string `data` to the given `path`, by default creating a new file if needed, else overwriting.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) |
| `data` | `string` |
| `options`? | [`WriteFileOptions`](/taurify/api/namespacefs/#writefileoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { writeTextFile, BaseDirectory } from '@crabnebula/taurify-api/fs';
await writeTextFile('file.txt', "Hello world", { baseDir: BaseDirectory.AppLocalData });
```
# geolocation
## Type Aliases
### Coordinates
```ts
type Coordinates: object;
```
#### Type declaration
| Name | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `accuracy` | `number` | Accuracy level of the latitude and longitude coordinates in meters. | |
| `altitude` | `number` \| `null` | The altitude the user is at, if available. | |
| `altitudeAccuracy` | `number` \| `null` | Accuracy level of the altitude coordinate in meters, if available. Available on all iOS versions and on Android 8 and above. | |
| `heading` | `number` \| `null` | The heading the user is facing, if available. | |
| `latitude` | `number` | Latitude in decimal degrees. | |
| `longitude` | `number` | Longitude in decimal degrees. | |
| `speed` | `number` \| `null` | - | |
***
### PermissionStatus
```ts
type PermissionStatus: object;
```
#### Type declaration
| Name | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `coarseLocation` | [`PermissionState`](/taurify/api/namespacecore/#permissionstate) | Permissions state for the coarseLoaction alias. On Android it requests/checks ACCESS_COARSE_LOCATION. On Android 12+, users can choose between Approximate location (ACCESS_COARSE_LOCATION) and Precise location (ACCESS_FINE_LOCATION). On iOS it will have the same value as the `location` alias. | |
| `location` | [`PermissionState`](/taurify/api/namespacecore/#permissionstate) | Permission state for the location alias. On Android it requests/checks both ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions. On iOS it requests/checks location permissions. | |
***
### PermissionType
```ts
type PermissionType: "location" | "coarseLocation";
```
***
### Position
```ts
type Position: object;
```
#### Type declaration
| Name | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `coords` | [`Coordinates`](/taurify/api/namespacegeolocation/#coordinates) | The GPD coordinates along with the accuracy of the data. | |
| `timestamp` | `number` | Creation time for these coordinates. | |
***
### PositionOptions
```ts
type PositionOptions: object;
```
#### Type declaration
| Name | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `enableHighAccuracy` | `boolean` | High accuracy mode (such as GPS, if available) Will be ignored on Android 12+ if users didn't grant the ACCESS_FINE_LOCATION permission (`coarseLocation` permission). | |
| `maximumAge` | `number` | The maximum age in milliseconds of a possible cached position that is acceptable to return. Default: 0 Ignored on iOS | |
| `timeout` | `number` | The maximum wait time in milliseconds for location updates. On Android the timeout gets ignored for getCurrentPosition. Ignored on iOS | |
## Functions
### checkPermissions()
```ts
function checkPermissions(): Promise
```
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`PermissionStatus`](/taurify/api/namespacegeolocation/#permissionstatus)\>
***
### clearWatch()
```ts
function clearWatch(channelId): Promise
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `channelId` | `number` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### getCurrentPosition()
```ts
function getCurrentPosition(options?): Promise
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `options`? | [`PositionOptions`](/taurify/api/namespacegeolocation/#positionoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Position`](/taurify/api/namespacegeolocation/#position)\>
***
### requestPermissions()
```ts
function requestPermissions(permissions): Promise
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `permissions` | `null` \| [`PermissionType`](/taurify/api/namespacegeolocation/#permissiontype)[] |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`PermissionStatus`](/taurify/api/namespacegeolocation/#permissionstatus)\>
***
### watchPosition()
```ts
function watchPosition(options, cb): Promise
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `options` | [`PositionOptions`](/taurify/api/namespacegeolocation/#positionoptions) |
| `cb` | (`location`, `error`?) => `void` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`number`\>
# globalShortcut
Register global shortcuts.
## Interfaces
### ShortcutEvent
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `id` | `number` | |
| `shortcut` | `string` | |
| `state` | `"Released"` \| `"Pressed"` | |
## Type Aliases
### ShortcutHandler()
```ts
type ShortcutHandler: (event) => void;
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `event` | [`ShortcutEvent`](/taurify/api/namespaceglobalshortcut/#shortcutevent) |
#### Returns
`void`
## Functions
### isRegistered()
```ts
function isRegistered(shortcut): Promise
```
Determines whether the given shortcut is registered by this application or not.
If the shortcut is registered by another application, it will still return `false`.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `shortcut` | `string` | shortcut definition, modifiers and key separated by "+" e.g. CmdOrControl+Q |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\>
#### Example
```typescript
import { isRegistered } from '@crabnebula/taurify-api/global-shortcut';
const isRegistered = await isRegistered('CommandOrControl+P');
```
***
### register()
```ts
function register(shortcuts, handler): Promise
```
Register a global shortcut or a list of shortcuts.
The handler is called when any of the registered shortcuts are pressed by the user.
If the shortcut is already taken by another application, the handler will not be triggered.
Make sure the shortcut is as unique as possible while still taking user experience into consideration.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `shortcuts` | `string` \| `string`[] | - |
| `handler` | [`ShortcutHandler`](/taurify/api/namespaceglobalshortcut/#shortcuthandler) | Shortcut handler callback - takes the triggered shortcut as argument |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { register } from '@crabnebula/taurify-api/global-shortcut';
// register a single hotkey
await register('CommandOrControl+Shift+C', (event) => {
if (event.state === "Pressed") {
console.log('Shortcut triggered');
}
});
// or register multiple hotkeys at once
await register(['CommandOrControl+Shift+C', 'Alt+A'], (event) => {
console.log(`Shortcut ${event.shortcut} triggered`);
});
```
***
### unregister()
```ts
function unregister(shortcuts): Promise
```
Unregister a global shortcut or a list of shortcuts.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `shortcuts` | `string` \| `string`[] |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { unregister } from '@crabnebula/taurify-api/global-shortcut';
// unregister a single hotkey
await unregister('CmdOrControl+Space');
// or unregister multiple hotkeys at the same time
await unregister(['CmdOrControl+Space', 'Alt+A']);
```
***
### unregisterAll()
```ts
function unregisterAll(): Promise
```
Unregister all global shortcuts.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
#### Example
```typescript
import { unregisterAll } from '@crabnebula/taurify-api/global-shortcut';
await unregisterAll();
```
# haptics
## Type Aliases
### ImpactFeedbackStyle
```ts
type ImpactFeedbackStyle:
| "light"
| "medium"
| "heavy"
| "soft"
| "rigid";
```
***
### NotificationFeedbackType
```ts
type NotificationFeedbackType: "success" | "warning" | "error";
```
## Functions
### impactFeedback()
```ts
function impactFeedback(style): Promise>
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `style` | [`ImpactFeedbackStyle`](/taurify/api/namespacehaptics/#impactfeedbackstyle) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`Result`\<`null`, `never`\>\>
***
### notificationFeedback()
```ts
function notificationFeedback(type): Promise>
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `type` | [`NotificationFeedbackType`](/taurify/api/namespacehaptics/#notificationfeedbacktype) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`Result`\<`null`, `never`\>\>
***
### selectionFeedback()
```ts
function selectionFeedback(): Promise>
```
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`Result`\<`null`, `never`\>\>
***
### vibrate()
```ts
function vibrate(duration): Promise>
```
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `duration` | `number` |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`Result`\<`null`, `never`\>\>
# http
Make HTTP requests with the Rust backend.
## Security
This API has a scope configuration that forces you to restrict the URLs that can be accessed using glob patterns.
For instance, this scope configuration only allows making HTTP requests to all subdomains for `tauri.app` except for `https://private.tauri.app`:
```json
{
"permissions": [
{
"identifier": "http:default",
"allow": [{ "url": "https://*.tauri.app" }],
"deny": [{ "url": "https://private.tauri.app" }]
}
]
}
```
Trying to execute any API with a URL not configured on the scope results in a promise rejection due to denied access.
## Interfaces
### ClientOptions
Options to configure the Rust client used to make fetch requests
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `connectTimeout?` | `number` | Timeout in milliseconds | |
| `danger?` | [`DangerousSettings`](/taurify/api/namespacehttp/#dangeroussettings) | Configuration for dangerous settings on the client such as disabling SSL verification. | |
| `maxRedirections?` | `number` | Defines the maximum number of redirects the client should follow. If set to 0, no redirects will be followed. | |
| `proxy?` | [`Proxy`](/taurify/api/namespacehttp/#proxy-1) | Configuration of a proxy that a Client should pass requests to. | |
***
### DangerousSettings
Configuration for dangerous settings on the client such as disabling SSL verification.
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `acceptInvalidCerts?` | `boolean` | Disables SSL verification. | |
| `acceptInvalidHostnames?` | `boolean` | Disables hostname verification. | |
***
### Proxy
Configuration of a proxy that a Client should pass requests to.
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `all?` | `string` \| [`ProxyConfig`](/taurify/api/namespacehttp/#proxyconfig) | Proxy all traffic to the passed URL. | |
| `http?` | `string` \| [`ProxyConfig`](/taurify/api/namespacehttp/#proxyconfig) | Proxy all HTTP traffic to the passed URL. | |
| `https?` | `string` \| [`ProxyConfig`](/taurify/api/namespacehttp/#proxyconfig) | Proxy all HTTPS traffic to the passed URL. | |
***
### ProxyConfig
#### Properties
| Property | Type | Description | Defined in |
| ------ | ------ | ------ | ------ |
| `basicAuth?` | `object` | Set the `Proxy-Authorization` header using Basic auth. | |
| `basicAuth.password` | `string` | - | |
| `basicAuth.username` | `string` | - | |
| `noProxy?` | `string` | A configuration for filtering out requests that shouldn't be proxied. Entries are expected to be comma-separated (whitespace between entries is ignored) | |
| `url` | `string` | The URL of the proxy server. | |
## Functions
### fetch()
```ts
function fetch(input, init?): Promise
```
Fetch a resource from the network. It returns a `Promise` that resolves to the
`Response` to that `Request`, whether it is successful or not.
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `input` | `string` \| [`URL`](https://developer.mozilla.org/docs/Web/API/URL) \| [`Request`](https://developer.mozilla.org/docs/Web/API/Request) |
| `init`? | `RequestInit` & [`ClientOptions`](/taurify/api/namespacehttp/#clientoptions) |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Response`](https://developer.mozilla.org/docs/Web/API/Response)\>
#### Example
```typescript
const response = await fetch("http://my.json.host/data.json");
console.log(response.status); // e.g. 200
console.log(response.statusText); // e.g. "OK"
const jsonData = await response.json();
```
# image
## Classes
### Image
An RGBA Image in row-major order from top to bottom.
#### Extends
- [`Resource`](/taurify/api/namespacecore/#resource)
#### Accessors
##### rid
###### Get Signature
```ts
get rid(): number
```
###### Returns
`number`
###### Inherited from
[`Resource`](/taurify/api/namespacecore/#resource).[`rid`](/taurify/api/namespacecore/#rid)
#### Methods
##### close()
```ts
close(): Promise
```
Destroys and cleans up this resource from memory.
**You should not call any method on this object anymore and should drop any reference to it.**
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
###### Inherited from
[`Resource`](/taurify/api/namespacecore/#resource).[`close`](/taurify/api/namespacecore/#close)
##### rgba()
```ts
rgba(): Promise>
```
Returns the RGBA data for this image, in row-major order from top to bottom.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\>\>
##### size()
```ts
size(): Promise
```
Returns the size of this image.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`ImageSize`](/taurify/api/namespaceimage/#imagesize)\>
##### fromBytes()
```ts
static fromBytes(bytes): Promise
```
Creates a new image using the provided bytes by inferring the file format.
If the format is known, prefer [@link Image.fromPngBytes] or [@link Image.fromIcoBytes].
Only `ico` and `png` are supported.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `bytes` | `number`[] \| [`ArrayBuffer`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) \| [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\> |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Image`](/taurify/api/namespaceimage/#image)\>
##### fromPath()
```ts
static fromPath(path): Promise
```
Creates a new image using the provided path.
Only `ico` and `png` are supported.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `path` | `string` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Image`](/taurify/api/namespaceimage/#image)\>
##### new()
```ts
static new(
rgba,
width,
height): Promise
```
Creates a new Image using RGBA data, in row-major order from top to bottom, and with specified width and height.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `rgba` | `number`[] \| [`ArrayBuffer`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) \| [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\> |
| `width` | `number` |
| `height` | `number` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`Image`](/taurify/api/namespaceimage/#image)\>
## Interfaces
### ImageSize
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `height` | `number` | |
| `width` | `number` | |
## Functions
### transformImage()
```ts
function transformImage(image): T
```
Transforms image from various types into a type acceptable by Rust.
See [tauri::image::JsImage](https://docs.rs/tauri/2/tauri/image/enum.JsImage.html) for more information.
Note the API signature is not stable and might change.
#### Type Parameters
| Type Parameter |
| ------ |
| `T` |
#### Parameters
| Parameter | Type |
| ------ | ------ |
| `image` | \| `null` \| `string` \| `number`[] \| [`ArrayBuffer`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) \| [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\> \| [`Image`](/taurify/api/namespaceimage/#image) |
#### Returns
`T`
# log
## Enumerations
### LogLevel
#### Enumeration Members
##### Debug
```ts
Debug: 2;
```
The "debug" level.
Designates lower priority information.
##### Error
```ts
Error: 5;
```
The "error" level.
Designates very serious errors.
##### Info
```ts
Info: 3;
```
The "info" level.
Designates useful information.
##### Trace
```ts
Trace: 1;
```
The "trace" level.
Designates very low priority, often extremely verbose, information.
##### Warn
```ts
Warn: 4;
```
The "warn" level.
Designates hazardous situations.
## Interfaces
### LogOptions
#### Properties
| Property | Type | Defined in |
| ------ | ------ | ------ |
| `file?` | `string` | |
| `keyValues?` | [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)\<`string`, `undefined` \| `string`\> | |
| `line?` | `number` | |
## Functions
### attachConsole()
```ts
function attachConsole(): Promise
```
Attaches a listener that writes log entries to the console as they come in.
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`UnlistenFn`](/taurify/api/namespaceevent/#unlistenfn)\>
a function to cancel the listener.
***
### attachLogger()
```ts
function attachLogger(fn): Promise
```
Attaches a listener for the log, and calls the passed function for each log entry.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `fn` | `LoggerFn` | |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`UnlistenFn`](/taurify/api/namespaceevent/#unlistenfn)\>
a function to cancel the listener.
***
### debug()
```ts
function debug(message, options?): Promise
```
Logs a message at the debug level.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | `string` | # Examples `import { debug } from '@crabnebula/taurify-api/log'; const pos = { x: 3.234, y: -1.223 }; debug(`New position: x: {pos.x}, y: {pos.y}`);` |
| `options`? | [`LogOptions`](/taurify/api/namespacelog/#logoptions) | - |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### error()
```ts
function error(message, options?): Promise
```
Logs a message at the error level.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | `string` | # Examples `import { error } from '@crabnebula/taurify-api/log'; const err_info = "No connection"; const port = 22; error(`Error: ${err_info} on port ${port}`);` |
| `options`? | [`LogOptions`](/taurify/api/namespacelog/#logoptions) | - |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### info()
```ts
function info(message, options?): Promise
```
Logs a message at the info level.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | `string` | # Examples `import { info } from '@crabnebula/taurify-api/log'; const conn_info = { port: 40, speed: 3.20 }; info(`Connected to port {conn_info.port} at {conn_info.speed} Mb/s`);` |
| `options`? | [`LogOptions`](/taurify/api/namespacelog/#logoptions) | - |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### trace()
```ts
function trace(message, options?): Promise
```
Logs a message at the trace level.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | `string` | # Examples `import { trace } from '@crabnebula/taurify-api/log'; let pos = { x: 3.234, y: -1.223 }; trace(`Position is: x: {pos.x}, y: {pos.y}`);` |
| `options`? | [`LogOptions`](/taurify/api/namespacelog/#logoptions) | - |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
***
### warn()
```ts
function warn(message, options?): Promise
```
Logs a message at the warn level.
#### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | `string` | # Examples `import { warn } from '@crabnebula/taurify-api/log'; const warn_description = "Invalid Input"; warn(`Warning! {warn_description}!`);` |
| `options`? | [`LogOptions`](/taurify/api/namespacelog/#logoptions) | - |
#### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
# menu
## Enumerations
### NativeIcon
A native Icon to be used for the menu item
#### Platform-specific:
- **Windows / Linux**: Unsupported.
#### Enumeration Members
##### Add
```ts
Add: "Add";
```
An add item template image.
##### Advanced
```ts
Advanced: "Advanced";
```
Advanced preferences toolbar icon for the preferences window.
##### Bluetooth
```ts
Bluetooth: "Bluetooth";
```
A Bluetooth template image.
##### Bookmarks
```ts
Bookmarks: "Bookmarks";
```
Bookmarks image suitable for a template.
##### Caution
```ts
Caution: "Caution";
```
A caution image.
##### ColorPanel
```ts
ColorPanel: "ColorPanel";
```
A color panel toolbar icon.
##### ColumnView
```ts
ColumnView: "ColumnView";
```
A column view mode template image.
##### Computer
```ts
Computer: "Computer";
```
A computer icon.
##### EnterFullScreen
```ts
EnterFullScreen: "EnterFullScreen";
```
An enter full-screen mode template image.
##### Everyone
```ts
Everyone: "Everyone";
```
Permissions for all users.
##### ExitFullScreen
```ts
ExitFullScreen: "ExitFullScreen";
```
An exit full-screen mode template image.
##### FlowView
```ts
FlowView: "FlowView";
```
A cover flow view mode template image.
##### Folder
```ts
Folder: "Folder";
```
A folder image.
##### FolderBurnable
```ts
FolderBurnable: "FolderBurnable";
```
A burnable folder icon.
##### FolderSmart
```ts
FolderSmart: "FolderSmart";
```
A smart folder icon.
##### FollowLinkFreestanding
```ts
FollowLinkFreestanding: "FollowLinkFreestanding";
```
A link template image.
##### FontPanel
```ts
FontPanel: "FontPanel";
```
A font panel toolbar icon.
##### GoLeft
```ts
GoLeft: "GoLeft";
```
A `go back` template image.
##### GoRight
```ts
GoRight: "GoRight";
```
A `go forward` template image.
##### Home
```ts
Home: "Home";
```
Home image suitable for a template.
##### IChatTheater
```ts
IChatTheater: "IChatTheater";
```
An iChat Theater template image.
##### IconView
```ts
IconView: "IconView";
```
An icon view mode template image.
##### Info
```ts
Info: "Info";
```
An information toolbar icon.
##### InvalidDataFreestanding
```ts
InvalidDataFreestanding: "InvalidDataFreestanding";
```
A template image used to denote invalid data.
##### LeftFacingTriangle
```ts
LeftFacingTriangle: "LeftFacingTriangle";
```
A generic left-facing triangle template image.
##### ListView
```ts
ListView: "ListView";
```
A list view mode template image.
##### LockLocked
```ts
LockLocked: "LockLocked";
```
A locked padlock template image.
##### LockUnlocked
```ts
LockUnlocked: "LockUnlocked";
```
An unlocked padlock template image.
##### MenuMixedState
```ts
MenuMixedState: "MenuMixedState";
```
A horizontal dash, for use in menus.
##### MenuOnState
```ts
MenuOnState: "MenuOnState";
```
A check mark template image, for use in menus.
##### MobileMe
```ts
MobileMe: "MobileMe";
```
A MobileMe icon.
##### MultipleDocuments
```ts
MultipleDocuments: "MultipleDocuments";
```
A drag image for multiple items.
##### Network
```ts
Network: "Network";
```
A network icon.
##### Path
```ts
Path: "Path";
```
A path button template image.
##### PreferencesGeneral
```ts
PreferencesGeneral: "PreferencesGeneral";
```
General preferences toolbar icon for the preferences window.
##### QuickLook
```ts
QuickLook: "QuickLook";
```
A Quick Look template image.
##### Refresh
```ts
Refresh: "Refresh";
```
A refresh template image.
##### RefreshFreestanding
```ts
RefreshFreestanding: "RefreshFreestanding";
```
A refresh template image.
##### Remove
```ts
Remove: "Remove";
```
A remove item template image.
##### RevealFreestanding
```ts
RevealFreestanding: "RevealFreestanding";
```
A reveal contents template image.
##### RightFacingTriangle
```ts
RightFacingTriangle: "RightFacingTriangle";
```
A generic right-facing triangle template image.
##### Share
```ts
Share: "Share";
```
A share view template image.
##### Slideshow
```ts
Slideshow: "Slideshow";
```
A slideshow template image.
##### SmartBadge
```ts
SmartBadge: "SmartBadge";
```
A badge for a `smart` item.
##### StatusAvailable
```ts
StatusAvailable: "StatusAvailable";
```
Small green indicator, similar to iChat's available image.
##### StatusNone
```ts
StatusNone: "StatusNone";
```
Small clear indicator.
##### StatusPartiallyAvailable
```ts
StatusPartiallyAvailable: "StatusPartiallyAvailable";
```
Small yellow indicator, similar to iChat's idle image.
##### StatusUnavailable
```ts
StatusUnavailable: "StatusUnavailable";
```
Small red indicator, similar to iChat's unavailable image.
##### StopProgress
```ts
StopProgress: "StopProgress";
```
A stop progress button template image.
##### StopProgressFreestanding
```ts
StopProgressFreestanding: "StopProgressFreestanding";
```
A stop progress template image.
##### TrashEmpty
```ts
TrashEmpty: "TrashEmpty";
```
An image of the empty trash can.
##### TrashFull
```ts
TrashFull: "TrashFull";
```
An image of the full trash can.
##### User
```ts
User: "User";
```
Permissions for a single user.
##### UserAccounts
```ts
UserAccounts: "UserAccounts";
```
User account toolbar icon for the preferences window.
##### UserGroup
```ts
UserGroup: "UserGroup";
```
Permissions for a group of users.
##### UserGuest
```ts
UserGuest: "UserGuest";
```
Permissions for guests.
## Classes
### CheckMenuItem
A check menu item inside a [`Menu`](/taurify/api/namespacemenu/#menu) or [`Submenu`](/taurify/api/namespacemenu/#submenu)
and usually contains a text and a check mark or a similar toggle
that corresponds to a checked and unchecked states.
#### Extends
- `MenuItemBase`
#### Accessors
##### id
###### Get Signature
```ts
get id(): string
```
The id of this item.
###### Returns
`string`
###### Inherited from
`MenuItemBase.id`
##### rid
###### Get Signature
```ts
get rid(): number
```
###### Returns
`number`
###### Inherited from
`MenuItemBase.rid`
#### Methods
##### close()
```ts
close(): Promise
```
Destroys and cleans up this resource from memory.
**You should not call any method on this object anymore and should drop any reference to it.**
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
###### Inherited from
`MenuItemBase.close`
##### isChecked()
```ts
isChecked(): Promise
```
Returns whether this check menu item is checked or not.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\>
##### isEnabled()
```ts
isEnabled(): Promise
```
Returns whether this check menu item is enabled or not.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\>
##### setAccelerator()
```ts
setAccelerator(accelerator): Promise
```
Sets the accelerator for this check menu item.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `accelerator` | `null` \| `string` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### setChecked()
```ts
setChecked(checked): Promise
```
Sets whether this check menu item is checked or not.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `checked` | `boolean` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### setEnabled()
```ts
setEnabled(enabled): Promise
```
Sets whether this check menu item is enabled or not.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `enabled` | `boolean` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### setText()
```ts
setText(text): Promise
```
Sets the text for this check menu item.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `text` | `string` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### text()
```ts
text(): Promise
```
Returns the text of this check menu item.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string`\>
##### new()
```ts
static new(opts): Promise
```
Create a new check menu item.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `opts` | [`CheckMenuItemOptions`](/taurify/api/namespacemenu/#checkmenuitemoptions) |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`CheckMenuItem`](/taurify/api/namespacemenu/#checkmenuitem)\>
***
### IconMenuItem
An icon menu item inside a [`Menu`](/taurify/api/namespacemenu/#menu) or [`Submenu`](/taurify/api/namespacemenu/#submenu)
and usually contains an icon and a text.
#### Extends
- `MenuItemBase`
#### Accessors
##### id
###### Get Signature
```ts
get id(): string
```
The id of this item.
###### Returns
`string`
###### Inherited from
`MenuItemBase.id`
##### rid
###### Get Signature
```ts
get rid(): number
```
###### Returns
`number`
###### Inherited from
`MenuItemBase.rid`
#### Methods
##### close()
```ts
close(): Promise
```
Destroys and cleans up this resource from memory.
**You should not call any method on this object anymore and should drop any reference to it.**
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
###### Inherited from
`MenuItemBase.close`
##### isEnabled()
```ts
isEnabled(): Promise
```
Returns whether this icon menu item is enabled or not.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`boolean`\>
##### setAccelerator()
```ts
setAccelerator(accelerator): Promise
```
Sets the accelerator for this icon menu item.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `accelerator` | `null` \| `string` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### setEnabled()
```ts
setEnabled(enabled): Promise
```
Sets whether this icon menu item is enabled or not.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `enabled` | `boolean` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### setIcon()
```ts
setIcon(icon): Promise
```
Sets an icon for this icon menu item
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `icon` | \| `null` \| `string` \| `number`[] \| [`ArrayBuffer`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) \| [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\<`ArrayBufferLike`\> \| [`Image`](/taurify/api/namespaceimage/#image) |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### setText()
```ts
setText(text): Promise
```
Sets the text for this icon menu item.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `text` | `string` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### text()
```ts
text(): Promise
```
Returns the text of this icon menu item.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`string`\>
##### new()
```ts
static new(opts): Promise
```
Create a new icon menu item.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `opts` | [`IconMenuItemOptions`](/taurify/api/namespacemenu/#iconmenuitemoptions) |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<[`IconMenuItem`](/taurify/api/namespacemenu/#iconmenuitem)\>
***
### Menu
A type that is either a menu bar on the window
on Windows and Linux or as a global menu in the menubar on macOS.
#### Platform-specific:
- **macOS**: if using [`Menu`](/taurify/api/namespacemenu/#menu) for the global menubar, it can only contain [`Submenu`](/taurify/api/namespacemenu/#submenu)s.
#### Extends
- `MenuItemBase`
#### Accessors
##### id
###### Get Signature
```ts
get id(): string
```
The id of this item.
###### Returns
`string`
###### Inherited from
`MenuItemBase.id`
##### rid
###### Get Signature
```ts
get rid(): number
```
###### Returns
`number`
###### Inherited from
`MenuItemBase.rid`
#### Methods
##### append()
```ts
append(items): Promise
```
Add a menu item to the end of this menu.
#### Platform-specific:
- **macOS:** Only [`Submenu`](/taurify/api/namespacemenu/#submenu)s can be added to a [`Menu`](/taurify/api/namespacemenu/#menu).
###### Type Parameters
| Type Parameter |
| ------ |
| `T` *extends* \| [`CheckMenuItemOptions`](/taurify/api/namespacemenu/#checkmenuitemoptions) \| [`MenuItemOptions`](/taurify/api/namespacemenu/#menuitemoptions) \| [`CheckMenuItem`](/taurify/api/namespacemenu/#checkmenuitem) \| [`SubmenuOptions`](/taurify/api/namespacemenu/#submenuoptions) \| [`PredefinedMenuItemOptions`](/taurify/api/namespacemenu/#predefinedmenuitemoptions) \| [`IconMenuItemOptions`](/taurify/api/namespacemenu/#iconmenuitemoptions) \| [`IconMenuItem`](/taurify/api/namespacemenu/#iconmenuitem) \| [`PredefinedMenuItem`](/taurify/api/namespacemenu/#predefinedmenuitem) \| [`Submenu`](/taurify/api/namespacemenu/#submenu) \| [`MenuItem`](/taurify/api/namespacemenu/#menuitem) |
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `items` | `T` \| `T`[] |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### close()
```ts
close(): Promise
```
Destroys and cleans up this resource from memory.
**You should not call any method on this object anymore and should drop any reference to it.**
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
###### Inherited from
`MenuItemBase.close`
##### get()
```ts
get(id): Promise<
| null
| CheckMenuItem
| IconMenuItem
| PredefinedMenuItem
| Submenu
| MenuItem>
```
Retrieves the menu item matching the given identifier.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `id` | `string` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<
\| `null`
\| [`CheckMenuItem`](/taurify/api/namespacemenu/#checkmenuitem)
\| [`IconMenuItem`](/taurify/api/namespacemenu/#iconmenuitem)
\| [`PredefinedMenuItem`](/taurify/api/namespacemenu/#predefinedmenuitem)
\| [`Submenu`](/taurify/api/namespacemenu/#submenu)
\| [`MenuItem`](/taurify/api/namespacemenu/#menuitem)\>
##### insert()
```ts
insert(items, position): Promise
```
Add a menu item to the specified position in this menu.
#### Platform-specific:
- **macOS:** Only [`Submenu`](/taurify/api/namespacemenu/#submenu)s can be added to a [`Menu`](/taurify/api/namespacemenu/#menu).
###### Type Parameters
| Type Parameter |
| ------ |
| `T` *extends* \| [`CheckMenuItemOptions`](/taurify/api/namespacemenu/#checkmenuitemoptions) \| [`MenuItemOptions`](/taurify/api/namespacemenu/#menuitemoptions) \| [`CheckMenuItem`](/taurify/api/namespacemenu/#checkmenuitem) \| [`SubmenuOptions`](/taurify/api/namespacemenu/#submenuoptions) \| [`PredefinedMenuItemOptions`](/taurify/api/namespacemenu/#predefinedmenuitemoptions) \| [`IconMenuItemOptions`](/taurify/api/namespacemenu/#iconmenuitemoptions) \| [`IconMenuItem`](/taurify/api/namespacemenu/#iconmenuitem) \| [`PredefinedMenuItem`](/taurify/api/namespacemenu/#predefinedmenuitem) \| [`Submenu`](/taurify/api/namespacemenu/#submenu) \| [`MenuItem`](/taurify/api/namespacemenu/#menuitem) |
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `items` | `T` \| `T`[] |
| `position` | `number` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### items()
```ts
items(): Promise<(
| CheckMenuItem
| IconMenuItem
| PredefinedMenuItem
| Submenu
| MenuItem)[]>
```
Returns a list of menu items that has been added to this menu.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<(
\| [`CheckMenuItem`](/taurify/api/namespacemenu/#checkmenuitem)
\| [`IconMenuItem`](/taurify/api/namespacemenu/#iconmenuitem)
\| [`PredefinedMenuItem`](/taurify/api/namespacemenu/#predefinedmenuitem)
\| [`Submenu`](/taurify/api/namespacemenu/#submenu)
\| [`MenuItem`](/taurify/api/namespacemenu/#menuitem))[]\>
##### popup()
```ts
popup(at?, window?): Promise
```
Popup this menu as a context menu on the specified window.
###### Parameters
| Parameter | Type | Description |
| ------ | ------ | ------ |
| `at`? | [`LogicalPosition`](/taurify/api/namespacedpi/#logicalposition) \| [`PhysicalPosition`](/taurify/api/namespacedpi/#physicalposition) \| [`Position`](/taurify/api/namespacedpi/#position) | If a position is provided, it is relative to the window's top-left corner. If there isn't one provided, the menu will pop up at the current location of the mouse. |
| `window`? | [`Window`](/taurify/api/namespacewindow/#window) | - |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### prepend()
```ts
prepend(items): Promise
```
Add a menu item to the beginning of this menu.
#### Platform-specific:
- **macOS:** Only [`Submenu`](/taurify/api/namespacemenu/#submenu)s can be added to a [`Menu`](/taurify/api/namespacemenu/#menu).
###### Type Parameters
| Type Parameter |
| ------ |
| `T` *extends* \| [`CheckMenuItemOptions`](/taurify/api/namespacemenu/#checkmenuitemoptions) \| [`MenuItemOptions`](/taurify/api/namespacemenu/#menuitemoptions) \| [`CheckMenuItem`](/taurify/api/namespacemenu/#checkmenuitem) \| [`SubmenuOptions`](/taurify/api/namespacemenu/#submenuoptions) \| [`PredefinedMenuItemOptions`](/taurify/api/namespacemenu/#predefinedmenuitemoptions) \| [`IconMenuItemOptions`](/taurify/api/namespacemenu/#iconmenuitemoptions) \| [`IconMenuItem`](/taurify/api/namespacemenu/#iconmenuitem) \| [`PredefinedMenuItem`](/taurify/api/namespacemenu/#predefinedmenuitem) \| [`Submenu`](/taurify/api/namespacemenu/#submenu) \| [`MenuItem`](/taurify/api/namespacemenu/#menuitem) |
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `items` | `T` \| `T`[] |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### remove()
```ts
remove(item): Promise
```
Remove a menu item from this menu.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `item` | \| [`CheckMenuItem`](/taurify/api/namespacemenu/#checkmenuitem) \| [`IconMenuItem`](/taurify/api/namespacemenu/#iconmenuitem) \| [`PredefinedMenuItem`](/taurify/api/namespacemenu/#predefinedmenuitem) \| [`Submenu`](/taurify/api/namespacemenu/#submenu) \| [`MenuItem`](/taurify/api/namespacemenu/#menuitem) |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`void`\>
##### removeAt()
```ts
removeAt(position): Promise<
| null
| CheckMenuItem
| IconMenuItem
| PredefinedMenuItem
| Submenu
| MenuItem>
```
Remove a menu item from this menu at the specified position.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `position` | `number` |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<
\| `null`
\| [`CheckMenuItem`](/taurify/api/namespacemenu/#checkmenuitem)
\| [`IconMenuItem`](/taurify/api/namespacemenu/#iconmenuitem)
\| [`PredefinedMenuItem`](/taurify/api/namespacemenu/#predefinedmenuitem)
\| [`Submenu`](/taurify/api/namespacemenu/#submenu)
\| [`MenuItem`](/taurify/api/namespacemenu/#menuitem)\>
##### setAsAppMenu()
```ts
setAsAppMenu(): Promise
```
Sets the app-wide menu and returns the previous one.
If a window was not created with an explicit menu or had one set explicitly,
this menu will be assigned to it.
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`null` \| [`Menu`](/taurify/api/namespacemenu/#menu)\>
##### setAsWindowMenu()
```ts
setAsWindowMenu(window?): Promise
```
Sets the window menu and returns the previous one.
#### Platform-specific:
- **macOS:** Unsupported. The menu on macOS is app-wide and not specific to one
window, if you need to set it, use [`Menu.setAsAppMenu`](/taurify/api/namespacemenu/#setasappmenu) instead.
###### Parameters
| Parameter | Type |
| ------ | ------ |
| `window`? | [`Window`](/taurify/api/namespacewindow/#window) |
###### Returns
[`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`null` \| [`Menu`](/taurify/api/namespacemenu/#menu)\>
##### default()
```ts
static default(): Promise