diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..4f5dfb5
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,24 @@
+version: 2
+
+updates:
+ - package-ecosystem: cargo
+ directory: /
+ schedule:
+ interval: weekly
+ cooldown:
+ default-days: 7
+ commit-message:
+ prefix: chore
+ include: scope
+ labels: [chore]
+
+ - package-ecosystem: github-actions
+ directory: /
+ schedule:
+ interval: weekly
+ cooldown:
+ default-days: 7
+ commit-message:
+ prefix: chore
+ include: scope
+ labels: [chore]
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7925998..5059ae3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,27 +5,58 @@ on:
branches: [main]
pull_request:
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ MISE_TASK_RUN_AUTO_INSTALL: false
+
jobs:
check:
- name: Build & Check
+ name: Check
runs-on: ubuntu-latest
+ timeout-minutes: 15
steps:
- - uses: actions/checkout@v7
+ - name: Checkout
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+
+ - name: Install tools
+ uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1
+ with:
+ install_args: rust mr-boxington jactionlint shellcheck
- - name: Install system dependencies
- run: sudo apt-get update && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libglib2.0-dev
+ - name: Set up build cache
+ uses: jdx/mr-boxington-action@47ce49b32025d93a7a2f4570815afaa2b7092240 # v1.7.2
- - uses: dtolnay/rust-toolchain@stable
+ - name: Run checks
+ run: mise run check
- - uses: actions/setup-node@v7
+ check-example:
+ name: Check example
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ steps:
+ - name: Checkout
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
- node-version: 20
+ persist-credentials: false
- - name: Install JS deps
- run: npm install
+ - name: Install tools
+ uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1
+ with:
+ install_args: rust mr-boxington
- - name: Build JS
- run: npm run build
+ - name: Set up build cache
+ uses: jdx/mr-boxington-action@47ce49b32025d93a7a2f4570815afaa2b7092240 # v1.7.2
+ with:
+ working-directory: examples/helloworld
+ cache-generation: example-v1
- - name: Check Rust
- run: cargo check
\ No newline at end of file
+ - name: Run checks
+ run: mise run example:check
diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml
new file mode 100644
index 0000000..9eaa83d
--- /dev/null
+++ b/.github/workflows/release-notes.yml
@@ -0,0 +1,40 @@
+name: Release notes
+
+on:
+ release:
+ types: [published]
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.release.tag_name }}
+ cancel-in-progress: false
+
+env:
+ MISE_TASK_RUN_AUTO_INSTALL: false
+
+jobs:
+ release-notes:
+ if: ${{ github.repository_owner == 'eugencowie' }}
+ name: Release notes
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ permissions:
+ contents: write
+ steps:
+ - name: Checkout
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+
+ - name: Install tools
+ uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1
+ with:
+ install_args: gh
+ cache: false
+
+ - name: Set release notes
+ run: |
+ notes=$(mise run release:notes "${TAG#v}")
+ gh release edit "$TAG" --notes "$notes"
+ env:
+ GH_TOKEN: ${{ github.token }}
+ TAG: ${{ github.event.release.tag_name }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4733630..9b74d85 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,36 +1,86 @@
name: Release
on:
- release:
- types: [published]
+ push:
+ branches: [main]
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: false
+
+env:
+ MISE_TASK_RUN_AUTO_INSTALL: false
jobs:
- publish-crates:
- name: Publish to crates.io
+ prepare-release:
+ if: ${{ github.repository_owner == 'eugencowie' }}
+ name: Prepare release
runs-on: ubuntu-latest
+ timeout-minutes: 30
+ permissions:
+ contents: write
+ pull-requests: write
steps:
- - uses: actions/checkout@v7
+ - name: Checkout
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: 0
+ persist-credentials: true
+ token: ${{ secrets.RELEASE_PLZ_TOKEN }}
- - uses: dtolnay/rust-toolchain@stable
+ - name: Install tools
+ uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1
+ with:
+ install_args: rust mr-boxington release-plz git-cliff gh
- - name: Publish
- run: cargo publish
+ - name: Configure git
+ uses: release-plz/git-config@59144859caf016f8b817a2ac9b051578729173c4 # v0.1.2
env:
- CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}
+
+ - name: Update changelog and version
+ run: mise run release:prepare
- publish-npm:
- name: Publish to npm
+ - name: Create or update release PR
+ run: |
+ out=$(release-plz release-pr -o json)
+ pr=$(jq -r '.prs[0].number // empty' <<< "$out")
+ [ -n "$pr" ] || exit 0
+ body=$(gh pr view "$pr" --json body --jq .body)
+ end='
'
+ if [[ "$body" != *"$end"* ]]; then
+ echo "::error::PR body has no $end to put the changelog before"
+ exit 1
+ fi
+ version=$(jq -r '.prs[0].releases[0].version' <<< "$out")
+ notes=$(mise run release:notes "$version")
+ gh pr edit "$pr" --body "${body/"$end"/"$notes"$'\n\n'"$end"}"
+ env:
+ GIT_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}
+ GH_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}
+
+ release:
+ if: ${{ github.repository_owner == 'eugencowie' }}
+ name: Release
runs-on: ubuntu-latest
+ timeout-minutes: 30
+ permissions:
+ contents: write
steps:
- - uses: actions/checkout@v7
-
- - uses: actions/setup-node@v7
+ - name: Checkout
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
- node-version: 20
- registry-url: https://registry.npmjs.org
+ fetch-depth: 0
+ persist-credentials: true
+ token: ${{ secrets.RELEASE_PLZ_TOKEN }}
- - run: npm install
+ - name: Install tools
+ uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1
+ with:
+ install_args: rust mr-boxington release-plz
- - run: npm publish
+ - name: Publish release
+ run: release-plz release
env:
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
\ No newline at end of file
+ GIT_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 01cfb28..fba9493 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,43 @@
-/.vs
-.DS_Store
-.Thumbs.db
-*.sublime*
-.idea/
-debug.log
-package-lock.json
-.vscode/settings.json
-yarn.lock
-
-/.tauri
-/target
-Cargo.lock
-node_modules/
-webview-dist/rollup.config.d.ts
+#
+# https://github.com/github/gitignore/blob/main/Rust.gitignore
+#
+
+# Generated by Cargo
+# will have compiled files and executables
+debug
+target
+
+# These are backup files generated by rustfmt
+**/*.rs.bk
+
+# MSVC Windows builds of rustc generate these, which store debugging information
+*.pdb
+
+# Generated by cargo mutants
+# Contains mutation testing data
+**/mutants.out*/
+
+# rustc will dump stack traces when hitting an internal compiler error to PWD
+rustc-ice-*.txt
+
+#
+# https://www.toptal.com/developers/gitignore/api/dotenv
+#
+
+### dotenv ###
+.env
+
+#
+# Examples
+#
+
+# Each example builds against the local crate, so a committed lockfile
+# only goes stale whenever the crate's version changes
+examples/*/Cargo.lock
+
+#
+# git-cliff
+#
+
+# Generated by `mise run release:prepare`
+.cliffignore
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..7a0c65d
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,14 @@
+# Agent Instructions
+
+## Development environment
+
+This project uses mise to manage the development environment.
+
+- Run `mise tasks` to see the available tasks.
+- Use `mise run ` for standard operations.
+- Run `mise ls -l` to see the managed tools.
+- When invoking a managed tool directly, use `mise exec -- [args]` rather than invoking the tool by its bare name.
+
+## Upstream references
+
+This repo is a fork of `aptabase/tauri-plugin-aptabase`. In commit messages, PR descriptions and comments, upstream PRs and issues should be cited as plain text by title or commit SHA. Avoid links and `#123` shorthand: GitHub cross-references those, which spams the upstream project with irrelevant notifications.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6939a81..6b96bc5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,120 +1,73 @@
# Changelog
-All notable changes to this project will be documented in this file.
+## 0.3.1
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+### ๐ Refactor
-## [1.2.0] - 2026-08-11
+- Move fork-only code out of upstream-shared files ([#25](https://github.com/eugencowie/aptabase-rs/pull/25))
-### Changed
+### ๐งช Testing
-- Bump all Rust dependencies to latest versions (tauri 2.11.5, tokio 1.53.1, reqwest 0.13.4, rand 0.10.0, serde 1.0.229, serde_json 1.0.151, time 0.3.41, os_info 3.12.0, log 0.4.27, tauri-plugin 2.6.3)
-- Bump JavaScript dependencies (@tauri-apps/api ^2.10.1, @rollup/plugin-node-resolve ^16.0.3, @rollup/plugin-typescript ^12.3.0, @rollup/plugin-terser ^1.0.0, rollup ^4.57.1, typescript ^5.9.3)
-- Update `rust-version` to 1.81.0 (required for `PanicHookInfo`)
-- Update `rustls-tls` feature to use `reqwest/rustls` (reqwest 0.13 renamed the feature)
-- Clean up tsconfig.json: remove dead baseUrl/paths, switch to moduleResolution "bundler", add outDir
-- Remove hardcoded `moduleResolution: 'node'` from rollup config
+- Test event delivery against a local stand-in server ([#28](https://github.com/eugencowie/aptabase-rs/pull/28))
-### Fixed
+### โ๏ธ Miscellaneous Tasks
-- Fix `rand` 0.10 API change: `rand::Rng` โ `rand::RngExt` in client.rs
-- Fix rollup build error: align tsconfig outDir with rollup output dir
-- Resolve issue #27: ENGINE_NAME not found on iOS โ already fixed on main, this release publishes the fix to crates.io
+- Stop tracking the example's lockfile ([#23](https://github.com/eugencowie/aptabase-rs/pull/23))
+- Match upstream's Rust edition and require Rust 1.88 ([#21](https://github.com/eugencowie/aptabase-rs/pull/21))
+- Stop mise run from installing unused tools in CI ([#26](https://github.com/eugencowie/aptabase-rs/pull/26))
+- Pin release-plz and git-cliff to mise.lock versions ([#27](https://github.com/eugencowie/aptabase-rs/pull/27))
+- Switch to jactionlint and harden the workflows ([#29](https://github.com/eugencowie/aptabase-rs/pull/29))
+- Cache builds with mbx ([#31](https://github.com/eugencowie/aptabase-rs/pull/31))
+- Install mbx for release jobs ([#32](https://github.com/eugencowie/aptabase-rs/pull/32))
+- Add the changelog to release PR and GitHub release bodies ([#33](https://github.com/eugencowie/aptabase-rs/pull/33))
-## [1.1.0] - 2026-08-11
+## 0.3.0
-### Fixed
+### ๐ Features
-- Fix runtime panic on startup for apps without `#[tokio::main]` by replacing `tokio::spawn` with `tauri::async_runtime::spawn` (#30, fixes #22, fixes #25)
-- Replace deprecated `std::panic::PanicInfo` with `std::panic::PanicHookInfo` (stable since Rust 1.81.0) (#30)
-- Bump `@tauri-apps/api` to `^2.7.0` to resolve `window.__TAURI_IPC__` error (#30)
+- **BREAKING CHANGE**: Switch default TLS backend to rustls ([#16](https://github.com/eugencowie/aptabase-rs/pull/16))
-### Added
+### ๐ Documentation
-- TLS backend feature flags for reqwest: `default-tls`, `native-tls`, `rustls-tls` (#34, closes #28)
-- Consumers can now opt into rustls for Android and cross-compile targets via `default-features = false, features = ["rustls-tls"]`
+- Remove specs and skills from repo ([#14](https://github.com/eugencowie/aptabase-rs/pull/14))
-### Changed
+### โ๏ธ Miscellaneous Tasks
-- `reqwest` is now declared with `default-features = false`; `default = ["default-tls"]` preserves previous behavior (#34)
+- Run CI and releases from main ([#12](https://github.com/eugencowie/aptabase-rs/pull/12))
+- Merge upstream changes ([#15](https://github.com/eugencowie/aptabase-rs/pull/15))
-## [1.0.0] - 2025-03-27
+## 0.2.0
-### Changed
+### ๐ Features
-- Update to Tauri v2
+- Add custom session ID support ([#10](https://github.com/eugencowie/aptabase-rs/pull/10))
-## [0.5.1] - 2024-02-04
+## 0.1.2
-### Fixed
+### ๐ Bug Fixes
-- Fixed an issue where `with_panic_hook` would swallow the panic after logging it
+- Fix build error in example ([#7](https://github.com/eugencowie/aptabase-rs/pull/7))
-## [0.5.0] - 2023-12-20
+### ๐ Documentation
-### Fixed
+- Tidy up readme ([#9](https://github.com/eugencowie/aptabase-rs/pull/9))
-- Fixed an issue where `with_panic_hook` would panic
+## 0.1.1
-### Added
+### โ๏ธ Miscellaneous Tasks
-- Added `msg: String` to `with_panic_hook`
+- Fix release workflow ([#5](https://github.com/eugencowie/aptabase-rs/pull/5))
-## [0.4.2] - 2023-11-03
+## 0.1.0
-### Changed
+### ๐ Features
-- Use new session id format
+- Generic Rust SDK for Aptabase ([#1](https://github.com/eugencowie/aptabase-rs/pull/1))
-## [0.4.1] - 2023-08-07
+### ๐ Documentation
-### Added
+- Update readme ([#4](https://github.com/eugencowie/aptabase-rs/pull/4))
-- Automatic flush of events on app exit
+### โ๏ธ Miscellaneous Tasks
-### Fixed
-
-- Fix User-Agent header
-
-## [0.4.0] - 2023-08-06
-
-### Changed
-
-- Events are now sent in batches to reduce network overhead
-- While offline, events will be enqueue and sent when the app is back online
-- Tauri 1.4 required
-
-## [0.3.2] - 2023-07-23
-
-### Fixed
-
-- (macOS) Fixed an issue where sessions could span multiple days if the app was left open overnight
-
-## [0.3.1] - 2023-07-11
-
-### Fixed
-
-- Wait for event to be flushed on panic
-
-## [0.3.0] - 2023-07-10
-
-### Added
-
-- Add ability for panic hook to log panics to aptabase
-
-## [0.2.1] - 2023-05-20
-
-### Added
-
-- Added support for automatic segregation of Debug/Release data source
-
-## [0.2.0] - 2023-05-17
-
-### Changed
-
-- BREAKING CHANGE: replaced the `init` function with a `Builder` struct, see README for example usage
-
-### Added
-
-- Ability to set custom hosts for self hosted servers
\ No newline at end of file
+- Configure release workflow ([#2](https://github.com/eugencowie/aptabase-rs/pull/2))
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..b1383d8
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,2295 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "aptabase-rs"
+version = "0.3.1"
+dependencies = [
+ "futures",
+ "log",
+ "os_info",
+ "rand",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "sys-locale",
+ "time",
+ "tokio",
+ "wiremock",
+]
+
+[[package]]
+name = "assert-json-diff"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "aws-lc-rs"
+version = "1.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e"
+dependencies = [
+ "aws-lc-sys",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-lc-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bff6c3b54fad79a2e60b8102caf565819711497c1f5f092f49508e2f5c31b27"
+dependencies = [
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+ "pkg-config",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "base64"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
+
+[[package]]
+name = "bitflags"
+version = "2.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
+
+[[package]]
+name = "block2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
+dependencies = [
+ "objc2",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
+
+[[package]]
+name = "bytes"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
+
+[[package]]
+name = "cc"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
+
+[[package]]
+name = "chacha20"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "rand_core",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "combine"
+version = "4.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "core_detect"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48"
+
+[[package]]
+name = "cpufeatures"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "deadpool"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b"
+dependencies = [
+ "deadpool-runtime",
+ "lazy_static",
+ "num_cpus",
+ "tokio",
+]
+
+[[package]]
+name = "deadpool-runtime"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b"
+
+[[package]]
+name = "deranged"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
+
+[[package]]
+name = "dispatch2"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
+dependencies = [
+ "bitflags",
+ "objc2",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679"
+dependencies = [
+ "cfg-if",
+ "core_detect",
+ "multiversion_no_op",
+ "rustversion",
+ "scopeguard",
+ "simdutf8",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
+name = "futures"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
+
+[[package]]
+name = "futures-task"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
+
+[[package]]
+name = "futures-util"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi",
+ "rand_core",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "h2"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
+
+[[package]]
+name = "hermit-abi"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284"
+
+[[package]]
+name = "http"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425"
+dependencies = [
+ "bytes",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
+name = "hyper"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
+dependencies = [
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
+dependencies = [
+ "bytes",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
+dependencies = [
+ "base64 0.22.1",
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "ipnet",
+ "libc",
+ "percent-encoding",
+ "pin-project-lite",
+ "socket2",
+ "system-configuration",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "windows-registry",
+]
+
+[[package]]
+name = "icu_collections"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "utf8_iter",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
+
+[[package]]
+name = "icu_properties"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
+dependencies = [
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
+
+[[package]]
+name = "icu_provider"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "idna"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "jni"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
+dependencies = [
+ "cfg-if",
+ "combine",
+ "jni-macros",
+ "jni-sys",
+ "log",
+ "simd_cesu8",
+ "thiserror",
+ "walkdir",
+ "windows-link",
+]
+
+[[package]]
+name = "jni-macros"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "simd_cesu8",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
+dependencies = [
+ "jni-sys-macros",
+]
+
+[[package]]
+name = "jni-sys-macros"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
+dependencies = [
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "jobserver"
+version = "0.1.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3"
+dependencies = [
+ "getrandom 0.4.3",
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb"
+
+[[package]]
+name = "libc"
+version = "0.2.189"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
+
+[[package]]
+name = "litemap"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
+
+[[package]]
+name = "log"
+version = "0.4.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
+
+[[package]]
+name = "lru-slab"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f"
+
+[[package]]
+name = "memchr"
+version = "2.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "mio"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "multiversion_no_op"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d"
+
+[[package]]
+name = "native-tls"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "nix"
+version = "0.31.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
+
+[[package]]
+name = "num_cpus"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "objc2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
+dependencies = [
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-cloud-kit"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-data"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
+dependencies = [
+ "bitflags",
+ "dispatch2",
+ "objc2",
+]
+
+[[package]]
+name = "objc2-core-graphics"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
+dependencies = [
+ "bitflags",
+ "dispatch2",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-io-surface",
+]
+
+[[package]]
+name = "objc2-core-image"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-location"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-text"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-core-graphics",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
+
+[[package]]
+name = "objc2-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
+dependencies = [
+ "bitflags",
+ "block2",
+ "libc",
+ "objc2",
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "objc2-io-surface"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "objc2-quartz-core"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-ui-kit"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
+dependencies = [
+ "bitflags",
+ "block2",
+ "objc2",
+ "objc2-cloud-kit",
+ "objc2-core-data",
+ "objc2-core-foundation",
+ "objc2-core-graphics",
+ "objc2-core-image",
+ "objc2-core-location",
+ "objc2-core-text",
+ "objc2-foundation",
+ "objc2-quartz-core",
+ "objc2-user-notifications",
+]
+
+[[package]]
+name = "objc2-user-notifications"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "openssl"
+version = "0.10.81"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "os_info"
+version = "3.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cf20a545b305cf1da722b236b5155c9bb35f1d5ceb28c048bd96ca842f41b5b"
+dependencies = [
+ "android_system_properties",
+ "log",
+ "nix",
+ "objc2",
+ "objc2-foundation",
+ "objc2-ui-kit",
+ "serde",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
+
+[[package]]
+name = "potential_utf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.107"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quinn"
+version = "0.11.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash",
+ "rustls",
+ "socket2",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe"
+dependencies = [
+ "aws-lc-rs",
+ "bytes",
+ "getrandom 0.4.3",
+ "lru-slab",
+ "rand",
+ "rand_pcg",
+ "ring",
+ "rustc-hash",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af66907df18639dcf4db56ca65490cabc4b27a97dbadd96f2926cca73298f016"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2",
+ "tracing",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "rand"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af"
+dependencies = [
+ "chacha20",
+ "getrandom 0.4.3",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+
+[[package]]
+name = "rand_pcg"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "regex"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
+
+[[package]]
+name = "reqwest"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029"
+dependencies = [
+ "base64 0.23.1",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-tls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-pki-types",
+ "rustls-platform-verifier",
+ "serde",
+ "serde_json",
+ "sync_wrapper",
+ "tokio",
+ "tokio-native-tls",
+ "tokio-rustls",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.17",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634"
+dependencies = [
+ "aws-lc-rs",
+ "once_cell",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
+dependencies = [
+ "openssl-probe",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96"
+dependencies = [
+ "web-time",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-platform-verifier"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1167586491e2b18b8bfbb293e8180ec17c201c4f076d7cb3070ca964e7598f98"
+dependencies = [
+ "core-foundation 0.10.1",
+ "core-foundation-sys",
+ "jni",
+ "log",
+ "once_cell",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-platform-verifier-android",
+ "rustls-webpki",
+ "security-framework",
+ "security-framework-sys",
+ "webpki-root-certs",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls-platform-verifier-android"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eec689c0bc40ff2458a5977b6619cb718087084a18e02a131c599b62d05e1a5f"
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
+dependencies = [
+ "aws-lc-rs",
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "schannel"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "security-framework"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
+dependencies = [
+ "bitflags",
+ "core-foundation 0.10.1",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+
+[[package]]
+name = "serde"
+version = "1.0.229"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.229"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.229"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.151"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "shlex"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
+
+[[package]]
+name = "simd_cesu8"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520"
+dependencies = [
+ "rustc_version",
+ "simdutf8",
+]
+
+[[package]]
+name = "simdutf8"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
+
+[[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
+name = "smallvec"
+version = "1.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
+
+[[package]]
+name = "socket2"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "2.0.119"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "sys-locale"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
+dependencies = [
+ "bitflags",
+ "core-foundation 0.9.4",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
+dependencies = [
+ "fastrand",
+ "getrandom 0.4.3",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "time"
+version = "0.3.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134"
+dependencies = [
+ "deranged",
+ "num-conv",
+ "powerfmt",
+ "serde_core",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
+
+[[package]]
+name = "time-macros"
+version = "0.2.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee"
+
+[[package]]
+name = "tokio"
+version = "1.53.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "libc",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tower"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
+dependencies = [
+ "bitflags",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "url",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+]
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webpki-root-certs"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-registry"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
+dependencies = [
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wiremock"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031"
+dependencies = [
+ "assert-json-diff",
+ "base64 0.22.1",
+ "deadpool",
+ "futures",
+ "http",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "log",
+ "once_cell",
+ "regex",
+ "serde",
+ "serde_json",
+ "tokio",
+ "url",
+]
+
+[[package]]
+name = "writeable"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
+
+[[package]]
+name = "yoke"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+ "synstructure",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
+
+[[package]]
+name = "zerotrie"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
diff --git a/Cargo.toml b/Cargo.toml
index a5e798f..4c18c14 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,34 +1,43 @@
[package]
-name = "tauri-plugin-aptabase"
-version = "1.2.0"
+name = "aptabase-rs"
+version = "0.3.1"
license = "MIT"
-description = "Tauri Plugin for Aptabase: Open Source, Privacy-First and Simple Analytics for Mobile, Desktop and Web Apps"
-authors = ["Guilherme Oenning"]
+description = "Rust SDK for Aptabase: Open Source, Privacy-First and Simple Analytics for Mobile, Desktop and Web Apps"
+authors = ["Eugรฉn Cowie"]
edition = "2021"
-rust-version = "1.81.0"
-readme = "README.md"
-repository = "https://github.com/aptabase/tauri-plugin-aptabase"
-exclude = ["/examples", "/webview-dist", "/webview-src", "/node_modules"]
-links = "tauri-plugin-aptabase"
+rust-version = "1.88"
+homepage = "https://github.com/eugencowie/aptabase-rs"
+repository = "https://github.com/eugencowie/aptabase-rs"
+keywords = ["analytics", "aptabase", "telemetry"]
+categories = ["api-bindings"]
[dependencies]
-tauri = "2.11.5"
-tokio = "1.53.1"
+tokio = { version = "1.43.0", features = ["rt", "time"] }
futures = "0.3.31"
-serde = "1.0.229"
-serde_json = "1.0.151"
-reqwest = { version = "0.13.4", default-features = false, features = ["json"] }
-time = { version = "0.3.41", features = ["formatting"] }
-os_info = "3.12.0"
+serde = "1.0.217"
+serde_json = "1.0.138"
+reqwest = { version = "0.13.4", default-features = false, features = ["json", "charset", "http2", "system-proxy"] }
+time = { version = "0.3.37", features = ["formatting"] }
+os_info = "3.9.2"
rand = "0.10.0"
-log = "0.4.27"
+log = "0.4.25"
sys-locale = "0.3.2"
-[build-dependencies]
-tauri-plugin = { version = "2.6.3", features = ["build"] }
+[dev-dependencies]
+tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread"] }
+time = { version = "0.3.37", features = ["parsing"] }
+wiremock = "0.6.5"
[features]
default = ["default-tls"]
default-tls = ["reqwest/default-tls"]
native-tls = ["reqwest/native-tls"]
rustls-tls = ["reqwest/rustls"]
+
+[lints.rust]
+warnings = "deny"
+
+[lints.clippy]
+all = { level = "deny", priority = -1 }
+to_string_in_format_args = "allow" # match upstream
+uninlined_format_args = "allow" # match upstream
diff --git a/GLOSSARY.md b/GLOSSARY.md
new file mode 100644
index 0000000..babe8c0
--- /dev/null
+++ b/GLOSSARY.md
@@ -0,0 +1,41 @@
+# Rust SDK for Aptabase
+
+A client that records analytics events in a Rust application and sends them to an Aptabase server.
+
+## Language
+
+### Core concepts
+
+**App Key**:
+The identifier Aptabase issues to an application, which names the region its events go to. An invalid app key disables tracking.
+_Avoid_: API key, token
+
+**Region**:
+The Aptabase server an app key belongs to: `US` or `EU` cloud, `DEV` for a local server, or `SH` for a self-hosted server at a host the application supplies.
+_Avoid_: Environment, server
+
+**Event**:
+A single named occurrence in the application, with optional custom properties, enriched by the SDK with the session, app version and system details.
+_Avoid_: Message, hit
+
+**Session**:
+A run of activity that groups events, identified by a session ID. It ends after 4 hours without events, and on application restart unless the application supplies a persisted session ID.
+_Avoid_: Visit
+
+### Event delivery
+
+**Flush**:
+Sending every event not yet delivered to the server.
+_Avoid_: Sync
+
+**Batch**:
+The events sent to the server together in one request.
+_Avoid_: Chunk, page
+
+**Polling**:
+Flushing automatically at a fixed interval, as opt-in behaviour for long-running applications.
+_Avoid_: Auto-flush, background sync
+
+**Delivery**:
+How a flush gets events to the server: how events are grouped into batches, and which failed batches are kept for the next flush and which are dropped.
+_Avoid_: Dispatch, upload
diff --git a/LICENSE b/LICENSE
index ee62ce0..9fde467 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,6 @@
MIT License
+Copyright (c) 2026 Eugรฉn Cowie
Copyright (c) 2023 Sumbit Labs Ltd.
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -18,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
\ No newline at end of file
+SOFTWARE.
diff --git a/README.md b/README.md
index 42fd437..f156929 100644
--- a/README.md
+++ b/README.md
@@ -1,129 +1,205 @@
-
+# Rust SDK for Aptabase
-# Tauri Plugin for Aptabase
+An unofficial, framework-independent Rust SDK for [Aptabase](https://aptabase.com), the open source, privacy-first, and simple analytics platform for mobile, desktop and web apps.
-This plugin allows you to instrument your app with events that can be analyzed in Aptabase, an Open Source, Privacy-First, and Simple Analytics for Mobile, Desktop, and Web Apps.
+This is a community project and is not affiliated with or endorsed by Aptabase. It is derived from the official [Tauri Plugin for Aptabase](https://github.com/aptabase/tauri-plugin-aptabase). If you're building a Tauri app, use that instead.
## Install
-Install the Core plugin by adding the following to your `Cargo.toml` file:
+Install the SDK by adding the following to your `Cargo.toml` file:
-`src-tauri/Cargo.toml`
+`Cargo.toml`
```toml
[dependencies]
-tauri-plugin-aptabase = "1.0.0"
+aptabase-rs = "0.3"
+serde_json = "1"
+tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```
-```toml
-[dependencies]
-tauri-plugin-aptabase = { git = "https://github.com/aptabase/tauri-plugin-aptabase" }
-```
+## Usage
+
+First, you need to get your `App Key` from Aptabase, you can find it in the `Instructions` menu on the left side menu.
+
+Then create the client with your app key and application version:
-You can install the JavaScript Guest bindings using your preferred JavaScript package manager
+`src/main.rs`
-```bash
-npm add @aptabase/tauri
+```rust
+use aptabase_rs::Builder;
+
+let client = Builder::new(
+ "", // ๐ this is where you enter your App Key
+ env!("CARGO_PKG_VERSION"),
+)
+.build();
```
-```bash
-npm add https://github.com/aptabase/tauri-plugin-aptabase
+You can then start sending events from Rust by calling the `track_event` method on `client`.
+
+As an example, you can add `app_started` and `app_exited` events like this:
+
+```rust
+use aptabase_rs::Builder;
+use std::error::Error;
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let client = Builder::new("", env!("CARGO_PKG_VERSION")).build();
+ client.track_event("app_started", None);
+
+ // do some work here...
+
+ client.track_event("app_exited", None);
+ client.flush().await;
+ Ok(())
+}
```
-## Usage
+A few important notes:
-First, you need to get your `App Key` from Aptabase, you can find it in the `Instructions` menu on the left side menu.
+1. The SDK will automatically enhance the event with some useful information, like the OS, the app version, and other things.
+2. You're in control of what gets sent to Aptabase. This SDK does not automatically track any events, you need to call `track_event` manually.
+ - Because of this, it's generally recommended to at least track an event at startup.
+3. You do not need to await for the `track_event` function, it'll run in the background.
+4. Only strings and numbers values are allowed on custom properties.
-Then register the plugin with Tauri:
+## Providing the APTABASE_KEY via .env
-`src-tauri/src/main.rs`
+It's possible to load the APTABASE_KEY from a .env file at compile time using the `dotenvy_macro` crate. The `.env` file needs to be
+in the project directory for the `dotevny_macro` crate to find it properly.
+
+Add the `use` declaration to where you are building the SDK (likely `main.rs`), and then call it where you would put the key.
```rust
+use aptabase_rs::Builder;
+use dotenvy_macro::dotenv;
+use std::error::Error;
+
#[tokio::main]
-async fn main() {
- tauri::Builder::default()
- .plugin(tauri_plugin_aptabase::Builder::new("").build()) // ๐ this is where you enter your App Key
- .run(tauri::generate_context!())
- .expect("error while running tauri application");
+async fn main() -> Result<(), Box> {
+ let client = Builder::new(dotenv!("APTABASE_KEY"), env!("CARGO_PKG_VERSION")).build();
+ client.track_event("app_started", None);
+
+ // do some work here...
+
+ client.track_event("app_exited", None);
+ client.flush().await;
+ Ok(())
}
```
-And finally add `aptabase:allow-track-event` to your list Access Control List.
+## Persisting sessions
-You can then start sending events from Rust by importing the `tauri_plugin_aptabase::EventTracker` trait and calling the `track_event` method on `App`, `AppHandle` or `Window`.
+By default, the SDK generates an in-memory session ID which rotates after 4 hours of inactivity or whenever the app restarts. Applications which start and exit frequently may want to persist the session ID to disk so it can be reused across restarts.
-As an example, you can add `app_started` and `app_exited` events like this:
+To implement persistent sessions, generate a new session ID with `aptabase_rs::new_session_id()` and persist it to your application's storage (file, database, etc.). This can be loaded at startup and passed to the builder with `Builder::with_session_id()`. When you do this, your application is responsible for rotating the persisted session ID; if it keeps reusing the same stored ID, those runs will be grouped into the same session.
```rust
-use tauri_plugin_aptabase::EventTracker;
+use aptabase_rs::Builder;
+use std::fs;
+
+let session_path = "aptabase-session-id";
+let session_id = fs::read_to_string(session_path).unwrap_or_else(|_| {
+ let id = aptabase_rs::new_session_id();
+ fs::write(session_path, &id).expect("failed to persist Aptabase session ID");
+ id
+});
+
+let client = Builder::new("", env!("CARGO_PKG_VERSION"))
+ .with_session_id(session_id)
+ .build();
+```
+
+## Periodic flushing
+
+Calling `track_event` only enqueues events to be sent to the server, you need to explicitly await `flush` to actually send the queued events. For short-lived applications, this would typically be done at the end of the application's lifecycle.
+
+Long-running applications can opt in to periodic flushing with `with_polling(true)`. The interval defaults to 60 seconds in release builds and 2 seconds in debug builds. This can be customized with `with_options(InitOptions)`. It is important that you still flush manually before the applcation exits, so that any remaining events in the queue are sent to the server.
+
+```rust
+use aptabase_rs::{Builder, InitOptions};
+use std::error::Error;
+use std::time::Duration;
#[tokio::main]
-async fn main() {
- tauri::Builder::default()
- .plugin(tauri_plugin_aptabase::init("".into()))
- .setup(|app| {
- app.track_event("app_started", None);
- Ok(())
- })
- .build(tauri::generate_context!())
- .expect("error while running tauri application")
- .run(|handler, event| match event {
- tauri::RunEvent::Exit { .. } => {
- handler.track_event("app_exited", None);
- handler.flush_events_blocking();
- }
- _ => {}
+async fn main() -> Result<(), Box> {
+ let client = Builder::new("", env!("CARGO_PKG_VERSION"))
+ .with_polling(true)
+ .with_options(InitOptions {
+ flush_interval: Some(Duration::from_secs(30)),
+ host: None,
})
+ .build();
+
+ // do some long-running work here...
+
+ client.flush().await;
+ Ok(())
}
```
-The `trackEvent` function is also available through the JavaScript guest bindings:
+## Panic hook
+
+You can use the default panic hook to enqueue a `panic` event before the process continues to the default panic handler. If the panicking thread has an active Tokio runtime, the hook makes a best-effort delivery attempt with the same Tokio-backed transport. Without an active Tokio runtime on that thread, the panic event is only enqueued in memory before the previous panic hook runs.
-```js
-import { trackEvent } from "@aptabase/tauri";
+```rust
+use aptabase_rs::Builder;
-trackEvent("save_settings") // An event with no properties
-trackEvent("screen_view", { name: "Settings" }) // An event with a custom property
+let client = Builder::new("", env!("CARGO_PKG_VERSION"))
+ .with_default_panic_hook()
+ .build();
```
-A few important notes:
+For custom panic event payloads, provide your own hook:
-1. The plugin will automatically enhance the event with some useful information, like the OS, the app version, and other things.
-2. You're in control of what gets sent to Aptabase. This plugin does not automatically track any events, you need to call `trackEvent` manually.
- - Because of this, it's generally recommended to at least track an event at startup
-3. You do not need to await for the `trackEvent` function, it'll run in the background.
-3. Only strings and numbers values are allowed on custom properties
+```rust
+use aptabase_rs::Builder;
+use serde_json::json;
+
+let client = Builder::new("", env!("CARGO_PKG_VERSION"))
+ .with_panic_hook(Box::new(|client, info, message| {
+ let location = info
+ .location()
+ .map(|loc| format!("{}:{}:{}", loc.file(), loc.line(), loc.column()))
+ .unwrap_or_default();
+
+ let _ = client.track_event(
+ "panic",
+ Some(json!({ "info": format!("{} ({})", message, location) })),
+ );
+ }))
+ .build();
+```
-## Providing the APTABASE_KEY via .env
+## Delivery behavior
-It's possible to load the APTABASE_KEY from a .env file at compile time using the `dotenvy_macro` crate. The `.env` file needs to be
-in the `src-tauri` directory for the `dotevny_macro` crate to find it properly.
+- Requests contain at most 25 events and use Aptabase's `/api/v0/events` endpoint.
+- Transport failures and HTTP 5xx responses are requeued in memory for a later flush.
+- Other unsuccessful HTTP responses are discarded.
+- This crate provides only the asynchronous Tokio transport; it does not expose a blocking flush API.
-Add the `use` declaration to where you are building the tauri app (likely `lib.rs` for Tauri v2), and then call it where you would put the key.
+## TLS backends
-```rust
-use tauri_plugin_aptabase::EventTracker;
-use dotenvy_macro::dotenv;
+The SDK uses [`reqwest`](https://crates.io/crates/reqwest) to send events, and you can choose its TLS backend with Cargo features:
-#[cfg_attr(mobile, tauri::mobile_entry_point)]
-/// This function sets up and runs a Rust application using the Tauri framework, with various plugins
-/// and event handlers.
-pub fn run() {
- tauri::Builder::default()
- .build(tauri::generate_context!())
- .plugin(tauri_plugin_aptabase::Builder::new(dotenv!("APTABASE_KEY")).build())
- .expect("Error when building tauri app")
- .run(|handler, event| match event {
- tauri::RunEvent::Exit { .. } => {
- handler.track_event("app_exited", None);
- handler.flush_events_blocking();
- }
- tauri::RunEvent::Ready { .. } => {
- handler.track_event("app_started", None);
- }
- _ => {}
- });
-}
+| Feature | Backend |
+| --- | --- |
+| `default-tls` (default) | `reqwest`'s default backend, currently `rustls` |
+| `rustls-tls` | `rustls` |
+| `native-tls` | The platform's native TLS library (OpenSSL on Linux) |
+
+To switch backend, disable the default features:
+
+```toml
+[dependencies]
+aptabase-rs = { version = "0.3", default-features = false, features = ["native-tls"] }
```
-For AI/LLM integration instructions, see [llms.txt](./llms.txt)
+Without any TLS feature, the SDK can only send events over plain HTTP. That works with `DEV` app keys, which send to `http://localhost:3000`, and with self-hosted servers on an `http://` host. Events sent to an `https://` host fail and are only logged at `debug` level.
+
+## Privacy
+
+The client never tracks events automatically. Applications decide which event names and properties to send. Each event includes the app version, SDK version, debug status, OS name and version, and locale. Avoid sending personal or sensitive data in event names or properties.
+
+See [Aptabase](https://aptabase.com) for service documentation and privacy guidance.
diff --git a/build.rs b/build.rs
deleted file mode 100644
index b6b7b1a..0000000
--- a/build.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-const COMMANDS: &[&str] = &["track_event"];
-
-fn main() {
- tauri_plugin::Builder::new(COMMANDS).build();
-}
diff --git a/cliff.toml b/cliff.toml
new file mode 100644
index 0000000..f8e622f
--- /dev/null
+++ b/cliff.toml
@@ -0,0 +1,54 @@
+# git-cliff ~ configuration file
+# https://git-cliff.org/docs/configuration
+
+[changelog]
+# Header template that will be rendered and added to the beginning of the changelog.
+header = "# Changelog"
+# A Tera template to be rendered for each release in the changelog.
+body = """
+
+{% if version %}\
+ ## {{ version | trim_start_matches(pat="v") }}
+{% else %}\
+ ## Unreleased
+{% endif %}\
+{% for group, commits in commits | group_by(attribute="group") %}
+ ### {{ group | striptags | trim | upper_first }}
+ {% for commit in commits %}
+ - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
+ {% if commit.breaking %}**BREAKING CHANGE**: {% endif %}\
+ {{ commit.message | upper_first }}\
+ {% endfor %}
+{% endfor %}
+"""
+
+[git]
+# Exclude tags that are not version-shaped.
+tag_pattern = "^v[0-9]"
+# An array of regex based parsers to modify commit messages prior to further processing.
+commit_preprocessors = [
+ # Replace issue numbers with link templates to be updated in `changelog.postprocessors`.
+ { pattern = '\(#([0-9]+)\)', replace = "([#${1}](https://github.com/eugencowie/aptabase-rs/pull/${1}))" },
+]
+# An array of regex based parsers for extracting data from the commit message.
+commit_parsers = [
+ { message = "^feat", group = "๐ Features" },
+ { message = "^fix", group = "๐ Bug Fixes" },
+ { message = "^doc", group = "๐ Documentation" },
+ { message = "^perf", group = "โก Performance" },
+ { message = "^refactor", group = "๐ Refactor" },
+ { message = "^style", group = "๐จ Styling" },
+ { message = "^test", group = "๐งช Testing" },
+ { message = "^chore\\(release\\)", skip = true },
+ { message = "^chore\\(deps.*\\)", skip = true },
+ { message = "^chore\\(pr\\)", skip = true },
+ { message = "^chore\\(pull\\)", skip = true },
+ { message = "^chore|^ci", group = "โ๏ธ Miscellaneous Tasks" },
+ { body = ".*security", group = "๐ก๏ธ Security" },
+ { message = "^revert", group = "โ๏ธ Revert" },
+ { message = ".*", group = "๐ผ Other" },
+]
+
+[bump]
+# Breaking changes bump the minor version while pre-1.0.
+breaking_always_bump_major = false
diff --git a/examples/helloworld/.env.example b/examples/helloworld/.env.example
new file mode 100644
index 0000000..f50fe9d
--- /dev/null
+++ b/examples/helloworld/.env.example
@@ -0,0 +1 @@
+APTABASE_KEY=
diff --git a/examples/helloworld/.gitignore b/examples/helloworld/.gitignore
deleted file mode 100644
index a547bf3..0000000
--- a/examples/helloworld/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
diff --git a/examples/helloworld/Cargo.toml b/examples/helloworld/Cargo.toml
new file mode 100644
index 0000000..5e1ed08
--- /dev/null
+++ b/examples/helloworld/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "helloworld"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+aptabase-rs = { path = "../.." }
+dotenvy_macro = "0.15.7"
+serde_json = "1.0.138"
+tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread"] }
diff --git a/examples/helloworld/index.html b/examples/helloworld/index.html
deleted file mode 100644
index fad1c5d..0000000
--- a/examples/helloworld/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
- Tauri + Svelte
-
-
-
-
-
-
-
diff --git a/examples/helloworld/jsconfig.json b/examples/helloworld/jsconfig.json
deleted file mode 100644
index ee5e92f..0000000
--- a/examples/helloworld/jsconfig.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "compilerOptions": {
- "moduleResolution": "Node",
- "target": "ESNext",
- "module": "ESNext",
- /**
- * svelte-preprocess cannot figure out whether you have
- * a value or a type, so tell TypeScript to enforce using
- * `import type` instead of `import` for Types.
- */
- "importsNotUsedAsValues": "error",
- "isolatedModules": true,
- "resolveJsonModule": true,
- /**
- * To have warnings / errors of the Svelte compiler at the
- * correct position, enable source maps by default.
- */
- "sourceMap": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "baseUrl": ".",
- /**
- * Typecheck JS in `.svelte` and `.js` files by default.
- * Disable this if you'd like to use dynamic types.
- */
- "checkJs": true
- },
- /**
- * Use global.d.ts instead of compilerOptions.types
- * to avoid limiting type declarations.
- */
- "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
-}
diff --git a/examples/helloworld/package.json b/examples/helloworld/package.json
deleted file mode 100644
index 8720e00..0000000
--- a/examples/helloworld/package.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "name": "helloworld",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "tauri dev",
- "dev:vite": "vite",
- "build": "tsc && vite build",
- "preview": "vite preview",
- "tauri": "tauri"
- },
- "dependencies": {
- "@tauri-apps/api": "^2.7.0",
- "@aptabase/tauri": "file:../../"
- },
- "devDependencies": {
- "@sveltejs/vite-plugin-svelte": "^1.0.1",
- "internal-ip": "^7.0.0",
- "svelte": "^3.49.0",
- "vite": "^3.0.2",
- "@tauri-apps/cli": "^2.1.0"
- }
-}
diff --git a/examples/helloworld/public/svelte.svg b/examples/helloworld/public/svelte.svg
deleted file mode 100644
index c5e0848..0000000
--- a/examples/helloworld/public/svelte.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/examples/helloworld/public/tauri.svg b/examples/helloworld/public/tauri.svg
deleted file mode 100644
index 31b62c9..0000000
--- a/examples/helloworld/public/tauri.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/examples/helloworld/public/vite.svg b/examples/helloworld/public/vite.svg
deleted file mode 100644
index e7b8dfb..0000000
--- a/examples/helloworld/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/examples/helloworld/src-tauri/.gitignore b/examples/helloworld/src-tauri/.gitignore
deleted file mode 100644
index f4dfb82..0000000
--- a/examples/helloworld/src-tauri/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-# Generated by Cargo
-# will have compiled files and executables
-/target/
-
diff --git a/examples/helloworld/src-tauri/Cargo.toml b/examples/helloworld/src-tauri/Cargo.toml
deleted file mode 100644
index 619e34e..0000000
--- a/examples/helloworld/src-tauri/Cargo.toml
+++ /dev/null
@@ -1,29 +0,0 @@
-[package]
-name = "tauri-app"
-version = "0.0.0"
-description = "A Tauri App"
-authors = ["you"]
-license = ""
-repository = ""
-edition = "2021"
-rust-version = "1.70"
-
-[lib]
-name = "tauri_app_lib"
-crate-type = ["staticlib", "cdylib", "rlib"]
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[build-dependencies]
-tauri-build = { version = "2.0", default-features = false, features = [] }
-
-[dependencies]
-tauri = { version = "2.1", features = [] }
-tauri-plugin-aptabase = { path = "../../../" }
-serde_json = "1.0"
-serde = { version = "1.0", features = ["derive"] }
-
-[features]
-# this feature is used for production builds or when `devUrl` points to the filesystem
-# DO NOT REMOVE!!
-custom-protocol = ["tauri/custom-protocol"]
diff --git a/examples/helloworld/src-tauri/build.rs b/examples/helloworld/src-tauri/build.rs
deleted file mode 100644
index 795b9b7..0000000
--- a/examples/helloworld/src-tauri/build.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
- tauri_build::build()
-}
diff --git a/examples/helloworld/src-tauri/capabilities/desktop.json b/examples/helloworld/src-tauri/capabilities/desktop.json
deleted file mode 100644
index 8182109..0000000
--- a/examples/helloworld/src-tauri/capabilities/desktop.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "identifier": "main-capability",
- "description": "Capability for the main window",
- "windows": ["main"],
- "permissions": [
- "aptabase:allow-track-event"
- ]
- }
\ No newline at end of file
diff --git a/examples/helloworld/src-tauri/gen/schemas/capabilities.json b/examples/helloworld/src-tauri/gen/schemas/capabilities.json
deleted file mode 100644
index ab8512e..0000000
--- a/examples/helloworld/src-tauri/gen/schemas/capabilities.json
+++ /dev/null
@@ -1 +0,0 @@
-{"main-capability":{"identifier":"main-capability","description":"Capability for the main window","context":"local","windows":["main"],"permissions":["aptabase:allow-track-event"],"platforms":["linux","macOS","windows","android","iOS"]}}
\ No newline at end of file
diff --git a/examples/helloworld/src-tauri/gen/schemas/desktop-schema.json b/examples/helloworld/src-tauri/gen/schemas/desktop-schema.json
deleted file mode 100644
index e42d396..0000000
--- a/examples/helloworld/src-tauri/gen/schemas/desktop-schema.json
+++ /dev/null
@@ -1 +0,0 @@
-{schema_str}
\ No newline at end of file
diff --git a/examples/helloworld/src-tauri/gen/schemas/macOS-schema.json b/examples/helloworld/src-tauri/gen/schemas/macOS-schema.json
deleted file mode 100644
index e42d396..0000000
--- a/examples/helloworld/src-tauri/gen/schemas/macOS-schema.json
+++ /dev/null
@@ -1 +0,0 @@
-{schema_str}
\ No newline at end of file
diff --git a/examples/helloworld/src-tauri/gen/schemas/plugin-manifests.json b/examples/helloworld/src-tauri/gen/schemas/plugin-manifests.json
deleted file mode 100644
index fc6adbe..0000000
--- a/examples/helloworld/src-tauri/gen/schemas/plugin-manifests.json
+++ /dev/null
@@ -1 +0,0 @@
-{"app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version"]},"permissions":{"allow-app-hide":{"version":null,"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]},"scope":{}},"allow-app-show":{"version":null,"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]},"scope":{}},"allow-name":{"version":null,"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]},"scope":{}},"allow-tauri-version":{"version":null,"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]},"scope":{}},"allow-version":{"version":null,"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]},"scope":{}},"deny-app-hide":{"version":null,"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]},"scope":{}},"deny-app-show":{"version":null,"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]},"scope":{}},"deny-name":{"version":null,"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]},"scope":{}},"deny-tauri-version":{"version":null,"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]},"scope":{}},"deny-version":{"version":null,"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]},"scope":{}}},"permission_sets":{},"global_scope_schema":null},"aptabase":{"default_permission":null,"permissions":{"allow-track-event":{"version":null,"identifier":"allow-track-event","description":"Enables the track_event command without any pre-configured scope.","commands":{"allow":["track_event"],"deny":[]},"scope":{}},"deny-track-event":{"version":null,"identifier":"deny-track-event","description":"Denies the track_event command without any pre-configured scope.","commands":{"allow":[],"deny":["track_event"]},"scope":{}}},"permission_sets":{},"global_scope_schema":null},"event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"version":null,"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]},"scope":{}},"allow-emit-to":{"version":null,"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]},"scope":{}},"allow-listen":{"version":null,"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]},"scope":{}},"allow-unlisten":{"version":null,"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]},"scope":{}},"deny-emit":{"version":null,"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]},"scope":{}},"deny-emit-to":{"version":null,"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]},"scope":{}},"deny-listen":{"version":null,"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]},"scope":{}},"deny-unlisten":{"version":null,"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]},"scope":{}}},"permission_sets":{},"global_scope_schema":null},"menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":[]},"permissions":{"allow-append":{"version":null,"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]},"scope":{}},"allow-create-default":{"version":null,"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]},"scope":{}},"allow-get":{"version":null,"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]},"scope":{}},"allow-insert":{"version":null,"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]},"scope":{}},"allow-is-checked":{"version":null,"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]},"scope":{}},"allow-is-enabled":{"version":null,"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]},"scope":{}},"allow-items":{"version":null,"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]},"scope":{}},"allow-new":{"version":null,"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]},"scope":{}},"allow-popup":{"version":null,"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]},"scope":{}},"allow-prepend":{"version":null,"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]},"scope":{}},"allow-remove":{"version":null,"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]},"scope":{}},"allow-remove-at":{"version":null,"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]},"scope":{}},"allow-set-accelerator":{"version":null,"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]},"scope":{}},"allow-set-as-app-menu":{"version":null,"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]},"scope":{}},"allow-set-as-help-menu-for-nsapp":{"version":null,"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]},"scope":{}},"allow-set-as-window-menu":{"version":null,"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]},"scope":{}},"allow-set-as-windows-menu-for-nsapp":{"version":null,"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]},"scope":{}},"allow-set-checked":{"version":null,"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]},"scope":{}},"allow-set-enabled":{"version":null,"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]},"scope":{}},"allow-set-icon":{"version":null,"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]},"scope":{}},"allow-set-text":{"version":null,"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]},"scope":{}},"allow-text":{"version":null,"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]},"scope":{}},"deny-append":{"version":null,"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]},"scope":{}},"deny-create-default":{"version":null,"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]},"scope":{}},"deny-get":{"version":null,"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]},"scope":{}},"deny-insert":{"version":null,"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]},"scope":{}},"deny-is-checked":{"version":null,"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]},"scope":{}},"deny-is-enabled":{"version":null,"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]},"scope":{}},"deny-items":{"version":null,"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]},"scope":{}},"deny-new":{"version":null,"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]},"scope":{}},"deny-popup":{"version":null,"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]},"scope":{}},"deny-prepend":{"version":null,"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]},"scope":{}},"deny-remove":{"version":null,"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]},"scope":{}},"deny-remove-at":{"version":null,"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]},"scope":{}},"deny-set-accelerator":{"version":null,"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]},"scope":{}},"deny-set-as-app-menu":{"version":null,"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]},"scope":{}},"deny-set-as-help-menu-for-nsapp":{"version":null,"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]},"scope":{}},"deny-set-as-window-menu":{"version":null,"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]},"scope":{}},"deny-set-as-windows-menu-for-nsapp":{"version":null,"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]},"scope":{}},"deny-set-checked":{"version":null,"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]},"scope":{}},"deny-set-enabled":{"version":null,"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]},"scope":{}},"deny-set-icon":{"version":null,"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]},"scope":{}},"deny-set-text":{"version":null,"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]},"scope":{}},"deny-text":{"version":null,"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]},"scope":{}}},"permission_sets":{},"global_scope_schema":null},"path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"version":null,"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]},"scope":{}},"allow-dirname":{"version":null,"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]},"scope":{}},"allow-extname":{"version":null,"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]},"scope":{}},"allow-is-absolute":{"version":null,"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]},"scope":{}},"allow-join":{"version":null,"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]},"scope":{}},"allow-normalize":{"version":null,"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]},"scope":{}},"allow-resolve":{"version":null,"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]},"scope":{}},"allow-resolve-directory":{"version":null,"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]},"scope":{}},"deny-basename":{"version":null,"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]},"scope":{}},"deny-dirname":{"version":null,"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]},"scope":{}},"deny-extname":{"version":null,"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]},"scope":{}},"deny-is-absolute":{"version":null,"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]},"scope":{}},"deny-join":{"version":null,"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]},"scope":{}},"deny-normalize":{"version":null,"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]},"scope":{}},"deny-resolve":{"version":null,"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]},"scope":{}},"deny-resolve-directory":{"version":null,"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]},"scope":{}}},"permission_sets":{},"global_scope_schema":null},"resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-close"]},"permissions":{"allow-close":{"version":null,"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]},"scope":{}},"deny-close":{"version":null,"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]},"scope":{}}},"permission_sets":{},"global_scope_schema":null},"tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":[]},"permissions":{"allow-new":{"version":null,"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]},"scope":{}},"allow-set-icon":{"version":null,"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]},"scope":{}},"allow-set-icon-as-template":{"version":null,"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]},"scope":{}},"allow-set-menu":{"version":null,"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]},"scope":{}},"allow-set-show-menu-on-left-click":{"version":null,"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]},"scope":{}},"allow-set-temp-dir-path":{"version":null,"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]},"scope":{}},"allow-set-title":{"version":null,"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]},"scope":{}},"allow-set-tooltip":{"version":null,"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]},"scope":{}},"allow-set-visible":{"version":null,"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]},"scope":{}},"deny-new":{"version":null,"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]},"scope":{}},"deny-set-icon":{"version":null,"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]},"scope":{}},"deny-set-icon-as-template":{"version":null,"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]},"scope":{}},"deny-set-menu":{"version":null,"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]},"scope":{}},"deny-set-show-menu-on-left-click":{"version":null,"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]},"scope":{}},"deny-set-temp-dir-path":{"version":null,"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]},"scope":{}},"deny-set-title":{"version":null,"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]},"scope":{}},"deny-set-tooltip":{"version":null,"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]},"scope":{}},"deny-set-visible":{"version":null,"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]},"scope":{}}},"permission_sets":{},"global_scope_schema":null},"webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-create-webview":{"version":null,"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]},"scope":{}},"allow-create-webview-window":{"version":null,"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]},"scope":{}},"allow-internal-toggle-devtools":{"version":null,"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]},"scope":{}},"allow-print":{"version":null,"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]},"scope":{}},"allow-set-webview-focus":{"version":null,"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]},"scope":{}},"allow-set-webview-position":{"version":null,"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]},"scope":{}},"allow-set-webview-size":{"version":null,"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]},"scope":{}},"allow-webview-close":{"version":null,"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]},"scope":{}},"allow-webview-position":{"version":null,"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]},"scope":{}},"allow-webview-size":{"version":null,"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]},"scope":{}},"deny-create-webview":{"version":null,"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]},"scope":{}},"deny-create-webview-window":{"version":null,"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]},"scope":{}},"deny-internal-toggle-devtools":{"version":null,"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]},"scope":{}},"deny-print":{"version":null,"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]},"scope":{}},"deny-set-webview-focus":{"version":null,"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]},"scope":{}},"deny-set-webview-position":{"version":null,"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]},"scope":{}},"deny-set-webview-size":{"version":null,"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]},"scope":{}},"deny-webview-close":{"version":null,"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]},"scope":{}},"deny-webview-position":{"version":null,"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]},"scope":{}},"deny-webview-size":{"version":null,"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]},"scope":{}}},"permission_sets":{},"global_scope_schema":null},"window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-title","allow-current-monitor","allow-primary-monitor","allow-available-monitors","allow-theme","allow-internal-toggle-maximize","allow-internal-on-mousemove","allow-internal-on-mousedown"]},"permissions":{"allow-available-monitors":{"version":null,"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]},"scope":{}},"allow-center":{"version":null,"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]},"scope":{}},"allow-close":{"version":null,"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]},"scope":{}},"allow-create":{"version":null,"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]},"scope":{}},"allow-current-monitor":{"version":null,"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]},"scope":{}},"allow-destroy":{"version":null,"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]},"scope":{}},"allow-hide":{"version":null,"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]},"scope":{}},"allow-inner-position":{"version":null,"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]},"scope":{}},"allow-inner-size":{"version":null,"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]},"scope":{}},"allow-internal-on-mousedown":{"version":null,"identifier":"allow-internal-on-mousedown","description":"Enables the internal_on_mousedown command without any pre-configured scope.","commands":{"allow":["internal_on_mousedown"],"deny":[]},"scope":{}},"allow-internal-on-mousemove":{"version":null,"identifier":"allow-internal-on-mousemove","description":"Enables the internal_on_mousemove command without any pre-configured scope.","commands":{"allow":["internal_on_mousemove"],"deny":[]},"scope":{}},"allow-internal-toggle-maximize":{"version":null,"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]},"scope":{}},"allow-is-closable":{"version":null,"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]},"scope":{}},"allow-is-decorated":{"version":null,"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]},"scope":{}},"allow-is-focused":{"version":null,"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]},"scope":{}},"allow-is-fullscreen":{"version":null,"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]},"scope":{}},"allow-is-maximizable":{"version":null,"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]},"scope":{}},"allow-is-maximized":{"version":null,"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]},"scope":{}},"allow-is-minimizable":{"version":null,"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]},"scope":{}},"allow-is-minimized":{"version":null,"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]},"scope":{}},"allow-is-resizable":{"version":null,"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]},"scope":{}},"allow-is-visible":{"version":null,"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]},"scope":{}},"allow-maximize":{"version":null,"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]},"scope":{}},"allow-minimize":{"version":null,"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]},"scope":{}},"allow-outer-position":{"version":null,"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]},"scope":{}},"allow-outer-size":{"version":null,"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]},"scope":{}},"allow-primary-monitor":{"version":null,"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]},"scope":{}},"allow-request-user-attention":{"version":null,"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]},"scope":{}},"allow-scale-factor":{"version":null,"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]},"scope":{}},"allow-set-always-on-bottom":{"version":null,"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]},"scope":{}},"allow-set-always-on-top":{"version":null,"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]},"scope":{}},"allow-set-closable":{"version":null,"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]},"scope":{}},"allow-set-content-protected":{"version":null,"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]},"scope":{}},"allow-set-cursor-grab":{"version":null,"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]},"scope":{}},"allow-set-cursor-icon":{"version":null,"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]},"scope":{}},"allow-set-cursor-position":{"version":null,"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]},"scope":{}},"allow-set-cursor-visible":{"version":null,"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]},"scope":{}},"allow-set-decorations":{"version":null,"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]},"scope":{}},"allow-set-effects":{"version":null,"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]},"scope":{}},"allow-set-focus":{"version":null,"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]},"scope":{}},"allow-set-fullscreen":{"version":null,"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]},"scope":{}},"allow-set-icon":{"version":null,"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]},"scope":{}},"allow-set-ignore-cursor-events":{"version":null,"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]},"scope":{}},"allow-set-max-size":{"version":null,"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]},"scope":{}},"allow-set-maximizable":{"version":null,"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]},"scope":{}},"allow-set-min-size":{"version":null,"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]},"scope":{}},"allow-set-minimizable":{"version":null,"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]},"scope":{}},"allow-set-position":{"version":null,"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]},"scope":{}},"allow-set-progress-bar":{"version":null,"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]},"scope":{}},"allow-set-resizable":{"version":null,"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]},"scope":{}},"allow-set-shadow":{"version":null,"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]},"scope":{}},"allow-set-size":{"version":null,"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]},"scope":{}},"allow-set-skip-taskbar":{"version":null,"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]},"scope":{}},"allow-set-title":{"version":null,"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]},"scope":{}},"allow-set-visible-on-all-workspaces":{"version":null,"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]},"scope":{}},"allow-show":{"version":null,"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]},"scope":{}},"allow-start-dragging":{"version":null,"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]},"scope":{}},"allow-theme":{"version":null,"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]},"scope":{}},"allow-title":{"version":null,"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]},"scope":{}},"allow-toggle-maximize":{"version":null,"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]},"scope":{}},"allow-unmaximize":{"version":null,"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]},"scope":{}},"allow-unminimize":{"version":null,"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]},"scope":{}},"deny-available-monitors":{"version":null,"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]},"scope":{}},"deny-center":{"version":null,"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]},"scope":{}},"deny-close":{"version":null,"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]},"scope":{}},"deny-create":{"version":null,"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]},"scope":{}},"deny-current-monitor":{"version":null,"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]},"scope":{}},"deny-destroy":{"version":null,"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]},"scope":{}},"deny-hide":{"version":null,"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]},"scope":{}},"deny-inner-position":{"version":null,"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]},"scope":{}},"deny-inner-size":{"version":null,"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]},"scope":{}},"deny-internal-on-mousedown":{"version":null,"identifier":"deny-internal-on-mousedown","description":"Denies the internal_on_mousedown command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_on_mousedown"]},"scope":{}},"deny-internal-on-mousemove":{"version":null,"identifier":"deny-internal-on-mousemove","description":"Denies the internal_on_mousemove command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_on_mousemove"]},"scope":{}},"deny-internal-toggle-maximize":{"version":null,"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]},"scope":{}},"deny-is-closable":{"version":null,"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]},"scope":{}},"deny-is-decorated":{"version":null,"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]},"scope":{}},"deny-is-focused":{"version":null,"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]},"scope":{}},"deny-is-fullscreen":{"version":null,"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]},"scope":{}},"deny-is-maximizable":{"version":null,"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]},"scope":{}},"deny-is-maximized":{"version":null,"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]},"scope":{}},"deny-is-minimizable":{"version":null,"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]},"scope":{}},"deny-is-minimized":{"version":null,"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]},"scope":{}},"deny-is-resizable":{"version":null,"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]},"scope":{}},"deny-is-visible":{"version":null,"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]},"scope":{}},"deny-maximize":{"version":null,"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]},"scope":{}},"deny-minimize":{"version":null,"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]},"scope":{}},"deny-outer-position":{"version":null,"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]},"scope":{}},"deny-outer-size":{"version":null,"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]},"scope":{}},"deny-primary-monitor":{"version":null,"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]},"scope":{}},"deny-request-user-attention":{"version":null,"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]},"scope":{}},"deny-scale-factor":{"version":null,"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]},"scope":{}},"deny-set-always-on-bottom":{"version":null,"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]},"scope":{}},"deny-set-always-on-top":{"version":null,"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]},"scope":{}},"deny-set-closable":{"version":null,"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]},"scope":{}},"deny-set-content-protected":{"version":null,"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]},"scope":{}},"deny-set-cursor-grab":{"version":null,"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]},"scope":{}},"deny-set-cursor-icon":{"version":null,"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]},"scope":{}},"deny-set-cursor-position":{"version":null,"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]},"scope":{}},"deny-set-cursor-visible":{"version":null,"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]},"scope":{}},"deny-set-decorations":{"version":null,"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]},"scope":{}},"deny-set-effects":{"version":null,"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]},"scope":{}},"deny-set-focus":{"version":null,"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]},"scope":{}},"deny-set-fullscreen":{"version":null,"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]},"scope":{}},"deny-set-icon":{"version":null,"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]},"scope":{}},"deny-set-ignore-cursor-events":{"version":null,"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]},"scope":{}},"deny-set-max-size":{"version":null,"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]},"scope":{}},"deny-set-maximizable":{"version":null,"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]},"scope":{}},"deny-set-min-size":{"version":null,"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]},"scope":{}},"deny-set-minimizable":{"version":null,"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]},"scope":{}},"deny-set-position":{"version":null,"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]},"scope":{}},"deny-set-progress-bar":{"version":null,"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]},"scope":{}},"deny-set-resizable":{"version":null,"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]},"scope":{}},"deny-set-shadow":{"version":null,"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]},"scope":{}},"deny-set-size":{"version":null,"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]},"scope":{}},"deny-set-skip-taskbar":{"version":null,"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]},"scope":{}},"deny-set-title":{"version":null,"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]},"scope":{}},"deny-set-visible-on-all-workspaces":{"version":null,"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]},"scope":{}},"deny-show":{"version":null,"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]},"scope":{}},"deny-start-dragging":{"version":null,"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]},"scope":{}},"deny-theme":{"version":null,"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]},"scope":{}},"deny-title":{"version":null,"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]},"scope":{}},"deny-toggle-maximize":{"version":null,"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]},"scope":{}},"deny-unmaximize":{"version":null,"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]},"scope":{}},"deny-unminimize":{"version":null,"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]},"scope":{}}},"permission_sets":{},"global_scope_schema":null}}
\ No newline at end of file
diff --git a/examples/helloworld/src-tauri/icons/128x128.png b/examples/helloworld/src-tauri/icons/128x128.png
deleted file mode 100644
index 77e7d23..0000000
Binary files a/examples/helloworld/src-tauri/icons/128x128.png and /dev/null differ
diff --git a/examples/helloworld/src-tauri/icons/128x128@2x.png b/examples/helloworld/src-tauri/icons/128x128@2x.png
deleted file mode 100644
index 0f7976f..0000000
Binary files a/examples/helloworld/src-tauri/icons/128x128@2x.png and /dev/null differ
diff --git a/examples/helloworld/src-tauri/icons/32x32.png b/examples/helloworld/src-tauri/icons/32x32.png
deleted file mode 100644
index 98fda06..0000000
Binary files a/examples/helloworld/src-tauri/icons/32x32.png and /dev/null differ
diff --git a/examples/helloworld/src-tauri/icons/icon.icns b/examples/helloworld/src-tauri/icons/icon.icns
deleted file mode 100644
index 29d6685..0000000
Binary files a/examples/helloworld/src-tauri/icons/icon.icns and /dev/null differ
diff --git a/examples/helloworld/src-tauri/icons/icon.ico b/examples/helloworld/src-tauri/icons/icon.ico
deleted file mode 100644
index 06c23c8..0000000
Binary files a/examples/helloworld/src-tauri/icons/icon.ico and /dev/null differ
diff --git a/examples/helloworld/src-tauri/icons/icon.png b/examples/helloworld/src-tauri/icons/icon.png
deleted file mode 100644
index d1756ce..0000000
Binary files a/examples/helloworld/src-tauri/icons/icon.png and /dev/null differ
diff --git a/examples/helloworld/src-tauri/src/lib.rs b/examples/helloworld/src-tauri/src/lib.rs
deleted file mode 100644
index f520eb8..0000000
--- a/examples/helloworld/src-tauri/src/lib.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use serde_json::json;
-
-#[tauri::command]
-fn greet(name: &str) -> String {
- format!("Hello, {}! You've been greeted from Rust!", name)
-}
-
-#[tauri::command]
-fn this_will_panic() {
- panic!("I told you!");
-}
-
-#[cfg_attr(mobile, tauri::mobile_entry_point)]
-pub fn run() {
- tauri::Builder::default()
- .invoke_handler(tauri::generate_handler![greet, this_will_panic])
- .plugin(tauri_plugin_aptabase::Builder::new("A-US-0928558097").with_panic_hook(Box::new(|client, info, msg| {
- let location = info.location().map(|loc| format!("{}:{}:{}", loc.file(), loc.line(), loc.column())).unwrap_or_else(|| "".to_string());
-
- client.track_event("panic", Some(json!({
- "info": format!("{} ({})", msg, location),
- })));
- })).build())
- .run(tauri::generate_context!())
- .expect("error while running tauri application");
-}
diff --git a/examples/helloworld/src-tauri/src/main.rs b/examples/helloworld/src-tauri/src/main.rs
deleted file mode 100644
index 455963e..0000000
--- a/examples/helloworld/src-tauri/src/main.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// Prevents additional console window on Windows in release, DO NOT REMOVE!!
-#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
-
-fn main() {
- tauri_app_lib::run();
-}
diff --git a/examples/helloworld/src-tauri/tauri.conf.json b/examples/helloworld/src-tauri/tauri.conf.json
deleted file mode 100644
index b028d19..0000000
--- a/examples/helloworld/src-tauri/tauri.conf.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "productName": "tauri-app",
- "version": "0.0.0",
- "identifier": "com.tauri.dev",
- "build": {
- "beforeDevCommand": "npm run dev:vite",
- "beforeBuildCommand": "npm run build",
- "devUrl": "http://localhost:1420",
- "frontendDist": "../dist"
- },
- "app": {
- "withGlobalTauri": false,
- "security": {
- "csp": null
- },
- "windows": [
- {
- "fullscreen": false,
- "height": 600,
- "resizable": true,
- "title": "tauri-app",
- "width": 800
- }
- ]
- },
- "bundle": {
- "active": true,
- "targets": "all",
- "icon": [
- "icons/32x32.png",
- "icons/128x128.png",
- "icons/128x128@2x.png",
- "icons/icon.icns",
- "icons/icon.ico"
- ]
- }
-}
diff --git a/examples/helloworld/src/App.svelte b/examples/helloworld/src/App.svelte
deleted file mode 100644
index 126b4a4..0000000
--- a/examples/helloworld/src/App.svelte
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
- Welcome to Tauri!
-
-
-
-
- Click on the Tauri, Vite, and Svelte logos to learn more.
-
-
-
-
-
-
-
- PANIC!
-
-
-
-
-
diff --git a/examples/helloworld/src/lib/Greet.svelte b/examples/helloworld/src/lib/Greet.svelte
deleted file mode 100644
index 91b9989..0000000
--- a/examples/helloworld/src/lib/Greet.svelte
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
- Greet
-
-
-
{greetMsg}
-
-
diff --git a/examples/helloworld/src/main.js b/examples/helloworld/src/main.js
deleted file mode 100644
index 6b4e1a9..0000000
--- a/examples/helloworld/src/main.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import "./style.css";
-import App from "./App.svelte";
-
-const app = new App({
- target: document.getElementById("app"),
-});
-
-export default app;
diff --git a/examples/helloworld/src/main.rs b/examples/helloworld/src/main.rs
new file mode 100644
index 0000000..b6bbabf
--- /dev/null
+++ b/examples/helloworld/src/main.rs
@@ -0,0 +1,24 @@
+// Copy .env.example to .env and set APTABASE_KEY.
+
+use aptabase_rs::Builder;
+use dotenvy_macro::dotenv;
+use serde_json::json;
+use std::error::Error;
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let client = Builder::new(dotenv!("APTABASE_KEY"), env!("CARGO_PKG_VERSION"))
+ .with_default_panic_hook()
+ .with_polling(true) // long-running processes can use polling to send events at regular intervals
+ .build();
+
+ client.track_event(
+ "cli_started",
+ Some(json!({
+ "msg": "Hello, world!"
+ })),
+ )?;
+
+ client.flush().await;
+ Ok(())
+}
diff --git a/examples/helloworld/src/style.css b/examples/helloworld/src/style.css
deleted file mode 100644
index c0f9e3b..0000000
--- a/examples/helloworld/src/style.css
+++ /dev/null
@@ -1,102 +0,0 @@
-:root {
- font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
- font-size: 16px;
- line-height: 24px;
- font-weight: 400;
-
- color: #0f0f0f;
- background-color: #f6f6f6;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- -webkit-text-size-adjust: 100%;
-}
-
-.container {
- margin: 0;
- padding-top: 10vh;
- display: flex;
- flex-direction: column;
- justify-content: center;
- text-align: center;
-}
-
-.logo {
- height: 6em;
- padding: 1.5em;
- will-change: filter;
- transition: 0.75s;
-}
-
-.logo.tauri:hover {
- filter: drop-shadow(0 0 2em #24c8db);
-}
-
-.row {
- display: flex;
- justify-content: center;
-}
-
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-
-a:hover {
- color: #535bf2;
-}
-
-h1 {
- text-align: center;
-}
-
-input,
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- color: #0f0f0f;
- background-color: #ffffff;
- transition: border-color 0.25s;
- box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
-}
-
-button {
- cursor: pointer;
-}
-
-button:hover {
- border-color: #396cd8;
-}
-
-input,
-button {
- outline: none;
-}
-
-#greet-input {
- margin-right: 5px;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- color: #f6f6f6;
- background-color: #2f2f2f;
- }
-
- a:hover {
- color: #24c8db;
- }
-
- input,
- button {
- color: #ffffff;
- background-color: #0f0f0f98;
- }
-}
diff --git a/examples/helloworld/src/vite-env.d.ts b/examples/helloworld/src/vite-env.d.ts
deleted file mode 100644
index 4078e74..0000000
--- a/examples/helloworld/src/vite-env.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-///
-///
diff --git a/examples/helloworld/vite.config.js b/examples/helloworld/vite.config.js
deleted file mode 100644
index 4e1a260..0000000
--- a/examples/helloworld/vite.config.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { defineConfig } from "vite";
-import { svelte } from "@sveltejs/vite-plugin-svelte";
-import { internalIpV4Sync } from 'internal-ip'
-
-const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM);
-
-// https://vitejs.dev/config/
-export default defineConfig({
- plugins: [svelte()],
-
- // Vite optons tailored for Tauri development and only applied in `tauri dev` or `tauri build`
- // prevent vite from obscuring rust errors
- clearScreen: false,
- // tauri expects a fixed port, fail if that port is not available
- server: {
- host: mobile ? "0.0.0.0" : false,
- port: 1420,
- strictPort: true,
- hmr: mobile ? {
- protocol: 'ws',
- host: internalIpV4Sync(),
- port: 1421
- } : undefined,
- },
-})
diff --git a/llms.txt b/llms.txt
deleted file mode 100644
index 5003bae..0000000
--- a/llms.txt
+++ /dev/null
@@ -1,161 +0,0 @@
-# Aptabase โ Tauri Plugin
-
-> Tauri plugin for Aptabase: open-source, privacy-first analytics for desktop and mobile apps built with Tauri v2.
-
-Rust Crate: `tauri-plugin-aptabase`
-Install (Rust): `cargo add tauri-plugin-aptabase`
-npm Package: `@aptabase/tauri`
-Install (JS): `npm add @aptabase/tauri`
-Repo: https://github.com/aptabase/tauri-plugin-aptabase
-
-## Overview
-
-Aptabase is an open-source, privacy-first analytics platform. This plugin integrates Aptabase into Tauri v2 apps.
-
-- Get your App Key from the Aptabase dashboard (Settings > Instructions)
-- App keys follow the format `A-EU-*` (European) or `A-US-*` (US)
-- Only strings and numbers are allowed as custom property values
-- All tracking is non-blocking and runs in the background
-- No events are tracked automatically โ you must call `track_event`/`trackEvent` manually
-- The plugin automatically captures OS, app version, locale, and other system properties
-
-## Important: Dual API (Rust + JavaScript)
-
-This plugin provides **two APIs** โ use whichever fits your app architecture:
-
-- **Rust API** โ use `EventTracker` trait on `App`, `AppHandle`, or `Window`
-- **JavaScript API** โ use `trackEvent()` from `@aptabase/tauri` in your webview frontend
-
-Both APIs require the Rust plugin to be registered in your Tauri builder. The JS API calls the Rust backend via Tauri's IPC.
-
-## Installation
-
-### 1. Add the Rust crate
-
-In `src-tauri/Cargo.toml`:
-
-```toml
-[dependencies]
-tauri-plugin-aptabase = "1.0.0"
-```
-
-### 2. Add the JS package (optional, for webview tracking)
-
-```bash
-npm add @aptabase/tauri
-```
-
-### 3. Register the plugin
-
-In `src-tauri/src/main.rs` (or `lib.rs`):
-
-```rust
-#[tokio::main]
-async fn main() {
- tauri::Builder::default()
- .plugin(tauri_plugin_aptabase::Builder::new("").build())
- .run(tauri::generate_context!())
- .expect("error while running tauri application");
-}
-```
-
-### 4. Add ACL permission
-
-Add `aptabase:allow-track-event` to your Tauri capabilities to allow the JS API to send events. In your `src-tauri/capabilities/*.json`:
-
-```json
-{
- "permissions": ["aptabase:allow-track-event"]
-}
-```
-
-## Track Events (Rust)
-
-Import the `EventTracker` trait and call `track_event` on `App`, `AppHandle`, or `Window`:
-
-```rust
-use tauri_plugin_aptabase::EventTracker;
-
-// Event with no properties
-app.track_event("app_started", None);
-
-// Event with properties (serde_json::Value)
-app.track_event("screen_view", Some(serde_json::json!({ "name": "Settings" })));
-```
-
-Full example with startup and exit events:
-
-```rust
-use tauri_plugin_aptabase::EventTracker;
-
-#[tokio::main]
-async fn main() {
- tauri::Builder::default()
- .plugin(tauri_plugin_aptabase::Builder::new("").build())
- .setup(|app| {
- app.track_event("app_started", None);
- Ok(())
- })
- .build(tauri::generate_context!())
- .expect("error while running tauri application")
- .run(|handler, event| match event {
- tauri::RunEvent::Exit { .. } => {
- handler.track_event("app_exited", None);
- handler.flush_events_blocking();
- }
- _ => {}
- });
-}
-```
-
-## Track Events (JavaScript)
-
-```js
-import { trackEvent } from "@aptabase/tauri";
-
-trackEvent("app_started");
-```
-
-## Track Events with Properties (JavaScript)
-
-```js
-import { trackEvent } from "@aptabase/tauri";
-
-trackEvent("screen_view", { name: "Settings" });
-trackEvent("purchase", { plan: "pro", price: 9.99 });
-```
-
-## Configuration
-
-The `Builder` accepts optional `InitOptions`:
-
-```rust
-use tauri_plugin_aptabase::{Builder, InitOptions};
-use std::time::Duration;
-
-tauri::Builder::default()
- .plugin(
- Builder::new("")
- .with_options(InitOptions {
- host: Some("https://your-self-hosted-instance.com".into()), // self-hosted only (A-SH-* keys)
- flush_interval: Some(Duration::from_secs(30)), // custom flush interval
- })
- .build()
- )
-```
-
-- `host` โ required only for self-hosted Aptabase instances (app keys starting with `A-SH-*`)
-- `flush_interval` โ defaults to 60s in release, 2s in debug mode
-- Events are batched and flushed periodically; `flush_events_blocking()` forces an immediate flush
-
-## Platform Notes
-
-- Requires Tauri v2 (2.x)
-- Rust edition 2021, MSRV 1.70
-- The `EventTracker` trait is implemented for `App`, `AppHandle`, and `Window`
-- The JS `trackEvent` is async but you don't need to await it
-- A custom panic hook can be set via `Builder::with_panic_hook()` to track crashes
-
-## Cross-Discovery
-
-For all Aptabase SDKs and documentation, see: https://aptabase.com/llms.txt
diff --git a/mise.lock b/mise.lock
new file mode 100644
index 0000000..5b8ec86
--- /dev/null
+++ b/mise.lock
@@ -0,0 +1,261 @@
+# @generated - this file is auto-generated by `mise lock` https://mise.jdx.dev/dev-tools/mise-lock.html
+
+lockfile_version = 3
+
+[[tools.gh]]
+version = "2.96.0"
+backend = "aqua:cli/cli"
+specifiers = ["latest"]
+
+[tools.gh."platforms.linux-arm64"]
+checksum = "sha256:06f86ec7103d41993b76cd78072f43595c34aaa56506d971d9860e67140bf909"
+url = "https://github.com/cli/cli/releases/download/v2.96.0/gh_2.96.0_linux_arm64.tar.gz"
+url_api = "https://api.github.com/repos/cli/cli/releases/assets/464728549"
+provenance = "github-attestations"
+
+[tools.gh."platforms.linux-arm64-musl"]
+checksum = "sha256:06f86ec7103d41993b76cd78072f43595c34aaa56506d971d9860e67140bf909"
+url = "https://github.com/cli/cli/releases/download/v2.96.0/gh_2.96.0_linux_arm64.tar.gz"
+url_api = "https://api.github.com/repos/cli/cli/releases/assets/464728549"
+provenance = "github-attestations"
+
+[tools.gh."platforms.linux-x64"]
+checksum = "sha256:83d5c2ccad5498f58bf6368acb1ab32588cf43ab3a4b1c301bf36328b1c8bd60"
+url = "https://github.com/cli/cli/releases/download/v2.96.0/gh_2.96.0_linux_amd64.tar.gz"
+url_api = "https://api.github.com/repos/cli/cli/releases/assets/464728543"
+provenance = "github-attestations"
+
+[tools.gh."platforms.linux-x64-musl"]
+checksum = "sha256:83d5c2ccad5498f58bf6368acb1ab32588cf43ab3a4b1c301bf36328b1c8bd60"
+url = "https://github.com/cli/cli/releases/download/v2.96.0/gh_2.96.0_linux_amd64.tar.gz"
+url_api = "https://api.github.com/repos/cli/cli/releases/assets/464728543"
+provenance = "github-attestations"
+
+[tools.gh."platforms.macos-arm64"]
+checksum = "sha256:f23a0c37d963aacc3bed703ccbd59b41c5ca22101fab7f00eb2b7cad23aba463"
+url = "https://github.com/cli/cli/releases/download/v2.96.0/gh_2.96.0_macOS_arm64.zip"
+url_api = "https://api.github.com/repos/cli/cli/releases/assets/464728562"
+provenance = "github-attestations"
+
+[tools.gh."platforms.macos-x64"]
+checksum = "sha256:4bd449df9ad639391bc62b8032546f0fe9edcd8526e06682a4f88abd8c5d163c"
+url = "https://github.com/cli/cli/releases/download/v2.96.0/gh_2.96.0_macOS_amd64.zip"
+url_api = "https://api.github.com/repos/cli/cli/releases/assets/464728560"
+provenance = "github-attestations"
+
+[tools.gh."platforms.windows-x64"]
+checksum = "sha256:c2d6acc935cd2f00e2144d7e036d5cd82e6b6bd5594e8c75aa75ef2a4ed6aac3"
+url = "https://github.com/cli/cli/releases/download/v2.96.0/gh_2.96.0_windows_amd64.zip"
+url_api = "https://api.github.com/repos/cli/cli/releases/assets/464728577"
+provenance = "github-attestations"
+
+[[tools.git-cliff]]
+version = "2.13.1"
+backend = "aqua:orhun/git-cliff"
+specifiers = ["latest"]
+
+[tools.git-cliff."platforms.linux-arm64"]
+checksum = "sha256:9619b7f0c584229f8a2331c1905afe88bd938bdc9102926c2073836a42f02455"
+url = "https://github.com/orhun/git-cliff/releases/download/v2.13.1/git-cliff-2.13.1-aarch64-unknown-linux-gnu.tar.gz"
+url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/405850077"
+
+[tools.git-cliff."platforms.linux-arm64-musl"]
+checksum = "sha256:4054c124b926c117f3fa048939bc8be0a954f29f3b6f367627e8cb22c1971882"
+url = "https://github.com/orhun/git-cliff/releases/download/v2.13.1/git-cliff-2.13.1-aarch64-unknown-linux-musl.tar.gz"
+url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/405850720"
+
+[tools.git-cliff."platforms.linux-x64"]
+checksum = "sha256:9a1263f24e59a2f508c7b3d3283c9dea94a8bf697f96dbc18cc783cac6284546"
+url = "https://github.com/orhun/git-cliff/releases/download/v2.13.1/git-cliff-2.13.1-x86_64-unknown-linux-gnu.tar.gz"
+url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/405850439"
+
+[tools.git-cliff."platforms.linux-x64-musl"]
+checksum = "sha256:200d2535da6d9703f3bcc8a4d159c3b55eacdb01cf2148c55b3eee9dd04d5249"
+url = "https://github.com/orhun/git-cliff/releases/download/v2.13.1/git-cliff-2.13.1-x86_64-unknown-linux-musl.tar.gz"
+url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/405850671"
+
+[tools.git-cliff."platforms.macos-arm64"]
+checksum = "sha256:21547ae4a0421164070ab75c2522864ea5565858a011fabc5f583061b20f1226"
+url = "https://github.com/orhun/git-cliff/releases/download/v2.13.1/git-cliff-2.13.1-aarch64-apple-darwin.tar.gz"
+url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/405849885"
+
+[tools.git-cliff."platforms.macos-x64"]
+checksum = "sha256:6e60ae390d375cecb9d8008c49f0e724a8dfe40390b532ef5501e421d2cc8acb"
+url = "https://github.com/orhun/git-cliff/releases/download/v2.13.1/git-cliff-2.13.1-x86_64-apple-darwin.tar.gz"
+url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/405850193"
+
+[tools.git-cliff."platforms.windows-x64"]
+checksum = "sha256:3ae3a5549e85c7ad5b20192ebcfee4371269deca51255f6f2f2e051c6541f5ca"
+url = "https://github.com/orhun/git-cliff/releases/download/v2.13.1/git-cliff-2.13.1-x86_64-pc-windows-msvc.zip"
+url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/405851866"
+
+[[tools.jactionlint]]
+version = "2.0.2"
+backend = "github:jdx/jactionlint"
+specifiers = ["latest"]
+
+[tools.jactionlint."platforms.linux-arm64"]
+checksum = "sha256:978a9f32cc4ed1d81b94563fc49643b8b3a48dcba4d1ea089d9ba05f7e17e7a7"
+url = "https://github.com/jdx/jactionlint/releases/download/v2.0.2/jactionlint_2.0.2_linux_arm64.tar.gz"
+url_api = "https://api.github.com/repos/jdx/jactionlint/releases/assets/626020784"
+provenance = "github-attestations"
+
+[tools.jactionlint."platforms.linux-arm64-musl"]
+checksum = "sha256:978a9f32cc4ed1d81b94563fc49643b8b3a48dcba4d1ea089d9ba05f7e17e7a7"
+url = "https://github.com/jdx/jactionlint/releases/download/v2.0.2/jactionlint_2.0.2_linux_arm64.tar.gz"
+url_api = "https://api.github.com/repos/jdx/jactionlint/releases/assets/626020784"
+provenance = "github-attestations"
+
+[tools.jactionlint."platforms.linux-x64"]
+checksum = "sha256:026bce6d0ef196f5b22bf43acb1348d47c5d0a5ae61d6ec3bdba1229a823161b"
+url = "https://github.com/jdx/jactionlint/releases/download/v2.0.2/jactionlint_2.0.2_linux_amd64.tar.gz"
+url_api = "https://api.github.com/repos/jdx/jactionlint/releases/assets/626020780"
+provenance = "github-attestations"
+
+[tools.jactionlint."platforms.linux-x64-musl"]
+checksum = "sha256:026bce6d0ef196f5b22bf43acb1348d47c5d0a5ae61d6ec3bdba1229a823161b"
+url = "https://github.com/jdx/jactionlint/releases/download/v2.0.2/jactionlint_2.0.2_linux_amd64.tar.gz"
+url_api = "https://api.github.com/repos/jdx/jactionlint/releases/assets/626020780"
+provenance = "github-attestations"
+
+[tools.jactionlint."platforms.macos-arm64"]
+checksum = "sha256:1ad210bd21f4c70a81e0bffecc6d223daca8dd13e57fa6899787064f8b724c7c"
+url = "https://github.com/jdx/jactionlint/releases/download/v2.0.2/jactionlint_2.0.2_darwin_arm64.tar.gz"
+url_api = "https://api.github.com/repos/jdx/jactionlint/releases/assets/626020734"
+provenance = "github-attestations"
+
+[tools.jactionlint."platforms.macos-x64"]
+checksum = "sha256:03ccb52f3bf3c6b1b6358689a4d31e5f05d558b32c0b8edaeac7c452abe7fff4"
+url = "https://github.com/jdx/jactionlint/releases/download/v2.0.2/jactionlint_2.0.2_darwin_amd64.tar.gz"
+url_api = "https://api.github.com/repos/jdx/jactionlint/releases/assets/626020732"
+provenance = "github-attestations"
+
+[tools.jactionlint."platforms.windows-x64"]
+checksum = "sha256:988403508761b96fa506920b7db420e6e738247aade084f9b928f452340c8f8f"
+url = "https://github.com/jdx/jactionlint/releases/download/v2.0.2/jactionlint_2.0.2_windows_amd64.zip"
+url_api = "https://api.github.com/repos/jdx/jactionlint/releases/assets/626020828"
+provenance = "github-attestations"
+
+[[tools.mr-boxington]]
+version = "1.23.0"
+backend = "packslip:github.com/jdx/mr-boxington"
+specifiers = ["latest"]
+
+[tools.mr-boxington."platforms.linux-arm64"]
+checksum = "sha256:7278068e1aa0c2acc9be675eae07584201c4bcb67f2b05b9952dc05979f3ddeb"
+url = "https://github.com/jdx/mr-boxington/releases/download/v1.23.0/mbx-aarch64-unknown-linux-gnu.tar.gz"
+signer = "sigstore-oidc:https://github.com/jdx/mr-boxington/.github/workflows/release.yml"
+repository_ids = { repository = "1340721957" }
+
+[tools.mr-boxington."platforms.linux-arm64-musl"]
+checksum = "sha256:2f4b304445843cf2d9626ce68a7d7923cc31f2ac924d26632dd6702c71f6df04"
+url = "https://github.com/jdx/mr-boxington/releases/download/v1.23.0/mbx-aarch64-unknown-linux-musl.tar.gz"
+signer = "sigstore-oidc:https://github.com/jdx/mr-boxington/.github/workflows/release.yml"
+repository_ids = { repository = "1340721957" }
+
+[tools.mr-boxington."platforms.linux-x64"]
+checksum = "sha256:417766e3286c9d669ebf9415f82a78114ac599a4644fda36223258090953d43f"
+url = "https://github.com/jdx/mr-boxington/releases/download/v1.23.0/mbx-x86_64-unknown-linux-gnu.tar.gz"
+signer = "sigstore-oidc:https://github.com/jdx/mr-boxington/.github/workflows/release.yml"
+repository_ids = { repository = "1340721957" }
+
+[tools.mr-boxington."platforms.linux-x64-musl"]
+checksum = "sha256:f50a708e7e3e67b054596729c7035b61bc872e1fce869d8101f45f8ab355f296"
+url = "https://github.com/jdx/mr-boxington/releases/download/v1.23.0/mbx-x86_64-unknown-linux-musl.tar.gz"
+signer = "sigstore-oidc:https://github.com/jdx/mr-boxington/.github/workflows/release.yml"
+repository_ids = { repository = "1340721957" }
+
+[tools.mr-boxington."platforms.macos-arm64"]
+checksum = "sha256:e836ef3ef83b15f2fce52a1a9ea2a82ddd8d2b2c8e107152fdc28098c8b41c60"
+url = "https://github.com/jdx/mr-boxington/releases/download/v1.23.0/mbx-aarch64-apple-darwin.tar.gz"
+signer = "sigstore-oidc:https://github.com/jdx/mr-boxington/.github/workflows/release.yml"
+repository_ids = { repository = "1340721957" }
+
+[tools.mr-boxington."platforms.windows-x64"]
+checksum = "sha256:ecd9a657cacd3e179f91a0a04ef32c458740365cd82f5a29734f8a95bed80710"
+url = "https://github.com/jdx/mr-boxington/releases/download/v1.23.0/mbx-x86_64-pc-windows-msvc.zip"
+signer = "sigstore-oidc:https://github.com/jdx/mr-boxington/.github/workflows/release.yml"
+repository_ids = { repository = "1340721957" }
+
+[[tools.release-plz]]
+version = "0.3.160"
+backend = "aqua:release-plz/release-plz"
+specifiers = ["latest"]
+
+[tools.release-plz."platforms.linux-arm64"]
+checksum = "sha256:38a64d9fd84083f352e29b628de7506eb0f3b6ca99b8a2305bd1e0fe747be754"
+url = "https://github.com/release-plz/release-plz/releases/download/release-plz-v0.3.160/release-plz-aarch64-unknown-linux-gnu.tar.gz"
+url_api = "https://api.github.com/repos/release-plz/release-plz/releases/assets/476457611"
+
+[tools.release-plz."platforms.linux-arm64-musl"]
+checksum = "sha256:43022dc9192f6da8d7f1e9157fc492a8339502b29623432b172f5353b0a4283a"
+url = "https://github.com/release-plz/release-plz/releases/download/release-plz-v0.3.160/release-plz-aarch64-unknown-linux-musl.tar.gz"
+url_api = "https://api.github.com/repos/release-plz/release-plz/releases/assets/476456802"
+
+[tools.release-plz."platforms.linux-x64"]
+checksum = "sha256:2263c4f95eac1513da96a114a77fde20ea038742a8c8050f7514b8f93b828646"
+url = "https://github.com/release-plz/release-plz/releases/download/release-plz-v0.3.160/release-plz-x86_64-unknown-linux-gnu.tar.gz"
+url_api = "https://api.github.com/repos/release-plz/release-plz/releases/assets/476455741"
+
+[tools.release-plz."platforms.linux-x64-musl"]
+checksum = "sha256:47a7ced8ce2870b767f47232adbfd5c561784af7cd0dbe1a83456977fe786d4a"
+url = "https://github.com/release-plz/release-plz/releases/download/release-plz-v0.3.160/release-plz-x86_64-unknown-linux-musl.tar.gz"
+url_api = "https://api.github.com/repos/release-plz/release-plz/releases/assets/476456450"
+
+[tools.release-plz."platforms.macos-arm64"]
+checksum = "sha256:4ed9c58e2deac929154236580b7228c9ce00c7af4c6a9010f81cec3a3d012f4d"
+url = "https://github.com/release-plz/release-plz/releases/download/release-plz-v0.3.160/release-plz-aarch64-apple-darwin.tar.gz"
+url_api = "https://api.github.com/repos/release-plz/release-plz/releases/assets/476455697"
+
+[tools.release-plz."platforms.windows-x64"]
+checksum = "sha256:febcc0361cdfa557b30def8edf5d49aecc628b101727bbae29140950c4adb92b"
+url = "https://github.com/release-plz/release-plz/releases/download/release-plz-v0.3.160/release-plz-x86_64-pc-windows-msvc.tar.gz"
+url_api = "https://api.github.com/repos/release-plz/release-plz/releases/assets/476459873"
+
+[[tools.rust]]
+version = "1.88.0"
+backend = "core:rust"
+specifiers = ["1.88"]
+
+[tools.rust.options]
+components = "clippy,rustfmt"
+
+[[tools.shellcheck]]
+version = "0.11.0"
+backend = "aqua:koalaman/shellcheck"
+specifiers = ["latest"]
+
+[tools.shellcheck."platforms.linux-arm64"]
+checksum = "sha256:12b331c1d2db6b9eb13cfca64306b1b157a86eb69db83023e261eaa7e7c14588"
+url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.aarch64.tar.xz"
+url_api = "https://api.github.com/repos/koalaman/shellcheck/releases/assets/279056934"
+
+[tools.shellcheck."platforms.linux-arm64-musl"]
+checksum = "sha256:12b331c1d2db6b9eb13cfca64306b1b157a86eb69db83023e261eaa7e7c14588"
+url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.aarch64.tar.xz"
+url_api = "https://api.github.com/repos/koalaman/shellcheck/releases/assets/279056934"
+
+[tools.shellcheck."platforms.linux-x64"]
+checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198"
+url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz"
+url_api = "https://api.github.com/repos/koalaman/shellcheck/releases/assets/279056942"
+
+[tools.shellcheck."platforms.linux-x64-musl"]
+checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198"
+url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz"
+url_api = "https://api.github.com/repos/koalaman/shellcheck/releases/assets/279056942"
+
+[tools.shellcheck."platforms.macos-arm64"]
+checksum = "sha256:56affdd8de5527894dca6dc3d7e0a99a873b0f004d7aabc30ae407d3f48b0a79"
+url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.aarch64.tar.xz"
+url_api = "https://api.github.com/repos/koalaman/shellcheck/releases/assets/279056932"
+
+[tools.shellcheck."platforms.macos-x64"]
+checksum = "sha256:3c89db4edcab7cf1c27bff178882e0f6f27f7afdf54e859fa041fca10febe4c6"
+url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.x86_64.tar.xz"
+url_api = "https://api.github.com/repos/koalaman/shellcheck/releases/assets/279056930"
+
+[tools.shellcheck."platforms.windows-x64"]
+checksum = "sha256:8a4e35ab0b331c85d73567b12f2a444df187f483e5079ceffa6bda1faa2e740e"
+url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.zip"
+url_api = "https://api.github.com/repos/koalaman/shellcheck/releases/assets/279056944"
diff --git a/mise.toml b/mise.toml
new file mode 100644
index 0000000..6f807ef
--- /dev/null
+++ b/mise.toml
@@ -0,0 +1,92 @@
+[tools]
+gh = "latest"
+git-cliff = "latest"
+jactionlint = "latest"
+mr-boxington = "latest"
+release-plz = "latest"
+shellcheck = "latest"
+rust = { version = "1.88", components = ["clippy", "rustfmt"], mr_boxington = true } # the MSRV
+
+[tasks.build]
+description = "Build project"
+run = "cargo build"
+
+[tasks.test]
+description = "Run tests"
+run = "cargo test"
+
+[tasks.format]
+description = "Fix formatting issues"
+run = "cargo fmt"
+
+[tasks.lint]
+description = "Fix linting issues"
+run = "cargo clippy --all-targets --fix --allow-dirty"
+
+[tasks.check]
+description = "Check formatting, linting, and tests"
+depends = ["check:toolchain", "check:workflows"]
+run = ["cargo fmt --check", "cargo clippy --all-targets", "cargo test"]
+
+[tasks."check:toolchain"]
+hide = true
+description = "Fail if the pinned toolchain has drifted from rust-version in Cargo.toml"
+run = 'grep -q "^rust-version = \"$(rustc -V | cut -d" " -f2 | cut -d. -f1,2)\"" Cargo.toml'
+
+[tasks."check:workflows"]
+hide = true
+description = "Check GitHub Actions workflows"
+run = "jactionlint"
+
+[tasks."example:build"]
+description = "Build example project"
+depends = ["example:copy-env"]
+dir = "examples/helloworld"
+run = "cargo build"
+
+[tasks."example:format"]
+description = "Fix formatting issues in example"
+dir = "examples/helloworld"
+run = "cargo fmt"
+
+[tasks."example:lint"]
+description = "Fix linting issues in example"
+depends = ["example:copy-env"]
+dir = "examples/helloworld"
+run = "cargo clippy --all-targets --fix --allow-dirty"
+
+[tasks."example:check"]
+description = "Check formatting and linting in example"
+depends = ["example:copy-env"]
+dir = "examples/helloworld"
+run = ["cargo fmt --check", "cargo clippy --all-targets"]
+
+[tasks."example:copy-env"]
+hide = true
+description = "Ensure .env is available at compile time"
+dir = "examples/helloworld"
+run = "test -f .env || cp .env.example .env"
+
+[tasks."release:prepare"]
+description = "Update CHANGELOG.md and Cargo.toml to the next version"
+shell = "bash -c"
+run = [
+ # Ignore commits off HEAD's first-parent chain (branch and upstream commits)
+ "comm -23 <(git rev-list HEAD | sort) <(git rev-list --first-parent HEAD | sort) > .cliffignore",
+ "git cliff --bump -o CHANGELOG.md",
+ 'version=$(git cliff --bumped-version) && release-plz set-version "${version#v}"',
+]
+
+[tasks."release:notes"]
+hide = true
+description = "Print a version's changelog section"
+usage = 'arg "" help="Version, without a leading v"'
+quiet = true
+run = '''
+awk -v heading="## $usage_version" '
+ $0 == heading {in_section=1; next}
+ /^## / {in_section=0}
+ in_section {print; if (NF) found=1}
+ END {if (!found) {print "CHANGELOG.md has no " heading " section" > "/dev/stderr"; exit 1}}
+' CHANGELOG.md
+'''
diff --git a/package.json b/package.json
deleted file mode 100644
index f8e502f..0000000
--- a/package.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "name": "@aptabase/tauri",
- "version": "0.6.0",
- "private": false,
- "type": "module",
- "description": "Tauri Plugin for Aptabase: Open Source, Privacy-First and Simple Analytics for Mobile, Desktop and Web Apps",
- "author": "Guilherme Oenning",
- "browser": "webview-dist/index.js",
- "main": "webview-dist/index.js",
- "types": "webview-dist/index.d.ts",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/aptabase/tauri-plugin-aptabase.git"
- },
- "bugs": {
- "url": "https://github.com/aptabase/tauri-plugin-aptabase/issues"
- },
- "homepage": "https://github.com/aptabase/tauri-plugin-aptabase",
- "scripts": {
- "build": "rollup -c ./webview-src/rollup.config.js",
- "watch": "rollup -c ./webview-src/rollup.config.js -w",
- "prepublishOnly": "npm run build",
- "pretest": "npm run build"
- },
- "files": [
- "README.md",
- "LICENSE",
- "webview-dist",
- "package.json"
- ],
- "devDependencies": {
- "@rollup/plugin-node-resolve": "^16.0.3",
- "@rollup/plugin-typescript": "^12.3.0",
- "@rollup/plugin-terser": "^1.0.0",
- "rollup": "^4.57.1",
- "typescript": "^5.9.3"
- },
- "dependencies": {
- "@tauri-apps/api": "^2.10.1",
- "tslib": "^2.8.1"
- }
-}
diff --git a/permissions/autogenerated/commands/track_event.toml b/permissions/autogenerated/commands/track_event.toml
deleted file mode 100644
index 02d667d..0000000
--- a/permissions/autogenerated/commands/track_event.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-# Automatically generated - DO NOT EDIT!
-
-"$schema" = "../../schemas/schema.json"
-
-[[permission]]
-identifier = "allow-track-event"
-description = "Enables the track_event command without any pre-configured scope."
-commands.allow = ["track_event"]
-
-[[permission]]
-identifier = "deny-track-event"
-description = "Denies the track_event command without any pre-configured scope."
-commands.deny = ["track_event"]
diff --git a/permissions/autogenerated/reference.md b/permissions/autogenerated/reference.md
deleted file mode 100644
index 652ec58..0000000
--- a/permissions/autogenerated/reference.md
+++ /dev/null
@@ -1,35 +0,0 @@
-## Permission Table
-
-
-
-Identifier
-Description
-
-
-
-
-
-
-`aptabase:allow-track-event`
-
-
-
-
-Enables the track_event command without any pre-configured scope.
-
-
-
-
-
-
-
-`aptabase:deny-track-event`
-
-
-
-
-Denies the track_event command without any pre-configured scope.
-
-
-
-
diff --git a/permissions/schemas/schema.json b/permissions/schemas/schema.json
deleted file mode 100644
index 4c0ac2b..0000000
--- a/permissions/schemas/schema.json
+++ /dev/null
@@ -1,312 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "PermissionFile",
- "description": "Permission file that can define a default permission, a set of permissions or a list of inlined permissions.",
- "type": "object",
- "properties": {
- "default": {
- "description": "The default permission set for the plugin",
- "anyOf": [
- {
- "$ref": "#/definitions/DefaultPermission"
- },
- {
- "type": "null"
- }
- ]
- },
- "set": {
- "description": "A list of permissions sets defined",
- "type": "array",
- "items": {
- "$ref": "#/definitions/PermissionSet"
- }
- },
- "permission": {
- "description": "A list of inlined permissions",
- "default": [],
- "type": "array",
- "items": {
- "$ref": "#/definitions/Permission"
- }
- }
- },
- "definitions": {
- "DefaultPermission": {
- "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
- "type": "object",
- "required": [
- "permissions"
- ],
- "properties": {
- "version": {
- "description": "The version of the permission.",
- "type": [
- "integer",
- "null"
- ],
- "format": "uint64",
- "minimum": 1.0
- },
- "description": {
- "description": "Human-readable description of what the permission does. Tauri convention is to use `` headings in markdown content for Tauri documentation generation purposes.",
- "type": [
- "string",
- "null"
- ]
- },
- "permissions": {
- "description": "All permissions this set contains.",
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
- "PermissionSet": {
- "description": "A set of direct permissions grouped together under a new name.",
- "type": "object",
- "required": [
- "description",
- "identifier",
- "permissions"
- ],
- "properties": {
- "identifier": {
- "description": "A unique identifier for the permission.",
- "type": "string"
- },
- "description": {
- "description": "Human-readable description of what the permission does.",
- "type": "string"
- },
- "permissions": {
- "description": "All permissions this set contains.",
- "type": "array",
- "items": {
- "$ref": "#/definitions/PermissionKind"
- }
- }
- }
- },
- "Permission": {
- "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.",
- "type": "object",
- "required": [
- "identifier"
- ],
- "properties": {
- "version": {
- "description": "The version of the permission.",
- "type": [
- "integer",
- "null"
- ],
- "format": "uint64",
- "minimum": 1.0
- },
- "identifier": {
- "description": "A unique identifier for the permission.",
- "type": "string"
- },
- "description": {
- "description": "Human-readable description of what the permission does. Tauri internal convention is to use `` headings in markdown content for Tauri documentation generation purposes.",
- "type": [
- "string",
- "null"
- ]
- },
- "commands": {
- "description": "Allowed or denied commands when using this permission.",
- "default": {
- "allow": [],
- "deny": []
- },
- "allOf": [
- {
- "$ref": "#/definitions/Commands"
- }
- ]
- },
- "scope": {
- "description": "Allowed or denied scoped when using this permission.",
- "allOf": [
- {
- "$ref": "#/definitions/Scopes"
- }
- ]
- },
- "platforms": {
- "description": "Target platforms this permission applies. By default all platforms are affected by this permission.",
- "type": [
- "array",
- "null"
- ],
- "items": {
- "$ref": "#/definitions/Target"
- }
- }
- }
- },
- "Commands": {
- "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.",
- "type": "object",
- "properties": {
- "allow": {
- "description": "Allowed command.",
- "default": [],
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "deny": {
- "description": "Denied command, which takes priority.",
- "default": [],
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
- "Scopes": {
- "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
- "type": "object",
- "properties": {
- "allow": {
- "description": "Data that defines what is allowed by the scope.",
- "type": [
- "array",
- "null"
- ],
- "items": {
- "$ref": "#/definitions/Value"
- }
- },
- "deny": {
- "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.",
- "type": [
- "array",
- "null"
- ],
- "items": {
- "$ref": "#/definitions/Value"
- }
- }
- }
- },
- "Value": {
- "description": "All supported ACL values.",
- "anyOf": [
- {
- "description": "Represents a null JSON value.",
- "type": "null"
- },
- {
- "description": "Represents a [`bool`].",
- "type": "boolean"
- },
- {
- "description": "Represents a valid ACL [`Number`].",
- "allOf": [
- {
- "$ref": "#/definitions/Number"
- }
- ]
- },
- {
- "description": "Represents a [`String`].",
- "type": "string"
- },
- {
- "description": "Represents a list of other [`Value`]s.",
- "type": "array",
- "items": {
- "$ref": "#/definitions/Value"
- }
- },
- {
- "description": "Represents a map of [`String`] keys to [`Value`]s.",
- "type": "object",
- "additionalProperties": {
- "$ref": "#/definitions/Value"
- }
- }
- ]
- },
- "Number": {
- "description": "A valid ACL number.",
- "anyOf": [
- {
- "description": "Represents an [`i64`].",
- "type": "integer",
- "format": "int64"
- },
- {
- "description": "Represents a [`f64`].",
- "type": "number",
- "format": "double"
- }
- ]
- },
- "Target": {
- "description": "Platform target.",
- "oneOf": [
- {
- "description": "MacOS.",
- "type": "string",
- "enum": [
- "macOS"
- ]
- },
- {
- "description": "Windows.",
- "type": "string",
- "enum": [
- "windows"
- ]
- },
- {
- "description": "Linux.",
- "type": "string",
- "enum": [
- "linux"
- ]
- },
- {
- "description": "Android.",
- "type": "string",
- "enum": [
- "android"
- ]
- },
- {
- "description": "iOS.",
- "type": "string",
- "enum": [
- "iOS"
- ]
- }
- ]
- },
- "PermissionKind": {
- "type": "string",
- "oneOf": [
- {
- "description": "Enables the track_event command without any pre-configured scope.",
- "type": "string",
- "const": "allow-track-event",
- "markdownDescription": "Enables the track_event command without any pre-configured scope."
- },
- {
- "description": "Denies the track_event command without any pre-configured scope.",
- "type": "string",
- "const": "deny-track-event",
- "markdownDescription": "Denies the track_event command without any pre-configured scope."
- }
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/release-plz.toml b/release-plz.toml
new file mode 100644
index 0000000..e7cb105
--- /dev/null
+++ b/release-plz.toml
@@ -0,0 +1,8 @@
+[workspace]
+allow_dirty = true
+changelog_update = false
+git_release_name = "{{ version }}"
+pr_name = "chore(release): Release {{ version }}"
+pr_branch_prefix = "release/"
+pr_labels = ["chore"]
+release_always = false
diff --git a/src/builder_ext.rs b/src/builder_ext.rs
new file mode 100644
index 0000000..0acc377
--- /dev/null
+++ b/src/builder_ext.rs
@@ -0,0 +1,36 @@
+// Fork-only additions to `Builder`, kept separate to minimise the diff against
+// upstream's `lib.rs`.
+
+use serde_json::json;
+
+use crate::Builder;
+
+impl Builder {
+ /// Sets the initial session ID.
+ pub fn with_session_id(mut self, session_id: impl Into) -> Self {
+ self.session_id = Some(session_id.into());
+ self
+ }
+
+ /// Sets whether polling should be enabled.
+ pub fn with_polling(mut self, enable: bool) -> Self {
+ self.enable_polling = enable;
+ self
+ }
+
+ /// Enables the default panic hook.
+ pub fn with_default_panic_hook(self) -> Self {
+ self.with_panic_hook(Box::new(|client, info, message| {
+ let location = info
+ .location()
+ .map(|loc| format!("{}:{}:{}", loc.file(), loc.line(), loc.column()))
+ .unwrap_or_default();
+ let _ = client.track_event(
+ "panic",
+ Some(json!({
+ "info": format!("{} ({})", message, location),
+ })),
+ );
+ }))
+ }
+}
diff --git a/src/client.rs b/src/client.rs
index d1cb149..cfee221 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,3 +1,5 @@
+pub(crate) mod session;
+
use rand::RngExt;
use serde_json::{json, Value};
use std::time::{SystemTime, UNIX_EPOCH};
@@ -56,7 +58,7 @@ pub struct AptabaseClient {
impl AptabaseClient {
/// Creates a new Aptabase client.
- pub fn new(config: &Config, app_version: String) -> Self {
+ pub(crate) fn new(config: &Config, app_version: String) -> Self {
let sys_info = sys::get_info();
let is_enabled = !config.app_key.is_empty();
@@ -75,7 +77,7 @@ impl AptabaseClient {
pub(crate) fn start_polling(&self, interval: Duration) {
let dispatcher = self.dispatcher.clone();
- tauri::async_runtime::spawn(async move {
+ tokio::spawn(async move {
loop {
tokio::time::sleep(interval).await;
dispatcher.flush().await;
@@ -121,8 +123,6 @@ impl AptabaseClient {
"osName": self.sys_info.os_name,
"osVersion": self.sys_info.os_version,
"locale": self.sys_info.locale,
- "engineName": self.sys_info.engine_name,
- "engineVersion": self.sys_info.engine_version,
"appVersion": self.app_version,
"sdkVersion": concat!(env!("CARGO_PKG_NAME"), "@", env!("CARGO_PKG_VERSION"))
},
@@ -140,7 +140,7 @@ impl AptabaseClient {
}
/// Flushes the event queue, blocking the current thread.
- pub fn flush_blocking(&self) {
+ pub(crate) fn flush_blocking(&self) {
futures::executor::block_on(async {
self.flush().await;
});
diff --git a/src/client/session.rs b/src/client/session.rs
new file mode 100644
index 0000000..f2f2a0c
--- /dev/null
+++ b/src/client/session.rs
@@ -0,0 +1,71 @@
+// Fork-only session ID handling, kept separate to minimise the diff against
+// upstream's `client.rs`. This is a child module of `client`, so it can reach
+// the private session state that upstream's `AptabaseClient` keeps to itself.
+
+use super::AptabaseClient;
+
+/// Generates a new session ID.
+pub fn new_session_id() -> String {
+ super::new_session_id()
+}
+
+impl AptabaseClient {
+ /// Replaces the generated session ID with a caller-supplied one, before the
+ /// client is shared. An absent or empty ID leaves the generated one in
+ /// place. Timeout rotation is unaffected: the SDK does not persist session
+ /// IDs, so a supplied ID starts its `SESSION_TIMEOUT` window at construction.
+ pub(crate) fn seed_session_id(&self, id: Option) {
+ let Some(id) = id.filter(|id| !id.is_empty()) else {
+ return;
+ };
+
+ let mut session = self.session.lock().expect("could not lock session");
+ session.id = id;
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::Builder;
+
+ #[test]
+ fn new_session_id_is_not_empty() {
+ // Act
+ let session_id = new_session_id();
+
+ // Assert
+ assert!(!session_id.is_empty());
+ }
+
+ #[test]
+ fn builder_uses_supplied_session_id() {
+ // Act
+ let client = Builder::new("A-DEV-123", "test")
+ .with_session_id("persisted-session")
+ .build();
+
+ // Assert
+ assert_eq!(client.eval_session_id(), "persisted-session");
+ }
+
+ #[test]
+ fn builder_generates_session_id_when_none_supplied() {
+ // Act
+ let client = Builder::new("A-DEV-123", "test").build();
+
+ // Assert
+ assert!(!client.eval_session_id().is_empty());
+ }
+
+ #[test]
+ fn builder_treats_empty_session_id_as_absent() {
+ // Act
+ let client = Builder::new("A-DEV-123", "test")
+ .with_session_id("")
+ .build();
+
+ // Assert
+ assert!(!client.eval_session_id().is_empty());
+ }
+}
diff --git a/src/commands.rs b/src/commands.rs
deleted file mode 100644
index 21839a9..0000000
--- a/src/commands.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use serde_json::Value;
-use std::sync::Arc;
-use tauri::{command, State};
-
-use crate::client::AptabaseClient;
-
-#[command]
-pub fn track_event(
- client: State<'_, Arc>,
- name: &str,
- props: Option,
-) -> Result<(), String> {
- client.track_event(name, props)
-}
diff --git a/src/dispatcher.rs b/src/dispatcher.rs
index b4885a4..bc49e79 100644
--- a/src/dispatcher.rs
+++ b/src/dispatcher.rs
@@ -30,10 +30,7 @@ impl EventDispatcher {
headers.insert("App-Key", app_key_header);
headers.insert("Content-Type", HeaderValue::from_static("application/json"));
- let user_agent = format!(
- "{}/{} {}/{} {}",
- sys.os_name, sys.os_version, sys.engine_name, sys.engine_version, sys.locale
- );
+ let user_agent = format!("{}/{} {}", sys.os_name, sys.os_version, sys.locale);
let http_client = reqwest::Client::builder()
.timeout(HTTP_REQUEST_TIMEOUT)
.default_headers(headers)
diff --git a/src/lib.rs b/src/lib.rs
index 824a794..8e34d33 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,18 +1,13 @@
+mod builder_ext;
mod client;
-mod commands;
mod config;
mod dispatcher;
mod sys;
use std::{panic::PanicHookInfo, sync::Arc, time::Duration};
-use client::AptabaseClient;
+pub use client::{session::new_session_id, AptabaseClient};
use config::Config;
-use serde_json::Value;
-use tauri::{
- plugin::{self, TauriPlugin},
- App, AppHandle, Manager, RunEvent, Runtime, Window,
-};
#[derive(Default, Debug, Clone)]
pub struct InitOptions {
@@ -20,9 +15,12 @@ pub struct InitOptions {
pub flush_interval: Option,
}
-/// The Aptabase Plugin builder
+/// The Aptabase client builder
pub struct Builder {
app_key: String,
+ app_version: String,
+ session_id: Option,
+ enable_polling: bool,
panic_hook: Option,
options: InitOptions,
}
@@ -43,9 +41,12 @@ fn get_panic_message(info: &PanicHookInfo) -> String {
impl Builder {
/// Creates a new builder.
- pub fn new(app_key: &str) -> Self {
+ pub fn new(app_key: &str, app_version: &str) -> Self {
Self {
app_key: app_key.into(),
+ app_version: app_version.into(),
+ session_id: None,
+ enable_polling: false,
panic_hook: None,
options: Default::default(),
}
@@ -63,82 +64,27 @@ impl Builder {
self
}
- /// Builds and initializes the plugin
- pub fn build(self) -> TauriPlugin {
- plugin::Builder::new("aptabase")
- .invoke_handler(tauri::generate_handler![commands::track_event])
- .setup(|app, _api| {
- let cfg = Config::new(self.app_key, self.options);
- let app_version = app.package_info().version.to_string();
- let client = Arc::new(AptabaseClient::new(&cfg, app_version));
+ /// Builds and initializes the client
+ pub fn build(self) -> Arc {
+ let cfg = Config::new(self.app_key, self.options);
+ let client = Arc::new(AptabaseClient::new(&cfg, self.app_version));
+ client.seed_session_id(self.session_id);
- client.start_polling(cfg.flush_interval);
-
- if let Some(hook) = self.panic_hook {
- let default_panic = std::panic::take_hook();
- let hook_client = client.clone();
- std::panic::set_hook(Box::new(move |info| {
- let msg = get_panic_message(info);
- hook(&hook_client, info, msg);
- hook_client.flush_blocking();
- default_panic(info);
- }));
- }
-
- app.manage(client);
- Ok(())
- })
- .on_event(move |app, event| {
- if let RunEvent::Exit = event {
- let client = app.state::>();
- client.flush_blocking();
- }
- })
- .build()
- }
-}
-
-/// Trait implemented by Tauri handlers
-pub trait EventTracker {
- /// Enqueues an event to be sent to the server.
- fn track_event(&self, name: &str, props: Option) -> Result<(), String>;
-
- /// Flushes the event queue, blocking the current thread.
- fn flush_events_blocking(&self);
-}
-
-impl EventTracker for App {
- fn track_event(&self, name: &str, props: Option) -> Result<(), String> {
- let client = self.state::>();
- client.track_event(name, props)
- }
-
- fn flush_events_blocking(&self) {
- let client = self.state::>();
- client.flush_blocking();
- }
-}
-
-impl EventTracker for AppHandle {
- fn track_event(&self, name: &str, props: Option) -> Result<(), String> {
- let client = self.state::>();
- client.track_event(name, props)
- }
-
- fn flush_events_blocking(&self) {
- let client = self.state::>();
- client.flush_blocking();
- }
-}
+ if self.enable_polling {
+ client.start_polling(cfg.flush_interval);
+ }
-impl EventTracker for Window {
- fn track_event(&self, name: &str, props: Option) -> Result<(), String> {
- let client = self.state::>();
- client.track_event(name, props)
- }
+ if let Some(hook) = self.panic_hook {
+ let default_panic = std::panic::take_hook();
+ let hook_client = client.clone();
+ std::panic::set_hook(Box::new(move |info| {
+ let msg = get_panic_message(info);
+ hook(&hook_client, info, msg);
+ hook_client.flush_blocking();
+ default_panic(info);
+ }));
+ }
- fn flush_events_blocking(&self) {
- let client = self.state::>();
- client.flush_blocking();
+ client
}
}
diff --git a/src/sys.rs b/src/sys.rs
index 369d4d3..bd1a662 100644
--- a/src/sys.rs
+++ b/src/sys.rs
@@ -1,17 +1,3 @@
-use tauri::webview_version;
-
-#[cfg(target_os = "linux")]
-static ENGINE_NAME: &str = "WebKitGTK";
-
-#[cfg(target_os = "android")]
-static ENGINE_NAME: &str = "Android System WebView";
-
-#[cfg(any(target_os = "macos", target_os = "ios"))]
-static ENGINE_NAME: &str = "WebKit";
-
-#[cfg(target_os = "windows")]
-static ENGINE_NAME: &str = "WebView2";
-
#[cfg(debug_assertions)]
static IS_DEBUG: bool = true;
@@ -23,8 +9,6 @@ pub struct SystemProperties {
pub os_name: String,
pub os_version: String,
pub locale: String,
- pub engine_name: String,
- pub engine_version: String,
}
#[cfg(target_os = "linux")]
@@ -39,7 +23,6 @@ fn is_flatpak() -> bool {
pub fn get_info() -> SystemProperties {
let info = os_info::get();
let locale = sys_locale::get_locale().unwrap_or_default();
- let engine_version = webview_version().unwrap_or_default();
let os_name = match info.os_type() {
os_info::Type::Macos => "macOS".to_string(),
@@ -54,7 +37,5 @@ pub fn get_info() -> SystemProperties {
os_name,
os_version: info.version().to_string(),
locale,
- engine_name: ENGINE_NAME.to_string(),
- engine_version,
}
}
diff --git a/tests/delivery.rs b/tests/delivery.rs
new file mode 100644
index 0000000..4539fa8
--- /dev/null
+++ b/tests/delivery.rs
@@ -0,0 +1,281 @@
+// Delivery behaviour, exercised through the public interface against a local
+// stand-in for the Aptabase server. An `SH` App Key sends to whichever host
+// the test supplies.
+
+use std::{net::TcpListener, sync::Arc, time::Duration};
+
+use aptabase_rs::{AptabaseClient, Builder, InitOptions};
+use serde_json::{json, Value};
+use time::{format_description::well_known::Rfc3339, OffsetDateTime};
+use wiremock::{
+ matchers::{method, path},
+ Mock, MockServer, Request, ResponseTemplate,
+};
+
+const SH_APP_KEY: &str = "A-SH-1234567890";
+const APP_VERSION: &str = "1.2.3";
+
+fn client_for(host: &str) -> Arc {
+ Builder::new(SH_APP_KEY, APP_VERSION)
+ .with_options(InitOptions {
+ host: Some(host.to_owned()),
+ flush_interval: None,
+ })
+ .build()
+}
+
+fn events_endpoint(status: u16) -> Mock {
+ Mock::given(method("POST"))
+ .and(path("/api/v0/events"))
+ .respond_with(ResponseTemplate::new(status))
+}
+
+fn batches(requests: &[Request]) -> Vec> {
+ requests
+ .iter()
+ .map(|request| request.body_json().unwrap())
+ .collect()
+}
+
+fn batch_sizes(requests: &[Request]) -> Vec {
+ batches(requests).iter().map(Vec::len).collect()
+}
+
+fn event_names(requests: &[Request]) -> Vec {
+ let mut names: Vec = batches(requests)
+ .into_iter()
+ .flatten()
+ .map(|event| event["eventName"].as_str().unwrap().to_owned())
+ .collect();
+ names.sort();
+ names
+}
+
+fn sorted_keys(value: &Value) -> Vec<&str> {
+ let mut keys: Vec<&str> = value
+ .as_object()
+ .unwrap()
+ .keys()
+ .map(String::as_str)
+ .collect();
+ keys.sort();
+ keys
+}
+
+#[tokio::test]
+async fn flush_sends_events_in_batches_of_25() {
+ // Arrange
+ let server = MockServer::start().await;
+ let delivered = events_endpoint(200).mount_as_scoped(&server).await;
+ let client = client_for(&server.uri());
+ for i in 0..60 {
+ client.track_event(&format!("event_{i}"), None).unwrap();
+ }
+
+ // Act
+ client.flush().await;
+
+ // Assert
+ assert_eq!(
+ batch_sizes(&delivered.received_requests().await),
+ [25, 25, 10]
+ );
+}
+
+#[tokio::test]
+async fn server_error_keeps_events_for_the_next_flush() {
+ // Arrange
+ let server = MockServer::start().await;
+ let failed = events_endpoint(503)
+ .up_to_n_times(1)
+ .mount_as_scoped(&server)
+ .await;
+ let delivered = events_endpoint(200).mount_as_scoped(&server).await;
+ let client = client_for(&server.uri());
+ client.track_event("app_started", None).unwrap();
+ client.track_event("app_exited", None).unwrap();
+
+ // Act
+ client.flush().await;
+ client.flush().await;
+
+ // Assert
+ assert_eq!(
+ event_names(&failed.received_requests().await),
+ ["app_exited", "app_started"]
+ );
+ assert_eq!(
+ event_names(&delivered.received_requests().await),
+ ["app_exited", "app_started"]
+ );
+}
+
+#[tokio::test]
+async fn transport_failure_keeps_events_for_the_next_flush() {
+ // Arrange
+ let addr = TcpListener::bind("127.0.0.1:0")
+ .unwrap()
+ .local_addr()
+ .unwrap();
+ let client = client_for(&format!("http://{addr}"));
+ client.track_event("app_started", None).unwrap();
+
+ // Act
+ // Nothing listens on the port during the first flush
+ client.flush().await;
+ let server = MockServer::builder()
+ .listener(TcpListener::bind(addr).unwrap())
+ .start()
+ .await;
+ let delivered = events_endpoint(200).mount_as_scoped(&server).await;
+ client.flush().await;
+
+ // Assert
+ assert_eq!(
+ event_names(&delivered.received_requests().await),
+ ["app_started"]
+ );
+}
+
+#[tokio::test]
+async fn client_error_drops_events() {
+ // Arrange
+ let server = MockServer::start().await;
+ let rejected = events_endpoint(400)
+ .up_to_n_times(1)
+ .mount_as_scoped(&server)
+ .await;
+ let delivered = events_endpoint(200).mount_as_scoped(&server).await;
+ let client = client_for(&server.uri());
+ client.track_event("app_started", None).unwrap();
+
+ // Act
+ client.flush().await;
+
+ // Assert
+ assert_eq!(
+ event_names(&rejected.received_requests().await),
+ ["app_started"]
+ );
+
+ // Act
+ client.flush().await;
+
+ // Assert
+ assert_eq!(
+ event_names(&delivered.received_requests().await),
+ Vec::::new()
+ );
+}
+
+#[tokio::test]
+async fn events_are_sent_in_aptabase_format() {
+ // Arrange
+ let server = MockServer::start().await;
+ let delivered = events_endpoint(200).mount_as_scoped(&server).await;
+ let client = client_for(&server.uri());
+ let props = json!({ "plan": "pro", "seats": 3 });
+ client
+ .track_event("app_started", Some(props.clone()))
+ .unwrap();
+
+ // Act
+ client.flush().await;
+
+ // Assert
+ let requests = delivered.received_requests().await;
+ let request = &requests[0];
+ assert_eq!(request.headers["App-Key"], SH_APP_KEY);
+ assert_eq!(request.headers["Content-Type"], "application/json");
+
+ let event = &batches(&requests)[0][0];
+ assert_eq!(
+ sorted_keys(event),
+ [
+ "eventName",
+ "props",
+ "sessionId",
+ "systemProps",
+ "timestamp"
+ ]
+ );
+ assert_eq!(event["eventName"], "app_started");
+ assert_eq!(event["props"], props);
+ assert!(!event["sessionId"].as_str().unwrap().is_empty());
+ OffsetDateTime::parse(event["timestamp"].as_str().unwrap(), &Rfc3339).unwrap();
+
+ let system = &event["systemProps"];
+ assert_eq!(
+ sorted_keys(system),
+ [
+ "appVersion",
+ "isDebug",
+ "locale",
+ "osName",
+ "osVersion",
+ "sdkVersion"
+ ]
+ );
+ assert_eq!(system["appVersion"], APP_VERSION);
+ assert_eq!(
+ system["sdkVersion"],
+ concat!("aptabase-rs@", env!("CARGO_PKG_VERSION"))
+ );
+ assert_eq!(system["isDebug"], cfg!(debug_assertions));
+ assert!(system["osName"].is_string());
+ assert!(system["osVersion"].is_string());
+ assert!(system["locale"].is_string());
+}
+
+#[tokio::test]
+async fn invalid_app_key_sends_nothing() {
+ // Arrange
+ let server = MockServer::start().await;
+ let delivered = events_endpoint(200).mount_as_scoped(&server).await;
+ let client = Builder::new("A-XX-1234567890", APP_VERSION)
+ .with_options(InitOptions {
+ host: Some(server.uri()),
+ flush_interval: None,
+ })
+ .build();
+ client.track_event("app_started", None).unwrap();
+
+ // Act
+ client.flush().await;
+
+ // Assert
+ assert_eq!(
+ event_names(&delivered.received_requests().await),
+ Vec::::new()
+ );
+}
+
+#[tokio::test]
+async fn polling_flushes_without_a_manual_flush() {
+ // Arrange
+ let server = MockServer::start().await;
+ let delivered = events_endpoint(200).mount_as_scoped(&server).await;
+ let client = Builder::new(SH_APP_KEY, APP_VERSION)
+ .with_polling(true)
+ .with_options(InitOptions {
+ host: Some(server.uri()),
+ flush_interval: Some(Duration::from_millis(50)),
+ })
+ .build();
+
+ // Act
+ client.track_event("app_started", None).unwrap();
+
+ // Assert
+ let arrived = tokio::time::timeout(Duration::from_secs(5), async {
+ while delivered.received_requests().await.is_empty() {
+ tokio::time::sleep(Duration::from_millis(25)).await;
+ }
+ })
+ .await;
+ assert!(arrived.is_ok(), "no flush within 5s");
+ assert_eq!(
+ event_names(&delivered.received_requests().await),
+ ["app_started"]
+ );
+}
diff --git a/webview-dist/index.d.ts b/webview-dist/index.d.ts
deleted file mode 100644
index dab0a4e..0000000
--- a/webview-dist/index.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-type Props = {
- [key: string]: string | number;
-};
-export declare function trackEvent(name: string, props?: Props): Promise;
-export {};
diff --git a/webview-dist/index.js b/webview-dist/index.js
deleted file mode 100644
index b957d7f..0000000
--- a/webview-dist/index.js
+++ /dev/null
@@ -1 +0,0 @@
-function n(n,e,r,t){return new(r||(r=Promise))(function(o,u){function i(n){try{p(t.next(n))}catch(n){u(n)}}function c(n){try{p(t.throw(n))}catch(n){u(n)}}function p(n){var e;n.done?o(n.value):(e=n.value,e instanceof r?e:new r(function(n){n(e)})).then(i,c)}p((t=t.apply(n,e||[])).next())})}function e(e,r){return n(this,void 0,void 0,function*(){yield async function(n,e={},r){return window.__TAURI_INTERNALS__.invoke(n,e,r)}("plugin:aptabase|track_event",{name:e,props:r})})}"function"==typeof SuppressedError&&SuppressedError,"function"==typeof SuppressedError&&SuppressedError;export{e as trackEvent};
diff --git a/webview-src/index.ts b/webview-src/index.ts
deleted file mode 100644
index f98960f..0000000
--- a/webview-src/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { invoke } from '@tauri-apps/api/core'
-
-type Props = {
- [key: string]: string | number;
-};
-
-export async function trackEvent(name: string, props?: Props): Promise {
- await invoke('plugin:aptabase|track_event', { name, props });
-}
diff --git a/webview-src/rollup.config.js b/webview-src/rollup.config.js
deleted file mode 100644
index f3acd47..0000000
--- a/webview-src/rollup.config.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { nodeResolve } from '@rollup/plugin-node-resolve'
-import typescript from '@rollup/plugin-typescript'
-import terser from '@rollup/plugin-terser'
-
-export default {
- input: './webview-src/index.ts',
- output: {
- dir: './webview-dist',
- entryFileNames: '[name].js',
- format: 'es',
- exports: 'auto'
- },
- plugins: [
- nodeResolve(),
- terser(),
- typescript({
- tsconfig: './webview-src/tsconfig.json'
- })
- ]
-}
diff --git a/webview-src/tsconfig.json b/webview-src/tsconfig.json
deleted file mode 100644
index caa184d..0000000
--- a/webview-src/tsconfig.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2015",
- "strict": true,
- "allowJs": true,
- "esModuleInterop": true,
- "moduleResolution": "bundler",
- "declaration": true,
- "declarationDir": "../webview-dist",
- "outDir": "../webview-dist",
- "rootDir": "./"
- },
- "include": ["./index.ts"],
- "exclude": ["./rollup.config.js"]
-}