Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@ All notable changes to this project will be documented in this file.
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).

## [Unreleased]
## [1.3.0] - 2026-10-16

### Fixed

- Use the system proxy settings on macOS and Windows again. Turning off reqwest's default features to add the TLS feature flags (#34) also turned off its `system-proxy`, `http2` and `charset` features; they're back on, and the TLS backend is still chosen with `default-tls`, `rustls-tls` or `native-tls`
- `rust-version` is 1.85.0: reqwest 0.13 and rand 0.10 don't build on 1.81
JavaScript bindings: `@aptabase/tauri` 0.7.0.

### Added

- Error reporting (beta), to the error endpoint (`/api/v0/error`); reports appear on the Errors page of the dashboard
- `ErrorTracker` trait on `App`, `AppHandle` and `Window`: `track_error(&err)` reports any `std::error::Error` with its type name and causes, and `track_error_report(ErrorReport)` reports one described field by field (`ErrorReport::with_fatal` for severity `fatal`)
- `trackError(error, { fatal })` in the JavaScript bindings, with the `aptabase:allow-track-error` permission
- `Builder::with_crash_reporting()`: a panic on the main thread is reported as a fatal `crash` (the app waits up to three seconds for the report before it exits), one in an async task as a `taskException` and one on another thread as `unhandled`; the webview's uncaught errors and unhandled promise rejections are reported too
- Reports are sent right away, one per request, with the same retry rules as the other SDKs: network errors, 408, 429 and 5xx are retried, a 403 (monthly error quota exhausted) and other 4xx are dropped; at most 25 wait for delivery
- Tests for event delivery (batches of 25, what's kept for the next flush and what's dropped, the event format, polling) and for App Key validation, run in CI
- README sections on delivery and on the TLS backend features

### Fixed

- Use the system proxy settings on macOS and Windows again. Turning off reqwest's default features to add the TLS feature flags (#34) also turned off its `system-proxy`, `http2` and `charset` features; they're back on, and the TLS backend is still chosen with `default-tls`, `rustls-tls` or `native-tls`
- `rust-version` is 1.85.0: reqwest 0.13 and rand 0.10 don't build on 1.81
- `flush_events_blocking()`, and the flush after a custom panic hook, panicked with "there is no reactor running" when events were queued and the calling thread was outside Tauri's async runtime (the main thread handling `RunEvent::Exit`, as the README shows); the flush now runs on the runtime

## [1.2.0] - 2026-08-11

### Changed
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-aptabase"
version = "1.2.0"
version = "1.3.0"
license = "MIT"
description = "Tauri Plugin for Aptabase: Open Source, Privacy-First and Simple Analytics for Mobile, Desktop and Web Apps"
authors = ["Guilherme Oenning"]
Expand All @@ -13,7 +13,7 @@ links = "tauri-plugin-aptabase"

[dependencies]
tauri = "2.11.5"
tokio = "1.53.1"
tokio = { version = "1.53.1", features = ["rt", "time", "net"] }
futures = "0.3.31"
serde = "1.0.229"
serde_json = "1.0.151"
Expand All @@ -26,6 +26,7 @@ log = "0.4.27"
sys-locale = "0.3.2"

[dev-dependencies]
tauri = { version = "2.11.5", features = ["test"] }
time = { version = "0.3.41", features = ["parsing"] }

[build-dependencies]
Expand Down
57 changes: 55 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:

```toml
[dependencies]
tauri-plugin-aptabase = "1.0.0"
tauri-plugin-aptabase = "1.3.0"
```

```toml
Expand Down Expand Up @@ -94,6 +94,59 @@ A few important notes:
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

## Error Reporting

> Error reporting is in beta. Reports appear on the `Errors` page of your Aptabase dashboard.

Use `track_error` to report errors you've caught and handled in Rust, through the `tauri_plugin_aptabase::ErrorTracker` trait on `App`, `AppHandle` or `Window`:

```rust
use tauri_plugin_aptabase::ErrorTracker;

if let Err(err) = std::fs::read_to_string("settings.json") {
app.track_error(&err); // severity: error
}
```

The `trackError` function does the same from JavaScript. Add `aptabase:allow-track-error` to your Access Control List first:

```js
import { trackError } from "@aptabase/tauri";

