From 7dfed2c052018d1aae2267a1805848730dd75d5f Mon Sep 17 00:00:00 2001 From: redshift <213178690+1ftredsh@users.noreply.github.com> Date: Mon, 27 Apr 2026 22:16:20 +0530 Subject: [PATCH] Add daemonUrl config for remote daemon support - Add optional daemonUrl field to RoutstrdConfig - Update callDaemon and isDaemonRunning to use configurable base URL - Disable auto-start when daemonUrl is set (Option A) - Gate local-only commands: onboard, start, restart, mode, logs, service install --- src/cli.ts | 16 ++++++++++++++++ src/utils/config.ts | 1 + src/utils/daemon-client.ts | 15 +++++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index bacfbbd..00c719f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -95,6 +95,16 @@ async function installCocodOrExit(): Promise { logger.log("cocod installed successfully."); } +async function requireLocalDaemon(): Promise { + const config = await loadConfig(); + if (config.daemonUrl) { + console.error( + `This command is not available when using a remote daemon (${config.daemonUrl}).`, + ); + process.exit(1); + } +} + async function initDaemon(): Promise { logger.log("Initializing routstrd..."); @@ -292,6 +302,7 @@ program "Initialize routstrd (creates config directory and initializes cocod)", ) .action(async () => { + await requireLocalDaemon(); await initDaemon(); }); @@ -302,6 +313,7 @@ program .option("--port ", "Port to listen on") .option("-p, --provider ", "Default provider to use") .action(async (options: { port?: string; provider?: string }) => { + await requireLocalDaemon(); const config = await loadConfig(); if (!(await isCocodInstalled(config.cocodPath))) { const installHint = config.cocodPath @@ -1103,6 +1115,7 @@ serviceCmd .command("install") .description("Install and start routstrd using PM2 for persistence") .action(async () => { + await requireLocalDaemon(); // 1. Check if PM2 is installed try { execSync("pm2 -v", { stdio: "ignore" }); @@ -1184,6 +1197,7 @@ program .option("--port ", "Port to listen on") .option("-p, --provider ", "Default provider to use") .action(async (options: { port?: string; provider?: string }) => { + await requireLocalDaemon(); const config = await loadConfig(); const wasRunning = await isDaemonRunning(); @@ -1221,6 +1235,7 @@ program .command("mode") .description("Set the client mode (lazyrefund/apikeys or xcashu)") .action(async () => { + await requireLocalDaemon(); const config = await loadConfig(); const currentMode = config.mode || "apikeys"; @@ -1311,6 +1326,7 @@ program .option("-f, --follow", "Follow log output", false) .option("-n, --lines ", "Number of lines to show", "50") .action(async (options: { follow: boolean; lines: string }) => { + await requireLocalDaemon(); const todayFile = getLogFileForDate(); const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); diff --git a/src/utils/config.ts b/src/utils/config.ts index 2a3be1e..4b613c8 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -12,6 +12,7 @@ export interface RoutstrdConfig { provider: string | null; cocodPath: string | null; mode?: "xcashu" | "apikeys"; + daemonUrl?: string; } export const DEFAULT_CONFIG: RoutstrdConfig = { diff --git a/src/utils/daemon-client.ts b/src/utils/daemon-client.ts index 838abb2..1ce13d6 100644 --- a/src/utils/daemon-client.ts +++ b/src/utils/daemon-client.ts @@ -23,14 +23,19 @@ export async function loadConfig(): Promise { return DEFAULT_CONFIG; } +function getDaemonBaseUrl(config: RoutstrdConfig): string { + return config.daemonUrl?.replace(/\/$/, "") || `http://localhost:${config.port}`; +} + export async function callDaemon( path: string, options: { method?: "GET" | "POST"; body?: object } = {}, ): Promise { const { method = "GET", body } = options; const config = await loadConfig(); + const baseUrl = getDaemonBaseUrl(config); - const response = await fetch(`http://localhost:${config.port}${path}`, { + const response = await fetch(`${baseUrl}${path}`, { method, headers: body ? { "Content-Type": "application/json" } : {}, body: body ? JSON.stringify(body) : undefined, @@ -47,7 +52,8 @@ export async function callDaemon( export async function isDaemonRunning(): Promise { try { const config = await loadConfig(); - const response = await fetch(`http://localhost:${config.port}/health`); + const baseUrl = getDaemonBaseUrl(config); + const response = await fetch(`${baseUrl}/health`); return response.ok; } catch { return false; @@ -84,6 +90,11 @@ export async function ensureDaemonRunning(): Promise { return; } + const config = await loadConfig(); + if (config.daemonUrl) { + throw new Error(`Daemon is not reachable at ${config.daemonUrl}`); + } + console.log("Starting daemon..."); await startDaemonProcess(); }