use axum::extract::State;
use axum::http::{header, StatusCode};
use axum::response::{IntoResponse, Response};
use std::sync::Arc;
use super::content::{generate_ai_txt, generate_llms_txt, ContentConfig};
use crate::callback::AuthCallback;
use crate::services::EmailService;
use crate::AppState;
pub async fn llms_txt<C: AuthCallback + 'static, E: EmailService + 'static>(
State(state): State<Arc<AppState<C, E>>>,
) -> Response {
let config = get_content_config(&state);
let content = generate_llms_txt(&config);
(
StatusCode::OK,
[(header::CONTENT_TYPE, "text/plain; charset=utf-8")],
content,
)
.into_response()
}
pub async fn llms_admin_txt<C: AuthCallback + 'static, E: EmailService + 'static>(
State(state): State<Arc<AppState<C, E>>>,
) -> Response {
let base = get_base_path(&state);
let content = format!(
r#"# Cedros Login Admin API
> Administrative operations for system management. Requires valid authentication (API key or JWT) plus system admin role OR org owner/admin role for org-scoped operations.
## Prerequisites
Admin operations require:
1. Valid authentication (API key or JWT)
2. System admin role OR org owner/admin role (for org-scoped operations)
## System Admin Operations
These require `is_system_admin: true` on the user account.
## User Management
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/admin/users | List all users (paginated) |
| GET | {base}/admin/users/stats | Get user statistics |
| GET | {base}/admin/users/{{id}} | Get user details |
| PATCH | {base}/admin/users/{{id}} | Update user |
| DELETE | {base}/admin/users/{{id}} | Delete user |
| POST | {base}/admin/users/{{id}}/system-admin | Set system admin status |
| POST | {base}/admin/users/{{id}}/force-password-reset | Force password reset |
## User Credits & Deposits
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/admin/users/{{id}}/credits | Get user credit balance & history |
| POST | {base}/admin/users/{{id}}/credits | Adjust user credits |
| GET | {base}/admin/users/{{id}}/deposits | Get user deposit history |
| GET | {base}/admin/users/{{id}}/withdrawal-history | Get withdrawal history |
## System Settings
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/admin/settings | List all system settings |
| PUT | {base}/admin/settings | Update system settings |
## Deposit Management
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/admin/deposits | List all deposits |
| GET | {base}/admin/deposits/stats | Get deposit statistics |
| GET | {base}/admin/deposits/privacy-period | List deposits in privacy period |
## Withdrawal Management
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/admin/withdrawals/pending | List pending withdrawals |
| POST | {base}/admin/withdrawals/{{id}}/process | Process a withdrawal |
| POST | {base}/admin/withdrawals/process-all | Process all pending withdrawals |
## SSO Provider Management
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/admin/sso-providers | List SSO providers |
| POST | {base}/admin/sso-providers | Create SSO provider |
| GET | {base}/admin/sso-providers/{{id}} | Get provider details |
| PATCH | {base}/admin/sso-providers/{{id}} | Update provider |
| DELETE | {base}/admin/sso-providers/{{id}} | Delete provider |
## Audit Logs
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/admin/audit-logs | Get system audit logs |
| GET | {base}/admin/orgs/{{id}}/audit-logs | Get org audit logs |
## Dashboard Permissions
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/admin/dashboard-permissions | Get dashboard permissions config |
| PUT | {base}/admin/dashboard-permissions | Update dashboard permissions |
## Org Admin Operations
These require owner/admin role within the organization.
## Member Management
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/orgs/{{id}}/members | List org members |
| PATCH | {base}/orgs/{{id}}/members/{{userId}} | Update member role |
| DELETE | {base}/orgs/{{id}}/members/{{userId}} | Remove member |
## Invite Management
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/orgs/{{id}}/invites | List pending invites |
| POST | {base}/orgs/{{id}}/invites | Create invite |
| POST | {base}/orgs/{{id}}/invites/{{id}}/resend | Resend invite |
| DELETE | {base}/orgs/{{id}}/invites/{{id}} | Cancel invite |
## Custom Roles (RBAC)
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/orgs/{{id}}/roles | List custom roles |
| POST | {base}/orgs/{{id}}/roles | Create custom role |
| PATCH | {base}/orgs/{{id}}/roles/{{id}} | Update role |
| DELETE | {base}/orgs/{{id}}/roles/{{id}} | Delete role |
## ABAC Policies
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/orgs/{{id}}/policies | List policies |
| POST | {base}/orgs/{{id}}/policies | Create policy |
| PATCH | {base}/orgs/{{id}}/policies/{{id}} | Update policy |
| DELETE | {base}/orgs/{{id}}/policies/{{id}} | Delete policy |
## Example: List Users (Admin)
```
GET {base}/admin/users?page=1&limit=20
Authorization: Bearer ck_xxx
Response:
{{
"users": [...],
"total": 150,
"page": 1,
"limit": 20
}}
```
## Example: Adjust User Credits
```
POST {base}/admin/users/{{user_id}}/credits
Authorization: Bearer ck_xxx
Content-Type: application/json
{{
"amount": 1000,
"reason": "Promotional credit"
}}
```
## Error Handling
Admin endpoints return standard error format:
```json
{{
"code": "FORBIDDEN",
"message": "Admin access required"
}}
```
Common admin error codes:
- FORBIDDEN - Insufficient permissions
- NOT_FOUND - Resource not found
- VALIDATION_ERROR - Invalid input
## API
- [{base}/openapi.json]({base}/openapi.json): Full OpenAPI 3.0 specification
- [{base}/llms.txt]({base}/llms.txt): Brief API summary
- [{base}/llms-full.txt]({base}/llms-full.txt): Complete API documentation
- [{base}/skills/admin.md]({base}/skills/admin.md): Admin skill documentation
"#,
base = base
);
(
StatusCode::OK,
[(header::CONTENT_TYPE, "text/plain; charset=utf-8")],
content,
)
.into_response()
}
pub async fn llms_full_txt<C: AuthCallback + 'static, E: EmailService + 'static>(
State(state): State<Arc<AppState<C, E>>>,
) -> Response {
let base = get_base_path(&state);
let content = format!(
r#"# Cedros Login API
> Complete authentication and authorization API documentation. Supports Solana wallet auth (recommended for agents), email/password, OAuth, passkeys, MFA, organizations with RBAC, and embedded Solana wallet operations.
All endpoints are relative to: `{base}`
## Authentication for AI Agents
### Recommended: Solana Wallet Auth
#### Step 1: Get Challenge
```
POST {base}/solana/challenge
Content-Type: application/json
{{"publicKey": "YourBase58SolanaPublicKey"}}
```
Response:
```json
{{"nonce": "Sign this message: cedros-auth-abc123...", "expiresAt": "2024-..."}}
```
#### Step 2: Sign and Authenticate
```
POST {base}/solana
Content-Type: application/json
{{
"publicKey": "YourBase58SolanaPublicKey",
"signature": "Base58SignatureOfNonce"
}}
```
Response (new user):
```json
{{
"user": {{"id": "uuid", "walletAddress": "..."}},
"tokens": {{"accessToken": "...", "refreshToken": "..."}},
"apiKey": "ck_live_abc123...",
"isNewUser": true
}}
```
#### Step 3: Use API Key
```
Authorization: Bearer ck_live_abc123...
```
## Core Endpoints
### User Operations
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/user | Get current user |
| PATCH | {base}/me | Update profile |
| POST | {base}/change-password | Change password |
| GET | {base}/user/api-key | Get API key |
| POST | {base}/user/api-key/regenerate | Regenerate API key |
### Sessions
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/sessions | List sessions |
| DELETE | {base}/sessions | Revoke all |
| POST | {base}/logout | Logout current |
| POST | {base}/logout-all | Logout all |
### Organizations
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/orgs | List orgs |
| POST | {base}/orgs | Create org |
| GET | {base}/orgs/{{id}} | Get org |
| PATCH | {base}/orgs/{{id}} | Update org |
| DELETE | {base}/orgs/{{id}} | Delete org |
| POST | {base}/orgs/{{id}}/switch | Switch context |
### Members
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/orgs/{{id}}/members | List members |
| PATCH | {base}/orgs/{{id}}/members/{{userId}} | Update role |
| DELETE | {base}/orgs/{{id}}/members/{{userId}} | Remove |
### Invites
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/orgs/{{id}}/invites | List invites |
| POST | {base}/orgs/{{id}}/invites | Create |
| POST | {base}/invites/{{token}}/accept | Accept |
| DELETE | {base}/orgs/{{id}}/invites/{{id}} | Cancel |
### Authorization
| Method | Path | Description |
|--------|------|-------------|
| POST | {base}/authorize | Check permission |
| GET | {base}/permissions | Get all permissions |
### MFA
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/mfa/status | Get status |
| POST | {base}/mfa/setup | Start setup |
| POST | {base}/mfa/enable | Enable |
| POST | {base}/mfa/disable | Disable |
| POST | {base}/mfa/verify | Verify code |
### Embedded Wallet
| Method | Path | Description |
|--------|------|-------------|
| GET | {base}/wallet/status | Get wallet status |
| GET | {base}/wallet/material | Get wallet material |
| POST | {base}/wallet/enroll | Enroll wallet |
| POST | {base}/wallet/unlock | Unlock wallet |
| POST | {base}/wallet/sign | Sign transaction |
## Error Format
```json
{{
"code": "ERROR_CODE",
"message": "Human-readable message",
"details": {{}}
}}
```
## Rate Limits
- Auth: 10 req/min per IP
- API: 100 req/min per key
- Admin: 30 req/min per key
## Docs
- [{base}/agent.md]({base}/agent.md): Agent integration guide with code examples
- [{base}/llms.txt]({base}/llms.txt): Brief API summary
- [{base}/llms-admin.txt]({base}/llms-admin.txt): Admin operations reference
## Skills
- [{base}/skills/auth.md]({base}/skills/auth.md): Authentication, sessions, API keys
- [{base}/skills/profile.md]({base}/skills/profile.md): User profile management
- [{base}/skills/orgs.md]({base}/skills/orgs.md): Organizations, members, invites, RBAC
- [{base}/skills/mfa.md]({base}/skills/mfa.md): Multi-factor authentication setup
- [{base}/skills/wallet.md]({base}/skills/wallet.md): Embedded Solana wallet operations
- [{base}/skills/admin.md]({base}/skills/admin.md): System administration (requires admin role)
## API
- [{base}/openapi.json]({base}/openapi.json): Full OpenAPI 3.0 specification
- [{base}/discovery]({base}/discovery): Machine-readable auth configuration
- [{base}/skill.json]({base}/skill.json): Machine-readable skill metadata
- [{base}/heartbeat.json]({base}/heartbeat.json): Health check endpoint
"#,
base = base
);
(
StatusCode::OK,
[(header::CONTENT_TYPE, "text/plain; charset=utf-8")],
content,
)
.into_response()
}
pub async fn ai_txt<C: AuthCallback + 'static, E: EmailService + 'static>(
State(state): State<Arc<AppState<C, E>>>,
) -> Response {
let config = get_content_config(&state);
let content = generate_ai_txt(&config);
(
StatusCode::OK,
[(header::CONTENT_TYPE, "text/plain; charset=utf-8")],
content,
)
.into_response()
}
pub fn get_content_config<C: AuthCallback, E: EmailService>(state: &AppState<C, E>) -> ContentConfig {
let base_path = state.config.server.auth_base_path.trim_end_matches('/');
ContentConfig::new(if base_path.is_empty() { "" } else { base_path })
}
fn get_base_path<C: AuthCallback, E: EmailService>(state: &AppState<C, E>) -> String {
let base_path = state.config.server.auth_base_path.trim_end_matches('/');
if base_path.is_empty() {
String::new()
} else {
base_path.to_string()
}
}