mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-06 08:18:58 +00:00
- Rename 20 crate directories lib/crates/arc-* → fabro-* - Update all Cargo.toml: crate names, dep paths, feature flags, bin name - Rename arc_server module → fabro_server in fabro-llm - ArcError → FabroError across 30+ files - ARC_VERSION/ARC_GIT_SHA/ARC_BUILD_DATE → FABRO_* constants - All use/qualified paths: arc_agent:: → fabro_agent::, etc. (~1500 occurrences) - Env vars ARC_* → FABRO_* in string literals and shell scripts - String literals: X-Arc-Demo, arc-bot, arc@local, arc-web, arc-mcp, etc. - Path strings: .arc/ → .fabro/, arc.toml → fabro.toml, refs/arc/ → refs/fabro/ - arc-api.yaml → fabro-api.yaml (OpenAPI spec) - skills/arc-create-workflow → fabro-create-workflow - trycmd fixtures: $ arc → $ fabro - Inline snapshots (insta) updated - CI, Docker, install.sh, scripts, CLAUDE.md, AGENTS.md - TypeScript app: env vars, headers, JWT issuer - Docs: page slugs, git refs, config paths, sandbox names, repo URLs - Repo references: brynary/arc → fabro-sh/fabro Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
67 lines
1.5 KiB
Rust
67 lines
1.5 KiB
Rust
use axum::http::StatusCode;
|
|
use axum::response::{IntoResponse, Response};
|
|
use axum::Json;
|
|
use serde::Serialize;
|
|
|
|
#[derive(Serialize)]
|
|
struct ErrorEntry {
|
|
status: String,
|
|
title: String,
|
|
detail: String,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct ErrorBody {
|
|
errors: Vec<ErrorEntry>,
|
|
}
|
|
|
|
/// Uniform API error response.
|
|
///
|
|
/// Serializes to `{"errors": [{"status": "4xx", "title": "...", "detail": "..."}]}`.
|
|
pub struct ApiError {
|
|
status: StatusCode,
|
|
detail: String,
|
|
}
|
|
|
|
impl ApiError {
|
|
pub fn new(status: StatusCode, detail: impl Into<String>) -> Self {
|
|
Self {
|
|
status,
|
|
detail: detail.into(),
|
|
}
|
|
}
|
|
|
|
pub fn not_found(detail: impl Into<String>) -> Self {
|
|
Self::new(StatusCode::NOT_FOUND, detail)
|
|
}
|
|
|
|
pub fn bad_request(detail: impl Into<String>) -> Self {
|
|
Self::new(StatusCode::BAD_REQUEST, detail)
|
|
}
|
|
|
|
pub fn unauthorized() -> Self {
|
|
Self::new(StatusCode::UNAUTHORIZED, "Authentication required.")
|
|
}
|
|
|
|
pub fn forbidden() -> Self {
|
|
Self::new(StatusCode::FORBIDDEN, "Access denied.")
|
|
}
|
|
}
|
|
|
|
impl IntoResponse for ApiError {
|
|
fn into_response(self) -> Response {
|
|
let title = self
|
|
.status
|
|
.canonical_reason()
|
|
.unwrap_or("Unknown")
|
|
.to_string();
|
|
let body = ErrorBody {
|
|
errors: vec![ErrorEntry {
|
|
status: self.status.as_u16().to_string(),
|
|
title,
|
|
detail: self.detail,
|
|
}],
|
|
};
|
|
(self.status, Json(body)).into_response()
|
|
}
|
|
}
|