diff --git a/backend/src/api.rs b/backend/src/api.rs index f276881..dd20c70 100644 --- a/backend/src/api.rs +++ b/backend/src/api.rs @@ -1,12 +1,12 @@ use std::sync::Arc; -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use axum::{ + Json, Router, extract::{Path, State}, http::{HeaderMap, Method, StatusCode, Uri}, response::{IntoResponse, Response}, routing::{get, post, put}, - Json, Router, }; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -26,12 +26,18 @@ pub struct AppState { pub fn router(state: AppState) -> Router { let tenant_routes = Router::new() .route("/tenant", get(get_tenant)) - .route("/tenant/relays", get(list_tenant_relays).post(create_tenant_relay)) + .route( + "/tenant/relays", + get(list_tenant_relays).post(create_tenant_relay), + ) .route( "/tenant/relays/:id", get(get_tenant_relay).put(update_tenant_relay), ) - .route("/tenant/relays/:id/deactivate", post(deactivate_tenant_relay)) + .route( + "/tenant/relays/:id/deactivate", + post(deactivate_tenant_relay), + ) .route("/tenant/invoices", get(list_tenant_invoices)) .route("/tenant/billing", put(update_tenant_billing)); @@ -67,16 +73,33 @@ impl IntoResponse for ApiError { } fn unauthorized() -> Response { - (StatusCode::UNAUTHORIZED, Json(ApiError { error: "unauthorized".into() })) + ( + StatusCode::UNAUTHORIZED, + Json(ApiError { + error: "unauthorized".into(), + }), + ) .into_response() } fn forbidden() -> Response { - (StatusCode::FORBIDDEN, Json(ApiError { error: "forbidden".into() })).into_response() + ( + StatusCode::FORBIDDEN, + Json(ApiError { + error: "forbidden".into(), + }), + ) + .into_response() } fn not_found() -> Response { - (StatusCode::NOT_FOUND, Json(ApiError { error: "not found".into() })).into_response() + ( + StatusCode::NOT_FOUND, + Json(ApiError { + error: "not found".into(), + }), + ) + .into_response() } fn is_unique_subdomain_violation(err: &anyhow::Error) -> bool { @@ -108,7 +131,10 @@ fn extract_auth_pubkey(headers: &HeaderMap, method: &Method, uri: &Uri) -> Resul .and_then(|v| v.to_str().ok()) .unwrap_or("http"); - let path = uri.path_and_query().map(|v| v.as_str()).unwrap_or(uri.path()); + let path = uri + .path_and_query() + .map(|v| v.as_str()) + .unwrap_or(uri.path()); let url = format!("{}://{}{}", scheme, host, path); let pubkey = verify_nip98(auth_header, &url, method.as_str())?; Ok(pubkey.to_hex()) @@ -136,11 +162,22 @@ async fn get_tenant( if state.repo.create_tenant(&tenant).await.is_ok() { (StatusCode::OK, Json(tenant)).into_response() } else { - (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to create tenant".into() })) + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to create tenant".into(), + }), + ) .into_response() } } - Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load tenant".into() })).into_response(), + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load tenant".into(), + }), + ) + .into_response(), } } @@ -157,7 +194,13 @@ async fn list_tenant_relays( match state.repo.list_relays_by_tenant(&pubkey).await { Ok(relays) => (StatusCode::OK, Json(relays)).into_response(), - Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load relays".into() })).into_response(), + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load relays".into(), + }), + ) + .into_response(), } } @@ -189,7 +232,12 @@ async fn create_tenant_relay( }; if let Err(_) = state.repo.create_tenant_if_missing(&tenant).await { - return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to ensure tenant".into() })) + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to ensure tenant".into(), + }), + ) .into_response(); } @@ -207,10 +255,22 @@ async fn create_tenant_relay( if let Err(err) = state.repo.create_relay(&relay).await { if is_unique_subdomain_violation(&err) { - return (StatusCode::CONFLICT, Json(ApiError { error: "subdomain already exists".into() })).into_response(); + return ( + StatusCode::CONFLICT, + Json(ApiError { + error: "subdomain already exists".into(), + }), + ) + .into_response(); } - return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to create relay".into() })).into_response(); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to create relay".into(), + }), + ) + .into_response(); } spawn_provisioning_worker(state.repo.clone(), state.provisioner.clone(), relay.clone()); @@ -234,7 +294,13 @@ async fn get_tenant_relay( Ok(Some(relay)) if relay.tenant == pubkey => (StatusCode::OK, Json(relay)).into_response(), Ok(Some(_)) => forbidden(), Ok(None) => not_found(), - Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load relay".into() })).into_response(), + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load relay".into(), + }), + ) + .into_response(), } } @@ -263,7 +329,15 @@ async fn update_tenant_relay( let existing = match state.repo.get_relay(&id).await { Ok(Some(relay)) => relay, Ok(None) => return not_found(), - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load relay".into() })).into_response(), + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load relay".into(), + }), + ) + .into_response(); + } }; if existing.tenant != pubkey { @@ -283,10 +357,22 @@ async fn update_tenant_relay( if let Err(err) = state.repo.update_relay(&updated).await { if is_unique_subdomain_violation(&err) { - return (StatusCode::CONFLICT, Json(ApiError { error: "subdomain already exists".into() })).into_response(); + return ( + StatusCode::CONFLICT, + Json(ApiError { + error: "subdomain already exists".into(), + }), + ) + .into_response(); } - return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to update relay".into() })).into_response(); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to update relay".into(), + }), + ) + .into_response(); } (StatusCode::OK, Json(updated)).into_response() @@ -307,7 +393,15 @@ async fn deactivate_tenant_relay( let existing = match state.repo.get_relay(&id).await { Ok(Some(relay)) => relay, Ok(None) => return not_found(), - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load relay".into() })).into_response(), + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load relay".into(), + }), + ) + .into_response(); + } }; if existing.tenant != pubkey { @@ -326,7 +420,13 @@ async fn deactivate_tenant_relay( }; if let Err(_) = state.repo.update_relay(&updated).await { - return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to deactivate relay".into() })).into_response(); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to deactivate relay".into(), + }), + ) + .into_response(); } (StatusCode::OK, Json(updated)).into_response() @@ -345,7 +445,13 @@ async fn list_tenant_invoices( match state.repo.list_invoices_by_tenant(&pubkey).await { Ok(invoices) => (StatusCode::OK, Json(invoices)).into_response(), - Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load invoices".into() })).into_response(), + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load invoices".into(), + }), + ) + .into_response(), } } @@ -371,7 +477,12 @@ async fn update_tenant_billing( .update_tenant_nwc_url(&pubkey, &payload.tenant_nwc_url) .await { - return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to update billing".into() })) + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to update billing".into(), + }), + ) .into_response(); } @@ -395,7 +506,13 @@ async fn admin_list_tenants( match state.repo.list_tenants().await { Ok(tenants) => (StatusCode::OK, Json(tenants)).into_response(), - Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load tenants".into() })).into_response(), + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load tenants".into(), + }), + ) + .into_response(), } } @@ -438,12 +555,28 @@ async fn admin_get_tenant( let tenant = match state.repo.get_tenant(&pubkey).await { Ok(Some(tenant)) => tenant, Ok(None) => return not_found(), - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load tenant".into() })).into_response(), + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load tenant".into(), + }), + ) + .into_response(); + } }; let relays = match state.repo.list_relays_by_tenant(&pubkey).await { Ok(relays) => relays, - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load relays".into() })).into_response(), + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load relays".into(), + }), + ) + .into_response(); + } }; #[derive(Serialize)] @@ -480,7 +613,15 @@ async fn admin_update_tenant_status( let tenant = match state.repo.get_tenant(&pubkey).await { Ok(Some(tenant)) => tenant, Ok(None) => return not_found(), - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load tenant".into() })).into_response(), + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load tenant".into(), + }), + ) + .into_response(); + } }; if let Err(_) = state @@ -488,7 +629,12 @@ async fn admin_update_tenant_status( .update_tenant_status(&tenant.pubkey, &payload.status) .await { - return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to update tenant".into() })) + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to update tenant".into(), + }), + ) .into_response(); } @@ -518,7 +664,13 @@ async fn admin_list_relays( match state.repo.list_relays().await { Ok(relays) => (StatusCode::OK, Json(relays)).into_response(), - Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load relays".into() })).into_response(), + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load relays".into(), + }), + ) + .into_response(), } } @@ -541,7 +693,13 @@ async fn admin_get_relay( match state.repo.get_relay(&id).await { Ok(Some(relay)) => (StatusCode::OK, Json(relay)).into_response(), Ok(None) => not_found(), - Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load relay".into() })).into_response(), + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load relay".into(), + }), + ) + .into_response(), } } @@ -565,7 +723,15 @@ async fn admin_update_relay( let existing = match state.repo.get_relay(&id).await { Ok(Some(relay)) => relay, Ok(None) => return not_found(), - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load relay".into() })).into_response(), + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load relay".into(), + }), + ) + .into_response(); + } }; let updated = UpdateRelay { @@ -581,10 +747,22 @@ async fn admin_update_relay( if let Err(err) = state.repo.update_relay(&updated).await { if is_unique_subdomain_violation(&err) { - return (StatusCode::CONFLICT, Json(ApiError { error: "subdomain already exists".into() })).into_response(); + return ( + StatusCode::CONFLICT, + Json(ApiError { + error: "subdomain already exists".into(), + }), + ) + .into_response(); } - return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to update relay".into() })).into_response(); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to update relay".into(), + }), + ) + .into_response(); } (StatusCode::OK, Json(updated)).into_response() @@ -609,7 +787,15 @@ async fn admin_deactivate_relay( let existing = match state.repo.get_relay(&id).await { Ok(Some(relay)) => relay, Ok(None) => return not_found(), - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to load relay".into() })).into_response(), + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to load relay".into(), + }), + ) + .into_response(); + } }; let updated = UpdateRelay { @@ -624,7 +810,13 @@ async fn admin_deactivate_relay( }; if let Err(_) = state.repo.update_relay(&updated).await { - return (StatusCode::INTERNAL_SERVER_ERROR, Json(ApiError { error: "failed to deactivate relay".into() })).into_response(); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ApiError { + error: "failed to deactivate relay".into(), + }), + ) + .into_response(); } (StatusCode::OK, Json(updated)).into_response() diff --git a/backend/src/auth.rs b/backend/src/auth.rs index b6bede2..68743ef 100644 --- a/backend/src/auth.rs +++ b/backend/src/auth.rs @@ -1,13 +1,13 @@ -use anyhow::{anyhow, Result}; -use base64::engine::general_purpose; +use anyhow::{Result, anyhow}; use base64::Engine; +use base64::engine::general_purpose; use std::str::FromStr; +use nostr_sdk::JsonUtil; use nostr_sdk::nostr::key::PublicKey; use nostr_sdk::nostr::nips::nip98::HttpMethod; use nostr_sdk::nostr::types::url::Url; use nostr_sdk::nostr::{Alphabet, Event, Kind, SingleLetterTag, TagKind, TagStandard}; -use nostr_sdk::JsonUtil; pub fn verify_nip98(auth_header: &str, url: &str, method: &str) -> Result { let url = Url::parse(url)?; diff --git a/backend/src/billing.rs b/backend/src/billing.rs index c5f94e8..6d7dbb0 100644 --- a/backend/src/billing.rs +++ b/backend/src/billing.rs @@ -1,6 +1,6 @@ -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use chrono::{DateTime, Months, Utc}; -use tokio::time::{sleep, Duration}; +use tokio::time::{Duration, sleep}; use uuid::Uuid; use crate::models::{Invoice, NewInvoice, NewInvoiceItem, Relay, Tenant}; @@ -8,7 +8,7 @@ use crate::notifications::Nip17Notifier; use crate::repo::Repo; use nostr_sdk::nips::nip47::{self, MakeInvoiceRequest, NostrWalletConnectURI, PayInvoiceRequest}; -use nostr_sdk::{Client, Filter, Kind, Keys, Timestamp}; +use nostr_sdk::{Client, Filter, Keys, Kind, Timestamp}; #[derive(Clone)] pub struct BillingService { @@ -18,11 +18,7 @@ pub struct BillingService { } impl BillingService { - pub fn new( - repo: Repo, - notifier: Nip17Notifier, - platform_nwc_url: String, - ) -> Self { + pub fn new(repo: Repo, notifier: Nip17Notifier, platform_nwc_url: String) -> Self { Self { repo, notifier, @@ -88,7 +84,9 @@ impl BillingService { invoice: invoice_str.clone(), }; - self.repo.create_invoice_with_items(&invoice, &items).await?; + self.repo + .create_invoice_with_items(&invoice, &items) + .await?; if tenant.tenant_nwc_url.trim().is_empty() { self.send_invoice_dm(tenant, &invoice, period_start, period_end) @@ -130,7 +128,9 @@ impl BillingService { return Ok(()); } - self.repo.update_tenant_status(&tenant.pubkey, "suspended").await?; + self.repo + .update_tenant_status(&tenant.pubkey, "suspended") + .await?; self.repo.suspend_relays_for_tenant(&tenant.pubkey).await?; Ok(()) } @@ -154,7 +154,9 @@ impl BillingService { async fn pay_invoice(&self, tenant_nwc_url: &str, invoice: &str) -> Result<()> { let uri = NostrWalletConnectURI::parse(tenant_nwc_url)?; let request = nip47::Request::pay_invoice(PayInvoiceRequest::new(invoice)); - self.send_nwc_request(&uri, request).await?.to_pay_invoice()?; + self.send_nwc_request(&uri, request) + .await? + .to_pay_invoice()?; Ok(()) } diff --git a/backend/src/db.rs b/backend/src/db.rs index f50ce96..85554ed 100644 --- a/backend/src/db.rs +++ b/backend/src/db.rs @@ -1,5 +1,7 @@ use anyhow::Result; -use sqlx::{migrate::Migrator, sqlite::SqliteConnectOptions, sqlite::SqlitePoolOptions, SqlitePool}; +use sqlx::{ + SqlitePool, migrate::Migrator, sqlite::SqliteConnectOptions, sqlite::SqlitePoolOptions, +}; use std::fs; use std::path::Path; use std::str::FromStr; diff --git a/backend/src/main.rs b/backend/src/main.rs index 715b050..c8c495a 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -12,14 +12,14 @@ mod repo; use std::net::SocketAddr; use anyhow::Result; -use axum::{routing::get, Router}; +use axum::{Router, routing::get}; use tokio::net::TcpListener; use tower_http::cors::CorsLayer; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; +use crate::billing::BillingService; use crate::config::Config; use crate::db::init_pool; -use crate::billing::BillingService; use crate::notifications::Nip17Notifier; use crate::platform::publish_platform_identity; use crate::provisioning::Provisioner; @@ -48,12 +48,12 @@ async fn main() -> Result<()> { &config.platform_messaging_relays, ) .await?; - let notifier = Nip17Notifier::new(config.platform_secret.clone(), config.indexer_relays.clone()).await?; - let billing = BillingService::new( - repo.clone(), - notifier, - config.platform_nwc_url.clone(), - ); + let notifier = Nip17Notifier::new( + config.platform_secret.clone(), + config.indexer_relays.clone(), + ) + .await?; + let billing = BillingService::new(repo.clone(), notifier, config.platform_nwc_url.clone()); tokio::spawn(billing.run()); let provisioner = Provisioner::new( config.zooid_api_url.clone(), diff --git a/backend/src/notifications.rs b/backend/src/notifications.rs index 5c2b323..7a6f13d 100644 --- a/backend/src/notifications.rs +++ b/backend/src/notifications.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use nostr_sdk::prelude::*; use std::collections::HashMap; use std::sync::Arc; @@ -16,7 +16,9 @@ pub struct Nip17Notifier { impl Nip17Notifier { pub async fn new(platform_secret: String, relays: Vec) -> Result { if platform_secret.trim().is_empty() { - return Err(anyhow!("PLATFORM_SECRET is required for NIP-17 notifications")); + return Err(anyhow!( + "PLATFORM_SECRET is required for NIP-17 notifications" + )); } let keys = Keys::parse(&platform_secret)?; diff --git a/backend/src/platform.rs b/backend/src/platform.rs index 97497e4..4f4b8b9 100644 --- a/backend/src/platform.rs +++ b/backend/src/platform.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use nostr_sdk::prelude::*; pub async fn publish_platform_identity( diff --git a/backend/src/provisioning.rs b/backend/src/provisioning.rs index f15017c..3f734c2 100644 --- a/backend/src/provisioning.rs +++ b/backend/src/provisioning.rs @@ -1,12 +1,12 @@ -use anyhow::{anyhow, Result}; -use rand::rngs::OsRng; +use anyhow::{Result, anyhow}; use rand::RngCore; +use rand::rngs::OsRng; use reqwest::Client; use serde::Serialize; +use nostr_sdk::nostr::Keys; use nostr_sdk::nostr::nips::nip98::{HttpData, HttpMethod}; use nostr_sdk::nostr::types::url::Url; -use nostr_sdk::nostr::Keys; use crate::models::NewRelay; @@ -54,7 +54,12 @@ impl Provisioner { if !res.status().is_success() { let status = res.status(); let body = res.text().await.unwrap_or_default(); - return Err(anyhow!("zooid provisioning failed for {}: {} {}", url, status, body)); + return Err(anyhow!( + "zooid provisioning failed for {}: {} {}", + url, + status, + body + )); } Ok(()) diff --git a/backend/src/repo.rs b/backend/src/repo.rs index 6a10682..3928745 100644 --- a/backend/src/repo.rs +++ b/backend/src/repo.rs @@ -2,7 +2,8 @@ use anyhow::Result; use sqlx::{Sqlite, SqlitePool, Transaction}; use crate::models::{ - Invoice, InvoiceItem, NewInvoice, NewInvoiceItem, NewRelay, NewTenant, Relay, Tenant, UpdateRelay, + Invoice, InvoiceItem, NewInvoice, NewInvoiceItem, NewRelay, NewTenant, Relay, Tenant, + UpdateRelay, }; #[derive(Clone)] @@ -16,14 +17,12 @@ impl Repo { } pub async fn create_tenant(&self, tenant: &NewTenant) -> Result<()> { - sqlx::query( - "INSERT INTO tenants (pubkey, status, tenant_nwc_url) VALUES (?, ?, ?)", - ) - .bind(&tenant.pubkey) - .bind(&tenant.status) - .bind(&tenant.tenant_nwc_url) - .execute(&self.pool) - .await?; + sqlx::query("INSERT INTO tenants (pubkey, status, tenant_nwc_url) VALUES (?, ?, ?)") + .bind(&tenant.pubkey) + .bind(&tenant.status) + .bind(&tenant.tenant_nwc_url) + .execute(&self.pool) + .await?; Ok(()) } @@ -123,10 +122,12 @@ impl Repo { } pub async fn suspend_relays_for_tenant(&self, tenant: &str) -> Result<()> { - sqlx::query("UPDATE relays SET status = 'suspended' WHERE tenant = ? AND status = 'active'") - .bind(tenant) - .execute(&self.pool) - .await?; + sqlx::query( + "UPDATE relays SET status = 'suspended' WHERE tenant = ? AND status = 'active'", + ) + .bind(tenant) + .execute(&self.pool) + .await?; Ok(()) } diff --git a/frontend/index.html b/frontend/index.html index 34ff6e1..062ebd7 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,9 +2,9 @@ - + - frontend + Caravel
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 5e7a444..78a76f4 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -2,10 +2,12 @@ import { render } from "solid-js/web" import "./index.css" import App from "./App" -import { restoreAccounts } from "./lib/nostr" +import { PLATFORM_NAME, restoreAccounts } from "./lib/nostr" const root = document.getElementById("root")! +document.title = PLATFORM_NAME + import("preline").then(() => { restoreAccounts() render(() => , root) diff --git a/frontend/src/pages/admin/AdminRelayList.tsx b/frontend/src/pages/admin/AdminRelayList.tsx index d4a7e30..8105625 100644 --- a/frontend/src/pages/admin/AdminRelayList.tsx +++ b/frontend/src/pages/admin/AdminRelayList.tsx @@ -52,7 +52,7 @@ export default function AdminRelayList() { errorText="Failed to load relays." /> - 0} fallback={

No relays found.

}> + 0} fallback={

No relays found.

}>
    {(relay) => ( diff --git a/frontend/src/pages/admin/AdminTenantList.tsx b/frontend/src/pages/admin/AdminTenantList.tsx index 924bda6..9ce0d6e 100644 --- a/frontend/src/pages/admin/AdminTenantList.tsx +++ b/frontend/src/pages/admin/AdminTenantList.tsx @@ -92,7 +92,7 @@ export default function AdminTenantList() { errorText="Failed to load tenants." /> - 0} fallback={

    No tenants found.

    }> + 0} fallback={

    No tenants found.

    }>
      {(tenant) => { diff --git a/frontend/src/pages/relays/RelayList.tsx b/frontend/src/pages/relays/RelayList.tsx index 9abbf6e..53d1078 100644 --- a/frontend/src/pages/relays/RelayList.tsx +++ b/frontend/src/pages/relays/RelayList.tsx @@ -79,7 +79,7 @@ export default function RelayList() { /> - 0} fallback={

      No relays match your filters.

      }> + 0} fallback={

      No relays found.

      }>
        {(relay) => (