try {
await saveSettings();
} catch (error) {
trackError(error); // severity: error
}
```

For errors your app can't recover from, mark the report as fatal:

```js
trackError(error, { fatal: true }); // severity: fatal
```

```rust
use tauri_plugin_aptabase::{ErrorReport, ErrorTracker};

app.track_error_report(ErrorReport::from_error(&err).with_fatal(true)); // severity: fatal
```

To also report crashes and uncaught errors automatically, enable crash reporting when you register the plugin:

```rust
tauri::Builder::default()
.plugin(tauri_plugin_aptabase::Builder::new("<YOUR_APP_KEY>").with_crash_reporting().build())
```

A few important notes about error reporting:

1. A panic on the main thread ends your app: it's reported as a fatal `crash`, and the app waits up to three seconds for the report to be sent before it exits. A panic in an async command or a task on Tauri's async runtime ends only that task (`taskException`), and one on a thread of your own ends only that thread (`unhandled`): both are reported with severity `error`. A hook set with `with_panic_hook` still runs.
2. With crash reporting on, the webview's uncaught errors (`unhandled`) and unhandled promise rejections (`taskException`) are reported too. This needs the `aptabase:allow-track-error` permission.
3. Each report includes the error type, message, stack trace, severity (`error` or `fatal`) and how it was captured (`handled`, `unhandled`, `taskException` or `crash`). A Rust error is reported with its type name and the errors that caused it; a panic with its location and a backtrace.
4. Errors count against a separate monthly error quota. When it is exhausted, the server rejects new reports until it resets, and the plugin drops them instead of retrying.
5. Crashes that don't go through Rust's panic handler (a segfault or an abort in native code) aren't captured.

## Providing the APTABASE_KEY via .env

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
Expand Down Expand Up @@ -151,7 +204,7 @@ To switch backend, turn off the default features:

```toml
[dependencies]
tauri-plugin-aptabase = { version = "1.2", default-features = false, features = ["native-tls"] }
tauri-plugin-aptabase = { version = "1.3", default-features = false, features = ["native-tls"] }
```

Neither `default-tls` nor `rustls-tls` needs OpenSSL, so you can cross-compile for Android and Linux without it.
Expand Down
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const COMMANDS: &[&str] = &["track_event"];
const COMMANDS: &[&str] = &["track_event", "track_error"];

fn main() {
tauri_plugin::Builder::new(COMMANDS).build();
Expand Down
3 changes: 2 additions & 1 deletion examples/helloworld/src-tauri/capabilities/desktop.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"aptabase:allow-track-event"
"aptabase:allow-track-event",
"aptabase:allow-track-error"
]
}
2 changes: 1 addition & 1 deletion examples/helloworld/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub fn run() {
client.track_event("panic", Some(json!({
"info": format!("{} ({})", msg, location),
})));
})).build())
})).with_crash_reporting().build())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
19 changes: 18 additions & 1 deletion examples/helloworld/src/lib/Greet.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script>
import { invoke } from "@tauri-apps/api/core"
import { trackEvent } from '@aptabase/tauri'
import { trackEvent, trackError } from '@aptabase/tauri'

let name = "";
let greetMsg = ""
Expand All @@ -10,6 +10,19 @@
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
greetMsg = await invoke("greet", { name })
}

function reportError() {
try {
JSON.parse("{ not json")
} catch (error) {
trackError(error)
}
}

function panicInRust() {
// A sync command runs on the main thread: with crash reporting on, the panic is reported as a crash.
invoke("this_will_panic")
}
</script>

<div>
Expand All @@ -20,5 +33,9 @@
</button>
</div>
<p>{greetMsg}</p>
<div class="row">
<button on:click={reportError}>Report an error</button>
<button on:click={panicInRust}>Panic in Rust</button>
</div>
</div>

49 changes: 44 additions & 5 deletions llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ In `src-tauri/Cargo.toml`:

```toml
[dependencies]
tauri-plugin-aptabase = "1.0.0"
tauri-plugin-aptabase = "1.3.0"
```

### 2. Add the JS package (optional, for webview tracking)
Expand All @@ -61,11 +61,11 @@ async fn main() {

### 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`:
Add `aptabase:allow-track-event` to your Tauri capabilities to allow the JS API to send events, and `aptabase:allow-track-error` to report errors. In your `src-tauri/capabilities/*.json`:

```json
{
"permissions": ["aptabase:allow-track-event"]
"permissions": ["aptabase:allow-track-event", "aptabase:allow-track-error"]
}
```

