Skip to content

Commit 61452cb

Browse files
authored
Merge pull request #26 from RAprogramm/codex/add-error-handling-for-frontend
Add frontend console logging support
2 parents 1d983dd + 7783452 commit 61452cb

File tree

10 files changed

+316
-21
lines changed

10 files changed

+316
-21
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file.
33

44
## [Unreleased]
55

6+
## [0.4.0] - 2025-09-15
7+
### Added
8+
- Optional `frontend` feature:
9+
- Converts [`AppError`] and [`ErrorResponse`] into `wasm_bindgen::JsValue` for browser contexts.
10+
- Logs structured errors to the browser console via `console.error`.
11+
- `BrowserConsoleError` and `BrowserConsoleExt` API for WASM front-ends.
12+
13+
### Documentation
14+
- Documented browser/WASM support and console logging workflow in the README and crate docs.
15+
616
## [0.3.5] - 2025-09-12
717
### Added
818
- Conversion from `teloxide_core::RequestError` into `AppError` (feature `teloxide`).
@@ -111,4 +121,5 @@ All notable changes to this project will be documented in this file.
111121
[0.3.0]: https://github.com/RAprogramm/masterror/releases/tag/v0.3.0
112122
[0.2.1]: https://github.com/RAprogramm/masterror/releases/tag/v0.2.1
113123
[0.2.0]: https://github.com/RAprogramm/masterror/releases/tag/v0.2.0
124+
[0.4.0]: https://github.com/RAprogramm/masterror/releases/tag/v0.4.0
114125

Cargo.lock

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "masterror"
3-
version = "0.3.5"
3+
version = "0.4.0"
44
rust-version = "1.89"
55
edition = "2024"
66
description = "Application error types and response mapping"
@@ -26,6 +26,7 @@ tokio = ["dep:tokio"]
2626
reqwest = ["dep:reqwest"]
2727
teloxide = ["dep:teloxide-core"]
2828
telegram-webapp-sdk = ["dep:telegram-webapp-sdk"]
29+
frontend = ["dep:wasm-bindgen", "dep:js-sys", "dep:serde-wasm-bindgen"]
2930
turnkey = []
3031

3132
openapi = ["dep:utoipa"]
@@ -58,6 +59,9 @@ tokio = { version = "1", optional = true, features = ["time"] }
5859
reqwest = { version = "0.12", optional = true, default-features = false }
5960
teloxide-core = { version = "0.13", optional = true, default-features = false }
6061
telegram-webapp-sdk = { version = "0.1", optional = true }
62+
wasm-bindgen = { version = "0.2", optional = true }
63+
js-sys = { version = "0.3", optional = true }
64+
serde-wasm-bindgen = { version = "0.6", optional = true }
6165

6266
[dev-dependencies]
6367
serde_json = "1"

README.md

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ Stable categories, conservative HTTP mapping, no `unsafe`.
2222

2323
~~~toml
2424
[dependencies]
25-
masterror = { version = "0.3", default-features = false }
25+
masterror = { version = "0.4", default-features = false }
2626
# or with features:
27-
# masterror = { version = "0.3", features = [
27+
# masterror = { version = "0.4", features = [
2828
# "axum", "actix", "serde_json", "openapi",
2929
# "sqlx", "reqwest", "redis", "validator", "config", "tokio", "teloxide"
3030
# ] }
3131
~~~
3232

33+
*Since v0.4.0: optional `frontend` feature for WASM/browser console logging.*
3334
*Since v0.3.0: stable `AppCode` enum and extended `ErrorResponse` with retry/authentication metadata.*
3435

3536
---
@@ -53,10 +54,10 @@ masterror = { version = "0.3", default-features = false }
5354
~~~toml
5455
[dependencies]
5556
# lean core
56-
masterror = { version = "0.3", default-features = false }
57+
masterror = { version = "0.4", default-features = false }
5758

