Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ hypr-am2 = { path = "crates/am2", package = "am2" }
hypr-analytics = { path = "crates/analytics", package = "analytics" }
hypr-api-integration = { path = "crates/api-integration", package = "api-integration" }
hypr-api-subscription = { path = "crates/api-subscription", package = "api-subscription" }
hypr-api-sync = { path = "crates/api-sync", package = "api-sync" }
hypr-apple-note = { path = "crates/apple-note", package = "apple-note" }
hypr-askama-utils = { path = "crates/askama-utils", package = "askama-utils" }
hypr-audio = { path = "crates/audio", package = "audio" }
Expand Down
19 changes: 19 additions & 0 deletions crates/api-sync/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "api-sync"
version = "0.1.0"
edition = "2024"

[dependencies]
hypr-supabase-auth = { workspace = true }

utoipa = { workspace = true }

axum = { workspace = true }
reqwest = { workspace = true, features = ["json"] }
sentry = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }

serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
23 changes: 23 additions & 0 deletions crates/api-sync/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::sync::Arc;

#[derive(Clone)]
pub struct SyncConfig {
pub supabase_url: String,
pub supabase_anon_key: String,
pub auth: Option<Arc<hypr_supabase_auth::SupabaseAuth>>,
}

impl SyncConfig {
pub fn new(supabase_url: impl Into<String>, supabase_anon_key: impl Into<String>) -> Self {
Self {
supabase_url: supabase_url.into(),
supabase_anon_key: supabase_anon_key.into(),
auth: None,
}
}

pub fn with_auth(mut self, auth: Arc<hypr_supabase_auth::SupabaseAuth>) -> Self {
self.auth = Some(auth);
self
}
}
52 changes: 52 additions & 0 deletions crates/api-sync/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use axum::{
Json,
http::StatusCode,
response::{IntoResponse, Response},
};
use serde::Serialize;
use thiserror::Error;

pub type Result<T> = std::result::Result<T, SyncError>;

#[derive(Debug, Serialize)]
pub struct ErrorResponse {
pub error: String,
}

#[derive(Debug, Error)]
pub enum SyncError {
#[error("Authentication error: {0}")]
Auth(String),

#[error("Invalid request: {0}")]
BadRequest(String),

#[error("Internal error: {0}")]
Internal(String),
}

impl From<hypr_supabase_auth::Error> for SyncError {
fn from(err: hypr_supabase_auth::Error) -> Self {
Self::Auth(err.to_string())
}
}

impl IntoResponse for SyncError {
fn into_response(self) -> Response {
let (status, error_code) = match &self {
Self::Auth(_) => (StatusCode::UNAUTHORIZED, "unauthorized"),
Self::BadRequest(_) => (StatusCode::BAD_REQUEST, "bad_request"),
Self::Internal(msg) => {
tracing::error!(error = %msg, "internal_error");
sentry::capture_message(msg, sentry::Level::Error);
(StatusCode::INTERNAL_SERVER_ERROR, "internal_server_error")
}
};

let body = Json(ErrorResponse {
error: error_code.to_string(),
});

(status, body).into_response()
}
}
9 changes: 9 additions & 0 deletions crates/api-sync/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
mod config;
mod error;
mod routes;
mod state;

pub use config::SyncConfig;
pub use error::{Result, SyncError};
pub use routes::{openapi, router};
pub use state::AppState;
22 changes: 22 additions & 0 deletions crates/api-sync/src/routes/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use axum::Router;
use utoipa::OpenApi;

use crate::state::AppState;

#[derive(OpenApi)]
#[openapi(
paths(),
components(schemas()),
tags(
(name = "sync", description = "Sync management")
)
)]
pub struct ApiDoc;

pub fn openapi() -> utoipa::openapi::OpenApi {
ApiDoc::openapi()
}

pub fn router(state: AppState) -> Router {
Router::new().with_state(state)
}
12 changes: 12 additions & 0 deletions crates/api-sync/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use crate::config::SyncConfig;

#[derive(Clone)]
pub struct AppState {
pub config: SyncConfig,
}

impl AppState {
pub fn new(config: SyncConfig) -> Self {
Self { config }
}
}
Loading