1pub mod account;
8pub mod auth;
9pub mod error;
10pub mod routes;
11pub mod state;
12pub mod ws;
13
14use std::sync::Arc;
15
16use axum::middleware;
17use axum::routing::{delete, get, patch, post};
18use axum::Router;
19use tower_http::cors::CorsLayer;
20use tower_http::trace::TraceLayer;
21
22use crate::state::AppState;
23
24pub fn build_router(state: Arc<AppState>) -> Router {
26 let api = Router::new()
27 .route("/health", get(routes::health::health))
28 .route("/health/detailed", get(routes::health::health_detailed))
29 .route("/auth/login", post(auth::routes::login))
31 .route("/auth/logout", post(auth::routes::logout))
32 .route("/auth/status", get(auth::routes::status))
33 .route("/analytics/summary", get(routes::analytics::summary))
35 .route("/analytics/followers", get(routes::analytics::followers))
36 .route(
37 "/analytics/performance",
38 get(routes::analytics::performance),
39 )
40 .route("/analytics/topics", get(routes::analytics::topics))
41 .route(
42 "/analytics/recent-performance",
43 get(routes::analytics::recent_performance),
44 )
45 .route("/approval/export", get(routes::approval::export_items))
47 .route("/approval", get(routes::approval::list_items))
48 .route("/approval/stats", get(routes::approval::stats))
49 .route("/approval/approve-all", post(routes::approval::approve_all))
50 .route(
51 "/approval/{id}/history",
52 get(routes::approval::get_edit_history),
53 )
54 .route("/approval/{id}", patch(routes::approval::edit_item))
55 .route(
56 "/approval/{id}/approve",
57 post(routes::approval::approve_item),
58 )
59 .route("/approval/{id}/reject", post(routes::approval::reject_item))
60 .route("/activity/export", get(routes::activity::export_activity))
62 .route("/activity", get(routes::activity::list_activity))
63 .route(
64 "/activity/rate-limits",
65 get(routes::activity::rate_limit_usage),
66 )
67 .route("/replies", get(routes::replies::list_replies))
69 .route(
71 "/content/tweets",
72 get(routes::content::list_tweets).post(routes::content::compose_tweet),
73 )
74 .route(
75 "/content/threads",
76 get(routes::content::list_threads).post(routes::content::compose_thread),
77 )
78 .route("/content/calendar", get(routes::content::calendar))
79 .route("/content/schedule", get(routes::content::schedule))
80 .route("/content/compose", post(routes::content::compose))
81 .route(
82 "/content/scheduled/{id}",
83 patch(routes::content::edit_scheduled).delete(routes::content::cancel_scheduled),
84 )
85 .route(
87 "/content/drafts",
88 get(routes::content::list_drafts).post(routes::content::create_draft),
89 )
90 .route(
91 "/content/drafts/{id}",
92 patch(routes::content::edit_draft).delete(routes::content::delete_draft),
93 )
94 .route(
95 "/content/drafts/{id}/schedule",
96 post(routes::content::schedule_draft),
97 )
98 .route(
99 "/content/drafts/{id}/publish",
100 post(routes::content::publish_draft),
101 )
102 .route("/ingest", post(routes::ingest::ingest))
104 .route(
106 "/targets",
107 get(routes::targets::list_targets).post(routes::targets::add_target),
108 )
109 .route(
110 "/targets/{username}/timeline",
111 get(routes::targets::target_timeline),
112 )
113 .route(
114 "/targets/{username}/stats",
115 get(routes::targets::target_stats),
116 )
117 .route(
118 "/targets/{username}",
119 delete(routes::targets::remove_target),
120 )
121 .route("/strategy/current", get(routes::strategy::current))
123 .route("/strategy/history", get(routes::strategy::history))
124 .route("/strategy/refresh", post(routes::strategy::refresh))
125 .route("/strategy/inputs", get(routes::strategy::inputs))
126 .route("/costs/summary", get(routes::costs::summary))
128 .route("/costs/daily", get(routes::costs::daily))
129 .route("/costs/by-model", get(routes::costs::by_model))
130 .route("/costs/by-type", get(routes::costs::by_type))
131 .route("/costs/x-api/summary", get(routes::costs::x_api_summary))
133 .route("/costs/x-api/daily", get(routes::costs::x_api_daily))
134 .route(
135 "/costs/x-api/by-endpoint",
136 get(routes::costs::x_api_by_endpoint),
137 )
138 .route("/assist/tweet", post(routes::assist::assist_tweet))
140 .route("/assist/reply", post(routes::assist::assist_reply))
141 .route("/assist/thread", post(routes::assist::assist_thread))
142 .route("/assist/improve", post(routes::assist::assist_improve))
143 .route("/assist/topics", get(routes::assist::assist_topics))
144 .route(
145 "/assist/optimal-times",
146 get(routes::assist::assist_optimal_times),
147 )
148 .route("/assist/mode", get(routes::assist::get_mode))
149 .route("/discovery/feed", get(routes::discovery::feed))
151 .route("/discovery/keywords", get(routes::discovery::keywords))
152 .route(
153 "/discovery/{tweet_id}/compose-reply",
154 post(routes::discovery::compose_reply),
155 )
156 .route(
157 "/discovery/{tweet_id}/queue-reply",
158 post(routes::discovery::queue_reply),
159 )
160 .route("/media/upload", post(routes::media::upload))
162 .route("/media/file", get(routes::media::serve_file))
163 .route(
165 "/settings/lan",
166 get(routes::lan::get_status).patch(routes::lan::toggle_lan),
167 )
168 .route(
169 "/settings/lan/reset-passphrase",
170 post(routes::lan::reset_passphrase),
171 )
172 .route("/settings/status", get(routes::settings::config_status))
174 .route("/settings/init", post(routes::settings::init_settings))
175 .route(
176 "/settings/validate",
177 post(routes::settings::validate_settings),
178 )
179 .route("/settings/defaults", get(routes::settings::get_defaults))
180 .route("/settings/test-llm", post(routes::settings::test_llm))
181 .route(
182 "/settings",
183 get(routes::settings::get_settings).patch(routes::settings::patch_settings),
184 )
185 .route(
187 "/mcp/policy",
188 get(routes::mcp::get_policy).patch(routes::mcp::patch_policy),
189 )
190 .route("/mcp/policy/templates", get(routes::mcp::list_templates))
191 .route(
192 "/mcp/policy/templates/{name}",
193 post(routes::mcp::apply_template),
194 )
195 .route(
196 "/mcp/telemetry/summary",
197 get(routes::mcp::telemetry_summary),
198 )
199 .route(
200 "/mcp/telemetry/metrics",
201 get(routes::mcp::telemetry_metrics),
202 )
203 .route("/mcp/telemetry/errors", get(routes::mcp::telemetry_errors))
204 .route("/mcp/telemetry/recent", get(routes::mcp::telemetry_recent))
205 .route("/runtime/status", get(routes::runtime::status))
207 .route("/runtime/start", post(routes::runtime::start))
208 .route("/runtime/stop", post(routes::runtime::stop))
209 .route(
211 "/accounts",
212 get(routes::accounts::list_accounts).post(routes::accounts::create_account),
213 )
214 .route(
215 "/accounts/{id}/roles",
216 get(routes::accounts::list_roles)
217 .post(routes::accounts::set_role)
218 .delete(routes::accounts::remove_role),
219 )
220 .route(
221 "/accounts/{id}",
222 get(routes::accounts::get_account)
223 .patch(routes::accounts::update_account)
224 .delete(routes::accounts::delete_account),
225 )
226 .route("/ws", get(ws::ws_handler))
228 .layer(middleware::from_fn_with_state(
230 state.clone(),
231 auth::auth_middleware,
232 ));
233
234 Router::new()
235 .nest("/api", api)
236 .layer(CorsLayer::permissive())
237 .layer(TraceLayer::new_for_http())
238 .with_state(state)
239}