feat: auto-refill no longer requires daemon restart

Changed startAutoRefillLoop to accept a config getter instead of a static
config object. The getter reads config from disk on every check cycle, so
CLI changes (nwc auto-refill on/off) take effect immediately.

- auto-refill.ts: config parameter replaced with getConfig() callback
- wallet/index.ts: always start loop when wallet exists, use getter
- daemon/index.ts: pass getAutoRefillConfig reading from disk sync
- config-store.ts: added loadDaemonConfigSync() for sync disk reads
- http/index.ts + cli.ts: removed 'Restart daemon to apply' messages
This commit is contained in:
redshift
2026-05-23 22:37:43 +08:00
parent b9d30b12a9
commit c98709e383
6 changed files with 61 additions and 30 deletions
+3 -9
View File
@@ -1309,13 +1309,9 @@ nwcCmd
});
}
// Validate the connection string format
const { validateConnectionString } = await import(
"./daemon/wallet/nwc-client"
);
const validation = validateConnectionString(connectionString);
if (!validation.valid) {
console.error(`Invalid NWC connection string: ${validation.error}`);
// Quick validation: must be nostr+walletconnect:// with a 64-char hex pubkey
if (!/^nostr\+walletconnect:\/\/[0-9a-fA-F]{64}\?relay=/.test(connectionString)) {
console.error("Invalid NWC connection string: expected nostr+walletconnect://<64-char-hex>?relay=...");
process.exit(1);
}
@@ -1387,7 +1383,6 @@ autoRefillCmd
cooldownMs: cooldownSec * 1000,
},
});
console.log("\nRun 'routstrd restart' to apply.");
});
autoRefillCmd
@@ -1398,7 +1393,6 @@ autoRefillCmd
method: "POST",
body: { enabled: false },
});
console.log("\nRun 'routstrd restart' to apply.");
});
// Stop
+13 -1
View File
@@ -1,5 +1,5 @@
import { mkdir } from "fs/promises";
import { existsSync } from "fs";
import { existsSync, readFileSync } from "fs";
import {
CONFIG_DIR,
CONFIG_FILE,
@@ -31,6 +31,18 @@ export async function loadDaemonConfig(): Promise<RoutstrdConfig> {
return DEFAULT_CONFIG;
}
export function loadDaemonConfigSync(): RoutstrdConfig {
try {
if (existsSync(CONFIG_FILE)) {
const content = readFileSync(CONFIG_FILE, "utf-8");
return { ...DEFAULT_CONFIG, ...JSON.parse(content) };
}
} catch (error) {
logger.error("Failed to load config:", error);
}
return DEFAULT_CONFIG;
}
export function saveDaemonConfig(config: RoutstrdConfig): void {
Bun.write(CONFIG_FILE, JSON.stringify(config, null, 2));
}
+1 -1
View File
@@ -558,7 +558,7 @@ export function createDaemonRequestHandler(deps: {
return {
output: {
message: `Auto-refill ${enabled ? "enabled" : "disabled"}. Restart daemon to apply.`,
message: `Auto-refill ${enabled ? "enabled" : "disabled"}.`,
autoRefill: config.nwc.autoRefill,
},
};
+16 -10
View File
@@ -26,12 +26,13 @@ function makeSdkLogger(prefix?: string): SdkLogger {
}
const daemonSdkLogger: SdkLogger = makeSdkLogger();
import { parseArgs } from "./args";
import { ensureDirs, loadDaemonConfig, saveDaemonConfig } from "./config-store";
import { ensureDirs, loadDaemonConfig, loadDaemonConfigSync, saveDaemonConfig } from "./config-store";
import {
createBunSqliteDriver,
createBunSqliteUsageTrackingDriver,
} from "@routstr/sdk/storage";
import { createWalletAdapter } from "./wallet";
import type { AutoRefillConfig } from "./wallet/auto-refill";
import { createCocodClient } from "./wallet/cocod-client";
import { createModelService } from "./models";
import { createDaemonRequestHandler } from "./http";
@@ -72,20 +73,25 @@ async function main(): Promise<void> {
const walletClient = createCocodClient({ cocodPath: config.cocodPath });
// ── Auto-refill configuration ────────────────────────────────
// Uses a getter that reads config from disk each cycle, so
// CLI changes take effect immediately without a daemon restart.
const nwcAutoRefill =
config.nwc?.autoRefill?.enabled && config.nwc?.connectionString
? {
threshold: config.nwc.autoRefill.threshold,
amount: config.nwc.autoRefill.amount,
cooldownMs: config.nwc.autoRefill.cooldownMs,
}
: undefined;
const getAutoRefillConfig = (): AutoRefillConfig | undefined => {
const cfg = loadDaemonConfigSync();
if (cfg.nwc?.autoRefill?.enabled && cfg.nwc?.connectionString) {
return {
threshold: cfg.nwc.autoRefill.threshold,
amount: cfg.nwc.autoRefill.amount,
cooldownMs: cfg.nwc.autoRefill.cooldownMs,
};
}
return undefined;
};
const walletAdapter = await createWalletAdapter({
cocodPath: config.cocodPath,
walletClient,
autoRefill: nwcAutoRefill,
getAutoRefillConfig,
nwcConnectionString: config.nwc?.connectionString,
});
+8 -1
View File
@@ -20,7 +20,7 @@ export interface AutoRefillConfig {
export function startAutoRefillLoop(
cocod: CocodClient,
wallet: WalletConnect,
config: AutoRefillConfig,
getConfig: () => AutoRefillConfig | undefined,
intervalMs: number = 5000,
): () => void {
let lastRefillAt = 0;
@@ -36,6 +36,13 @@ export function startAutoRefillLoop(
return;
}
// Read config fresh each cycle so changes apply without restart
const config = getConfig();
if (!config) {
// Auto-refill disabled
return;
}
const now = Date.now();
if (now - lastRefillAt < config.cooldownMs) {
return;
+20 -8
View File
@@ -22,8 +22,14 @@ export interface WalletAdapterOptions {
walletClient?: CocodClient;
/** NWC connection string for Lightning funding (uses applesauce-wallet-connect) */
nwcConnectionString?: string;
/** Auto-refill configuration */
/** Auto-refill configuration (static, for startup only) */
autoRefill?: AutoRefillConfig;
/**
* Config getter called on every check cycle to allow live updates.
* Return undefined to disable auto-refill, or a config to use.
* When provided, this replaces the static `autoRefill` option.
*/
getAutoRefillConfig?: () => AutoRefillConfig | undefined;
}
export async function createWalletAdapter(
@@ -266,15 +272,21 @@ export async function createWalletAdapter(
let stopAutoRefill: (() => void) | undefined;
if (options.autoRefill && wallet) {
stopAutoRefill = startAutoRefillLoop(
client,
wallet,
options.autoRefill,
);
const autoRefillConfig = options.getAutoRefillConfig
? options.getAutoRefillConfig()
: options.autoRefill;
if (autoRefillConfig && wallet) {
const getConfig = options.getAutoRefillConfig ?? (() => options.autoRefill);
stopAutoRefill = startAutoRefillLoop(client, wallet, getConfig);
logger.log(
`[wallet] Auto-refill enabled: threshold=${options.autoRefill.threshold} sats, amount=${options.autoRefill.amount} sats, cooldown=${options.autoRefill.cooldownMs}ms`,
`[wallet] Auto-refill enabled: threshold=${autoRefillConfig.threshold} sats, amount=${autoRefillConfig.amount} sats, cooldown=${autoRefillConfig.cooldownMs}ms`,
);
} else if (wallet && options.getAutoRefillConfig) {
// Wallet exists but auto-refill is not currently enabled.
// Start the loop anyway so it can pick up changes without a restart.
stopAutoRefill = startAutoRefillLoop(client, wallet, options.getAutoRefillConfig);
logger.log("[wallet] Auto-refill loop started (currently disabled — enable via CLI to activate)");
}
try {