Expand Down Expand Up @@ -125,6 +125,45 @@ trackEvent("screen_view", { name: "Settings" });
trackEvent("purchase", { plan: "pro", price: 9.99 });
```

## Error Reporting (beta)

Reports appear on the `Errors` page of the Aptabase dashboard. Errors count against a separate monthly error quota.

Report a handled error from Rust with the `ErrorTracker` trait (implemented for `App`, `AppHandle`, and `Window`):

```rust
use tauri_plugin_aptabase::{ErrorReport, ErrorTracker};

app.track_error(&err); // any std::error::Error: its type name, message and causes
app.track_error_report(ErrorReport::from_error(&err).with_fatal(true)); // severity: fatal
app.track_error_report(ErrorReport::new("SyncConflict", "two devices edited the same note"));
```

Report a handled error from JavaScript (needs the `aptabase:allow-track-error` permission):

```js
import { trackError } from "@aptabase/tauri";

try {
await saveSettings();
} catch (error) {
trackError(error); // severity: error
// trackError(error, { fatal: true }) for errors the app can't recover from
}
```

Report crashes and uncaught errors automatically:

```rust
tauri::Builder::default()
.plugin(tauri_plugin_aptabase::Builder::new("<YOUR_APP_KEY>").with_crash_reporting().build())
```

- A panic on the main thread is a fatal `crash`; the app waits up to 3 seconds for the report before it exits
- A panic in an async command or a task on Tauri's async runtime is a `taskException`; one on another thread is `unhandled` (both severity `error`)
- The webview's uncaught errors (`unhandled`) and unhandled promise rejections (`taskException`) are reported too, with the `aptabase:allow-track-error` permission
- Reports are sent immediately, one per request; network errors, 408, 429 and 5xx are retried, a 403 (quota exhausted) is dropped

## Configuration

The `Builder` accepts optional `InitOptions`:
Expand Down Expand Up @@ -155,7 +194,7 @@ tauri::Builder::default()
Cargo features choose the TLS backend: `default-tls` (default, rustls), `rustls-tls`, or `native-tls` (OpenSSL on Linux and Android). To switch, turn off the default features:

```toml
tauri-plugin-aptabase = { version = "1.2", default-features = false, features = ["native-tls"] }
tauri-plugin-aptabase = { version = "1.3", default-features = false, features = ["native-tls"] }
```

## Platform Notes
Expand All @@ -164,7 +203,7 @@ tauri-plugin-aptabase = { version = "1.2", default-features = false, features =
- Rust edition 2021, MSRV 1.85
- 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
- `Builder::with_crash_reporting()` reports panics and the webview's uncaught errors; a custom panic hook can still be set via `Builder::with_panic_hook()`

## Cross-Discovery

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@aptabase/tauri",
"version": "0.6.0",
"version": "0.7.0",
"private": false,
"type": "module",
"description": "Tauri Plugin for Aptabase: Open Source, Privacy-First and Simple Analytics for Mobile, Desktop and Web Apps",
Expand Down
13 changes: 13 additions & 0 deletions permissions/autogenerated/commands/track_error.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Automatically generated - DO NOT EDIT!

"$schema" = "../../schemas/schema.json"

[[permission]]
identifier = "allow-track-error"
description = "Enables the track_error command without any pre-configured scope."
commands.allow = ["track_error"]

[[permission]]
identifier = "deny-track-error"
description = "Denies the track_error command without any pre-configured scope."
commands.deny = ["track_error"]
26 changes: 26 additions & 0 deletions permissions/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,32 @@
</tr>


<tr>
<td>

`aptabase:allow-track-error`

</td>
<td>

Enables the track_error command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`aptabase:deny-track-error`

</td>
<td>

Denies the track_error command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

Expand Down
12 changes: 12 additions & 0 deletions permissions/schemas/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,18 @@
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "Enables the track_error command without any pre-configured scope.",
"type": "string",
"const": "allow-track-error",
"markdownDescription": "Enables the track_error command without any pre-configured scope."
},
{
"description": "Denies the track_error command without any pre-configured scope.",
"type": "string",
"const": "deny-track-error",
"markdownDescription": "Denies the track_error command without any pre-configured scope."
},
{
"description": "Enables the track_event command without any pre-configured scope.",
"type": "string",
Expand Down
Loading
Loading