From c77c74612d9b0bce2b131bf613d0ea82a74f00e9 Mon Sep 17 00:00:00 2001 From: Dorian Date: Wed, 6 May 2026 18:09:58 +0100 Subject: [PATCH] Add graph telemetry and remote signer login --- .env.example | 8 +- apps/api/src/datum/poller.ts | 9 + apps/api/src/server.ts | 2 +- apps/web/src/App.vue | 41 ++- apps/web/src/components/MinerCard.vue | 13 +- apps/web/src/router.ts | 11 + apps/web/src/services/signer.ts | 120 ++++++ apps/web/src/stores/auth.ts | 20 +- apps/web/src/stores/stats.ts | 61 +++- apps/web/src/strings.ts | 16 +- apps/web/src/types.ts | 13 + apps/web/src/views/DashboardView.vue | 61 +++- apps/web/src/views/GraphsView.vue | 441 +++++++++++++++++++++++ apps/web/src/views/LoginView.vue | 30 +- apps/web/src/views/NostrCallbackView.vue | 23 ++ docker-compose.yml | 27 +- 16 files changed, 855 insertions(+), 41 deletions(-) create mode 100644 apps/web/src/views/GraphsView.vue create mode 100644 apps/web/src/views/NostrCallbackView.vue diff --git a/.env.example b/.env.example index 4e38d36..e266664 100644 --- a/.env.example +++ b/.env.example @@ -13,10 +13,10 @@ LOG_LEVEL=info # STATIC_DIR= # ---- Datum gateway (the Umbrel app we're polling) ---- -# Reachable internally inside Umbrel's docker network. From your LAN it's also -# at http://192.168.1.191:21000 but that path goes through umbrelOS auth. -# Inside the Umbrel docker network, use the Datum service hostname directly. -DATUM_URL=http://10.21.0.11:21000 +# Inside the Umbrel docker network, use Datum's service hostname directly. +# If you run the API outside that Docker network, override this with a hostname +# or IP address reachable from that process. +DATUM_URL=http://datum:21000 DATUM_ADMIN_USER=admin DATUM_ADMIN_PASSWORD= # How often to scrape /clients (ms). Datum updates per-worker hashrate every diff --git a/apps/api/src/datum/poller.ts b/apps/api/src/datum/poller.ts index e848a12..d66cc9e 100644 --- a/apps/api/src/datum/poller.ts +++ b/apps/api/src/datum/poller.ts @@ -51,6 +51,15 @@ function formatErr(err: unknown): string { const cause = (err as Error & { cause?: unknown }).cause; if (cause instanceof Error) { const code = (cause as Error & { code?: string }).code; + const hostname = (cause as Error & { hostname?: string }).hostname; + if (code === "ENOTFOUND" && hostname) { + const datumHost = new URL(config.datum.url).hostname; + const hint = + hostname === datumHost + ? "; check DATUM_NETWORK or set DATUM_URL to a hostname/IP reachable from the gashboard API container" + : ""; + return `${err.message}: DNS could not resolve ${hostname} (${code})${hint}`; + } return code ? `${err.message}: ${cause.message} (${code})` : `${err.message}: ${cause.message}`; } return err.message; diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts index e3aa767..3b7a528 100644 --- a/apps/api/src/server.ts +++ b/apps/api/src/server.ts @@ -26,7 +26,7 @@ export function buildApp() { "script-src": ["'self'"], "style-src": ["'self'", "'unsafe-inline'"], "img-src": ["'self'", "data:"], - "connect-src": ["'self'"], + "connect-src": ["'self'", "wss://relay.primal.net"], "font-src": ["'self'", "data:"], "frame-ancestors": ["'none'"], "upgrade-insecure-requests": null, diff --git a/apps/web/src/App.vue b/apps/web/src/App.vue index 058a08f..e641dfa 100644 --- a/apps/web/src/App.vue +++ b/apps/web/src/App.vue @@ -1,6 +1,6 @@