summaryrefslogtreecommitdiff
path: root/makima/src/server
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-04-28 19:12:52 +0100
committerGitHub <noreply@github.com>2026-04-28 19:12:52 +0100
commitd1fdfb140cc440664f77a24886172f9976a05a31 (patch)
tree454739f80dde60fc6c1cd97acbaef3223ac041c6 /makima/src/server
parent636694182fe9381479f2e9062229dda3838c5421 (diff)
downloadsoryu-d1fdfb140cc440664f77a24886172f9976a05a31.tar.gz
soryu-d1fdfb140cc440664f77a24886172f9976a05a31.zip
feat: revert broken directive PRs, re-implement Lexical document orchestrator (#98)
* feat: soryu-co/soryu - makima: Revert broken directive PRs and verify clean build * feat: soryu-co/soryu - makima: Re-implement frontend: Lexical document editor with feature flag and base components * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Add contract blocks, expandable log rows, and interaction controls * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: End-to-end build verification and integration polish
Diffstat (limited to 'makima/src/server')
-rw-r--r--makima/src/server/handlers/listen.rs3
-rw-r--r--makima/src/server/handlers/mesh.rs2
-rw-r--r--makima/src/server/handlers/mesh_daemon.rs2
-rw-r--r--makima/src/server/handlers/mesh_supervisor.rs2
-rw-r--r--makima/src/server/handlers/mod.rs1
-rw-r--r--makima/src/server/handlers/settings.rs196
-rw-r--r--makima/src/server/mod.rs22
7 files changed, 16 insertions, 212 deletions
diff --git a/makima/src/server/handlers/listen.rs b/makima/src/server/handlers/listen.rs
index 7edcdfc..e1bc30e 100644
--- a/makima/src/server/handlers/listen.rs
+++ b/makima/src/server/handlers/listen.rs
@@ -208,7 +208,8 @@ async fn handle_socket(socket: WebSocket, state: SharedState) {
audio_offset = 0.0;
finalized_segments.clear();
file_id = None;
- // authenticated_owner_id and target_contract_id are kept from above
+ authenticated_owner_id = authenticated_owner_id; // Keep from above
+ target_contract_id = target_contract_id; // Keep from above
// Reset models for new session
let mut sortformer = ml_models.sortformer.lock().await;
diff --git a/makima/src/server/handlers/mesh.rs b/makima/src/server/handlers/mesh.rs
index d9d40d7..1a5b9c1 100644
--- a/makima/src/server/handlers/mesh.rs
+++ b/makima/src/server/handlers/mesh.rs
@@ -20,7 +20,7 @@ use crate::db::models::{
use crate::db::repository::{self, RepositoryError};
use crate::server::auth::Authenticated;
use crate::server::messages::ApiError;
-use crate::server::state::{DaemonCommand, SharedState, TaskUpdateNotification};
+use crate::server::state::{DaemonCommand, DaemonReauthStatus, SharedState, TaskUpdateNotification};
// =============================================================================
// Authentication Types
diff --git a/makima/src/server/handlers/mesh_daemon.rs b/makima/src/server/handlers/mesh_daemon.rs
index ed1b603..e5f0a81 100644
--- a/makima/src/server/handlers/mesh_daemon.rs
+++ b/makima/src/server/handlers/mesh_daemon.rs
@@ -1627,7 +1627,7 @@ async fn handle_daemon_connection(socket: WebSocket, state: SharedState, auth_re
);
// Broadcast as task output with auth_required type so UI can display the login link
- let _content = format!(
+ let content = format!(
"🔐 Authentication required on daemon{}. Click to login: {}",
hostname.as_ref().map(|h| format!(" ({})", h)).unwrap_or_default(),
login_url
diff --git a/makima/src/server/handlers/mesh_supervisor.rs b/makima/src/server/handlers/mesh_supervisor.rs
index 3adb850..ebde52b 100644
--- a/makima/src/server/handlers/mesh_supervisor.rs
+++ b/makima/src/server/handlers/mesh_supervisor.rs
@@ -1272,7 +1272,7 @@ pub async fn create_branch(
headers: HeaderMap,
Json(request): Json<CreateBranchRequest>,
) -> impl IntoResponse {
- let (supervisor_id, _owner_id) = match verify_supervisor_auth(&state, &headers, None).await {
+ let (supervisor_id, owner_id) = match verify_supervisor_auth(&state, &headers, None).await {
Ok(ids) => ids,
Err(e) => return e.into_response(),
};
diff --git a/makima/src/server/handlers/mod.rs b/makima/src/server/handlers/mod.rs
index b3c433b..4bdb424 100644
--- a/makima/src/server/handlers/mod.rs
+++ b/makima/src/server/handlers/mod.rs
@@ -20,7 +20,6 @@ pub mod mesh_merge;
pub mod mesh_supervisor;
pub mod mesh_ws;
pub mod repository_history;
-pub mod settings;
pub mod speak;
pub mod templates;
pub mod voice;
diff --git a/makima/src/server/handlers/settings.rs b/makima/src/server/handlers/settings.rs
deleted file mode 100644
index ae52d5a..0000000
--- a/makima/src/server/handlers/settings.rs
+++ /dev/null
@@ -1,196 +0,0 @@
-//! HTTP handlers for user settings (feature flags / preferences).
-
-use axum::{
- extract::{Path, State},
- http::StatusCode,
- response::IntoResponse,
- Json,
-};
-
-use crate::db::models::{UpsertUserSettingRequest, UserSettingsResponse};
-use crate::db::repository;
-use crate::server::auth::Authenticated;
-use crate::server::messages::ApiError;
-use crate::server::state::SharedState;
-
-/// List all settings for the authenticated user.
-#[utoipa::path(
- get,
- path = "/api/v1/settings",
- responses(
- (status = 200, description = "User settings", body = UserSettingsResponse),
- (status = 401, description = "Not authenticated", body = ApiError),
- (status = 503, description = "Database not configured", body = ApiError),
- (status = 500, description = "Internal server error", body = ApiError),
- ),
- security(
- ("bearer_auth" = [])
- ),
- tag = "Settings"
-)]
-pub async fn list_settings(
- State(state): State<SharedState>,
- Authenticated(user): Authenticated,
-) -> impl IntoResponse {
- let Some(ref pool) = state.db_pool else {
- return (
- StatusCode::SERVICE_UNAVAILABLE,
- Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
- )
- .into_response();
- };
-
- match repository::get_user_settings(pool, user.owner_id).await {
- Ok(settings) => Json(UserSettingsResponse { settings }).into_response(),
- Err(e) => {
- tracing::error!("Failed to list user settings: {}", e);
- (
- StatusCode::INTERNAL_SERVER_ERROR,
- Json(ApiError::new("DB_ERROR", e.to_string())),
- )
- .into_response()
- }
- }
-}
-
-/// Get a specific setting by key.
-#[utoipa::path(
- get,
- path = "/api/v1/settings/{key}",
- params(
- ("key" = String, Path, description = "Setting key")
- ),
- responses(
- (status = 200, description = "User setting", body = crate::db::models::UserSetting),
- (status = 401, description = "Not authenticated", body = ApiError),
- (status = 404, description = "Setting not found", body = ApiError),
- (status = 503, description = "Database not configured", body = ApiError),
- (status = 500, description = "Internal server error", body = ApiError),
- ),
- security(
- ("bearer_auth" = [])
- ),
- tag = "Settings"
-)]
-pub async fn get_setting(
- State(state): State<SharedState>,
- Authenticated(user): Authenticated,
- Path(key): Path<String>,
-) -> impl IntoResponse {
- let Some(ref pool) = state.db_pool else {
- return (
- StatusCode::SERVICE_UNAVAILABLE,
- Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
- )
- .into_response();
- };
-
- match repository::get_user_setting(pool, user.owner_id, &key).await {
- Ok(Some(setting)) => Json(setting).into_response(),
- Ok(None) => (
- StatusCode::NOT_FOUND,
- Json(ApiError::new("NOT_FOUND", format!("Setting '{}' not found", key))),
- )
- .into_response(),
- Err(e) => {
- tracing::error!("Failed to get user setting: {}", e);
- (
- StatusCode::INTERNAL_SERVER_ERROR,
- Json(ApiError::new("DB_ERROR", e.to_string())),
- )
- .into_response()
- }
- }
-}
-
-/// Upsert a user setting (create or update).
-#[utoipa::path(
- put,
- path = "/api/v1/settings",
- request_body = UpsertUserSettingRequest,
- responses(
- (status = 200, description = "Setting upserted", body = crate::db::models::UserSetting),
- (status = 401, description = "Not authenticated", body = ApiError),
- (status = 503, description = "Database not configured", body = ApiError),
- (status = 500, description = "Internal server error", body = ApiError),
- ),
- security(
- ("bearer_auth" = [])
- ),
- tag = "Settings"
-)]
-pub async fn upsert_setting(
- State(state): State<SharedState>,
- Authenticated(user): Authenticated,
- Json(req): Json<UpsertUserSettingRequest>,
-) -> impl IntoResponse {
- let Some(ref pool) = state.db_pool else {
- return (
- StatusCode::SERVICE_UNAVAILABLE,
- Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
- )
- .into_response();
- };
-
- match repository::upsert_user_setting(pool, user.owner_id, &req.key, &req.value).await {
- Ok(setting) => Json(setting).into_response(),
- Err(e) => {
- tracing::error!("Failed to upsert user setting: {}", e);
- (
- StatusCode::INTERNAL_SERVER_ERROR,
- Json(ApiError::new("DB_ERROR", e.to_string())),
- )
- .into_response()
- }
- }
-}
-
-/// Delete a user setting by key.
-#[utoipa::path(
- delete,
- path = "/api/v1/settings/{key}",
- params(
- ("key" = String, Path, description = "Setting key")
- ),
- responses(
- (status = 200, description = "Setting deleted"),
- (status = 401, description = "Not authenticated", body = ApiError),
- (status = 404, description = "Setting not found", body = ApiError),
- (status = 503, description = "Database not configured", body = ApiError),
- (status = 500, description = "Internal server error", body = ApiError),
- ),
- security(
- ("bearer_auth" = [])
- ),
- tag = "Settings"
-)]
-pub async fn delete_setting(
- State(state): State<SharedState>,
- Authenticated(user): Authenticated,
- Path(key): Path<String>,
-) -> impl IntoResponse {
- let Some(ref pool) = state.db_pool else {
- return (
- StatusCode::SERVICE_UNAVAILABLE,
- Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
- )
- .into_response();
- };
-
- match repository::delete_user_setting(pool, user.owner_id, &key).await {
- Ok(true) => StatusCode::OK.into_response(),
- Ok(false) => (
- StatusCode::NOT_FOUND,
- Json(ApiError::new("NOT_FOUND", format!("Setting '{}' not found", key))),
- )
- .into_response(),
- Err(e) => {
- tracing::error!("Failed to delete user setting: {}", e);
- (
- StatusCode::INTERNAL_SERVER_ERROR,
- Json(ApiError::new("DB_ERROR", e.to_string())),
- )
- .into_response()
- }
- }
-}
diff --git a/makima/src/server/mod.rs b/makima/src/server/mod.rs
index 025ec85..99dc1f3 100644
--- a/makima/src/server/mod.rs
+++ b/makima/src/server/mod.rs
@@ -18,7 +18,7 @@ use tower_http::trace::TraceLayer;
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;
-use crate::server::handlers::{api_keys, chat, contract_chat, contract_daemon, contract_discuss, contracts, daemon_download, directives, file_ws, files, history, listen, mesh, mesh_chat, mesh_daemon, mesh_merge, mesh_supervisor, mesh_ws, orders, repository_history, settings, speak, templates, transcript_analysis, users, versions};
+use crate::server::handlers::{api_keys, chat, contract_chat, contract_daemon, contract_discuss, contracts, daemon_download, directives, file_ws, files, history, listen, mesh, mesh_chat, mesh_daemon, mesh_merge, mesh_supervisor, mesh_ws, orders, repository_history, speak, templates, transcript_analysis, users, versions};
use crate::server::openapi::ApiDoc;
use crate::server::state::SharedState;
@@ -281,16 +281,7 @@ pub fn make_router(state: SharedState) -> Router {
.route("/timeline", get(history::get_timeline))
// Contract type templates (built-in only)
.route("/contract-types", get(templates::list_contract_types))
- // User settings (feature flags) endpoints
- .route(
- "/user-settings",
- get(settings::list_settings).put(settings::upsert_setting),
- )
- .route(
- "/user-settings/{key}",
- get(settings::get_setting).delete(settings::delete_setting),
- )
- // Settings endpoints
+ // Settings endpoints (static routes first to avoid conflict with /settings/{key})
.route(
"/settings/repository-history",
get(repository_history::list_repository_history),
@@ -303,6 +294,15 @@ pub fn make_router(state: SharedState) -> Router {
"/settings/repository-history/{id}",
axum::routing::delete(repository_history::delete_repository_history),
)
+ // User settings (feature flags / preferences)
+ .route(
+ "/settings",
+ get(settings::list_settings).put(settings::upsert_setting),
+ )
+ .route(
+ "/settings/{key}",
+ get(settings::get_setting).delete(settings::delete_setting),
+ )
.with_state(state);
let swagger = SwaggerUi::new("/swagger-ui")