5859
# with Axum/Actix + JSON + integrations
59-
# masterror = { version = "0.3", features = [
60+
# masterror = { version = "0.4", features = [
6061
# "axum", "actix", "serde_json", "openapi",
6162
# "sqlx", "reqwest", "redis", "validator", "config", "tokio", "teloxide"
6263
# ] }
@@ -160,12 +161,37 @@ async fn payload() -> impl Responder {
160161

161162
~~~toml
162163
[dependencies]
163-
masterror = { version = "0.3", features = ["openapi", "serde_json"] }
164+
masterror = { version = "0.4", features = ["openapi", "serde_json"] }
164165
utoipa = "5"
165166
~~~
166167

167168
</details>
168169

170+
<details>
171+
<summary><b>Browser (WASM)</b></summary>
172+
173+
~~~rust
174+
// features = ["frontend"]
175+
use masterror::{AppError, AppErrorKind};
176+
use masterror::frontend::{BrowserConsoleError, BrowserConsoleExt};
177+
178+
fn report() -> Result<(), BrowserConsoleError> {
179+
let err = AppError::bad_request("missing field");
180+
let payload = err.to_js_value()?;
181+
assert!(payload.is_object());
182+
183+
#[cfg(target_arch = "wasm32")]
184+
err.log_to_browser_console()?;
185+
186+
Ok(())
187+
}
188+
~~~
189+
190+
- On non-WASM targets `log_to_browser_console` returns
191+
`BrowserConsoleError::UnsupportedTarget`.
192+
193+
</details>
194+
169195
<details>
170196
<summary><b>Feature flags</b></summary>
171197

@@ -174,6 +200,7 @@ utoipa = "5"
174200
- `openapi` — utoipa schema
175201
- `serde_json` — JSON details
176202
- `sqlx`, `redis`, `reqwest`, `validator`, `config`, `tokio`, `multipart`, `teloxide`, `telegram-webapp-sdk`
203+
- `frontend` — convert errors into `JsValue` and log via `console.error` (WASM)
177204
- `turnkey` — domain taxonomy and conversions for Turnkey errors
178205

179206
</details>
@@ -201,13 +228,13 @@ utoipa = "5"
201228
Minimal core:
202229

203230
~~~toml
204-
masterror = { version = "0.3", default-features = false }
231+
masterror = { version = "0.4", default-features = false }
205232
~~~
206233

207234
API (Axum + JSON + deps):
208235

209236
~~~toml
210-
masterror = { version = "0.3", features = [
237+
masterror = { version = "0.4", features = [
211238
"axum", "serde_json", "openapi",
212239
"sqlx", "reqwest", "redis", "validator", "config", "tokio"
213240
] }
@@ -216,7 +243,7 @@ masterror = { version = "0.3", features = [
216243
API (Actix + JSON + deps):
217244

218245
~~~toml
219-
masterror = { version = "0.3", features = [
246+
masterror = { version = "0.4", features = [
220247
"actix", "serde_json", "openapi",
221248
"sqlx", "reqwest", "redis", "validator", "config", "tokio"
222249
] }

src/convert.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@
4646
//! ```rust
4747
//! use std::io::{self, ErrorKind};
4848
//!
49-
//! use masterror::{AppError, AppErrorKind};
49+
//! use masterror::{AppError, AppErrorKind, AppResult};
5050
//!
51-
//! fn open() -> Result<(), AppError> {
51+
//! fn open() -> AppResult<()> {
5252
//! let _ = io::Error::new(ErrorKind::Other, "boom");
5353
//! Err(io::Error::from(ErrorKind::Other).into())
5454
//! }
@@ -61,9 +61,9 @@
6161
//! feature):
6262
//!
6363
//! ```rust
64-
//! use masterror::{AppError, AppErrorKind};
64+
//! use masterror::{AppError, AppErrorKind, AppResult};
6565
//!
66-
//! fn validate(x: i32) -> Result<(), AppError> {
66+
//! fn validate(x: i32) -> AppResult<()> {
6767
//! if x < 0 {
6868
//! return Err(String::from("must be non-negative").into());
6969
//! }
@@ -149,9 +149,9 @@ impl From<IoError> for AppError {
149149
/// Prefer structured validation for complex DTOs, but this covers simple cases.
150150
///
151151
/// ```rust
152-
/// use masterror::{AppError, AppErrorKind};
152+
/// use masterror::{AppError, AppErrorKind, AppResult};
153153
///
154-
/// fn check(name: &str) -> Result<(), AppError> {
154+
/// fn check(name: &str) -> AppResult<()> {
155155
/// if name.is_empty() {
156156
/// return Err(String::from("name must not be empty").into());
157157
/// }

src/convert/actix.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//!
66
//! ## What it does
77
//! - Implements `actix_web::ResponseError` for [`AppError`].
8-
//! - This lets you `return Result<_, AppError>` from Actix handlers.
8+
//! - This lets you `return AppResult<_>` from Actix handlers.
99
//! - On error, Actix automatically builds an `HttpResponse` with the right
1010
//! status code and JSON body (when the `serde_json` feature is enabled).
1111
//! - Provides stable mapping from [`AppErrorKind`] to

src/convert/validator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
//! ## Example
2020
//!
2121
//! ```rust,ignore
22-
//! use masterror::{AppError, AppErrorKind};
22+
//! use masterror::{AppError, AppErrorKind, AppResult};
2323
//! use validator::{Validate, ValidationError};
2424
//!
2525
//! #[derive(Validate)]
@@ -28,7 +28,7 @@
2828
//! name: String,
2929
//! }
3030
//!
31-
//! fn validate_payload(p: Payload) -> Result<(), AppError> {
31+
//! fn validate_payload(p: Payload) -> AppResult<()> {
3232
//! p.validate()?;
3333
//! Ok(())
3434
//! }

0 commit comments

Comments
 (0)