mirror of
https://github.com/Routstr/routstrd.git
synced 2026-10-05 20:38:22 +00:00
feat(providers): show manual enable/disable status and add nostr-sync command
- providers list now shows the source of a provider's state: DISABLED (manual), DISABLED (nostr review), or enabled (manual override) - new 'routstrd providers nostr-sync <indices...>' command clears manual enable/disable overrides via POST /providers/nostr-sync, returning the provider to its kind-38425 review-based state, and reports the resulting enabled/disabled verdict
This commit is contained in:
+52
-1
@@ -1152,6 +1152,8 @@ providersCmd
|
||||
index: number;
|
||||
baseUrl: string;
|
||||
disabled: boolean;
|
||||
manuallyDisabled?: boolean;
|
||||
manuallyEnabled?: boolean;
|
||||
}>;
|
||||
disabledCount: number;
|
||||
totalCount: number;
|
||||
@@ -1167,7 +1169,13 @@ providersCmd
|
||||
`Providers (${output.totalCount} total, ${output.disabledCount} disabled):\n`,
|
||||
);
|
||||
for (const provider of output.providers) {
|
||||
const status = provider.disabled ? "DISABLED" : "enabled ";
|
||||
const status = provider.manuallyDisabled
|
||||
? "DISABLED (manual) "
|
||||
: provider.disabled
|
||||
? "DISABLED (nostr review) "
|
||||
: provider.manuallyEnabled
|
||||
? "enabled (manual override)"
|
||||
: "enabled ";
|
||||
console.log(` [${provider.index}] ${status} ${provider.baseUrl}`);
|
||||
}
|
||||
});
|
||||
@@ -1246,6 +1254,49 @@ providersCmd
|
||||
}
|
||||
});
|
||||
|
||||
providersCmd
|
||||
.command("nostr-sync <indices...>")
|
||||
.description(
|
||||
"Remove manual enable/disable overrides and return providers to their Nostr review-based state (e.g., routstrd providers nostr-sync 0 2 5)",
|
||||
)
|
||||
.action(async (indices: string[]) => {
|
||||
await ensureDaemonRunning();
|
||||
|
||||
const indexNums = indices
|
||||
.map((s) => parseInt(s, 10))
|
||||
.filter((n) => Number.isFinite(n));
|
||||
if (indexNums.length === 0) {
|
||||
console.log("No valid indices provided.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const result = await callDaemon("/providers/nostr-sync", {
|
||||
method: "POST",
|
||||
body: { indices: indexNums },
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
console.log(result.error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const output = result.output as
|
||||
| {
|
||||
message: string;
|
||||
providers: Array<{ baseUrl: string; disabled: boolean }>;
|
||||
}
|
||||
| undefined;
|
||||
if (output) {
|
||||
console.log(output.message);
|
||||
for (const provider of output.providers) {
|
||||
const status = provider.disabled
|
||||
? "DISABLED (nostr review)"
|
||||
: "enabled";
|
||||
console.log(` - ${provider.baseUrl} -> ${status}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
providersCmd
|
||||
.command("reviews")
|
||||
.description(
|
||||
|
||||
@@ -1286,6 +1286,89 @@ export function createDaemonRequestHandler(deps: {
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method === "POST" && url.pathname === "/providers/nostr-sync") {
|
||||
try {
|
||||
const bodyText = await readBody(req);
|
||||
const body = bodyText ? JSON.parse(bodyText) : {};
|
||||
const indices = body.indices as number[] | undefined;
|
||||
|
||||
if (!Array.isArray(indices)) {
|
||||
res.writeHead(400, { "Content-Type": "application/json" });
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
error: "Missing or invalid 'indices' field (expected number[]).",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const state = deps.store.getState();
|
||||
const baseUrlsList: string[] = state.baseUrlsList || [];
|
||||
// Clearing both manual lists returns the provider to the
|
||||
// review-based state: the effective disabled set is the union of
|
||||
// disabledProviders (kind-38425 review sync) and the manual lists,
|
||||
// so with no manual entries the Nostr review verdict applies again.
|
||||
const manuallyDisabledProviders: string[] = [
|
||||
...(state.manuallyDisabledProviders || []),
|
||||
];
|
||||
const manuallyEnabledProviders: string[] = [
|
||||
...(state.manuallyEnabledProviders || []),
|
||||
];
|
||||
|
||||
const synced: string[] = [];
|
||||
for (const idx of indices) {
|
||||
if (
|
||||
typeof idx === "number" &&
|
||||
idx >= 0 &&
|
||||
idx < baseUrlsList.length
|
||||
) {
|
||||
const baseUrl = baseUrlsList[idx]!;
|
||||
const disabledPos = manuallyDisabledProviders.indexOf(baseUrl);
|
||||
if (disabledPos !== -1) {
|
||||
manuallyDisabledProviders.splice(disabledPos, 1);
|
||||
}
|
||||
const enabledPos = manuallyEnabledProviders.indexOf(baseUrl);
|
||||
if (enabledPos !== -1) {
|
||||
manuallyEnabledProviders.splice(enabledPos, 1);
|
||||
}
|
||||
synced.push(baseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
deps.store.getState().setManuallyDisabledProviders(manuallyDisabledProviders);
|
||||
deps.discoveryAdapter.setManuallyDisabledProviders(manuallyDisabledProviders);
|
||||
deps.store.getState().setManuallyEnabledProviders(manuallyEnabledProviders);
|
||||
deps.discoveryAdapter.setManuallyEnabledProviders(manuallyEnabledProviders);
|
||||
|
||||
// Report each synced provider's resulting state so the CLI can show
|
||||
// whether Nostr reviews now have it enabled or disabled. Read from
|
||||
// the discovery adapter (the source the router uses) after the
|
||||
// writes above; with both manual lists cleared, its disabled set is
|
||||
// exactly the review-based set.
|
||||
const reviewDisabled = new Set(
|
||||
deps.discoveryAdapter.getDisabledProviders() || [],
|
||||
);
|
||||
const resulting = synced.map((baseUrl) => ({
|
||||
baseUrl,
|
||||
disabled: reviewDisabled.has(baseUrl),
|
||||
}));
|
||||
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
output: {
|
||||
message: `Reverted ${synced.length} provider(s) to Nostr review-based state`,
|
||||
providers: resulting,
|
||||
},
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
res.writeHead(500, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify({ error: String(error) }));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Client management endpoints
|
||||
if (req.method === "GET" && url.pathname === "/clients") {
|
||||
try {
|
||||
@@ -1490,6 +1573,9 @@ export function createDaemonRequestHandler(deps: {
|
||||
const manuallyEnabled = new Set(
|
||||
state.manuallyEnabledProviders || [],
|
||||
);
|
||||
const manuallyDisabled = new Set(
|
||||
state.manuallyDisabledProviders || [],
|
||||
);
|
||||
const disabledProviders: string[] = [
|
||||
...new Set([
|
||||
...(state.disabledProviders || []),
|
||||
@@ -1501,6 +1587,8 @@ export function createDaemonRequestHandler(deps: {
|
||||
index,
|
||||
baseUrl,
|
||||
disabled: disabledProviders.includes(baseUrl),
|
||||
manuallyDisabled: manuallyDisabled.has(baseUrl),
|
||||
manuallyEnabled: manuallyEnabled.has(baseUrl),
|
||||
}));
|
||||
|
||||
// Only count disabled providers that are actually in the current list
|
||||
|
||||
Reference in New Issue
Block a user