refactor(shared): reuse node list parsers across cli and tools

This commit is contained in:
Peter Steinberger
2026-02-18 23:32:37 +00:00
parent 3b7c8fe79a
commit b366279030
4 changed files with 44 additions and 31 deletions

View File

@@ -1,26 +1,10 @@
import type {
NodeListNode,
PairedNode,
PairingList,
PendingRequest,
} from "../../shared/node-list-types.js";
import { parseNodeList, parsePairingList } from "../../shared/node-list-parse.js";
import type { NodeListNode } from "../../shared/node-list-types.js";
import { resolveNodeIdFromCandidates } from "../../shared/node-match.js";
import { callGatewayTool, type GatewayCallOptions } from "./gateway.js";
export type { NodeListNode };
function parseNodeList(value: unknown): NodeListNode[] {
const obj = typeof value === "object" && value !== null ? (value as Record<string, unknown>) : {};
return Array.isArray(obj.nodes) ? (obj.nodes as NodeListNode[]) : [];
}
function parsePairingList(value: unknown): PairingList {
const obj = typeof value === "object" && value !== null ? (value as Record<string, unknown>) : {};
const pending = Array.isArray(obj.pending) ? (obj.pending as PendingRequest[]) : [];
const paired = Array.isArray(obj.paired) ? (obj.paired as PairedNode[]) : [];
return { pending, paired };
}
async function loadNodes(opts: GatewayCallOptions): Promise<NodeListNode[]> {
try {
const res = await callGatewayTool("node.list", opts, {});

View File

@@ -1,16 +1,4 @@
import type { NodeListNode, PairedNode, PairingList, PendingRequest } from "./types.js";
export function parsePairingList(value: unknown): PairingList {
const obj = typeof value === "object" && value !== null ? (value as Record<string, unknown>) : {};
const pending = Array.isArray(obj.pending) ? (obj.pending as PendingRequest[]) : [];
const paired = Array.isArray(obj.paired) ? (obj.paired as PairedNode[]) : [];
return { pending, paired };
}
export function parseNodeList(value: unknown): NodeListNode[] {
const obj = typeof value === "object" && value !== null ? (value as Record<string, unknown>) : {};
return Array.isArray(obj.nodes) ? (obj.nodes as NodeListNode[]) : [];
}
export { parseNodeList, parsePairingList } from "../../shared/node-list-parse.js";
export function formatPermissions(raw: unknown) {
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {

View File

@@ -0,0 +1,24 @@
import { describe, expect, it } from "vitest";
import { parseNodeList, parsePairingList } from "./node-list-parse.js";
describe("shared/node-list-parse", () => {
it("parses node.list payloads", () => {
expect(parseNodeList({ nodes: [{ nodeId: "node-1" }] })).toEqual([{ nodeId: "node-1" }]);
expect(parseNodeList({ nodes: "nope" })).toEqual([]);
expect(parseNodeList(null)).toEqual([]);
});
it("parses node.pair.list payloads", () => {
expect(
parsePairingList({
pending: [{ requestId: "r1", nodeId: "n1", ts: 1 }],
paired: [{ nodeId: "n1" }],
}),
).toEqual({
pending: [{ requestId: "r1", nodeId: "n1", ts: 1 }],
paired: [{ nodeId: "n1" }],
});
expect(parsePairingList({ pending: 1, paired: "x" })).toEqual({ pending: [], paired: [] });
expect(parsePairingList(undefined)).toEqual({ pending: [], paired: [] });
});
});

View File

@@ -0,0 +1,17 @@
import type { NodeListNode, PairedNode, PairingList, PendingRequest } from "./node-list-types.js";
function asRecord(value: unknown): Record<string, unknown> {
return typeof value === "object" && value !== null ? (value as Record<string, unknown>) : {};
}
export function parsePairingList(value: unknown): PairingList {
const obj = asRecord(value);
const pending = Array.isArray(obj.pending) ? (obj.pending as PendingRequest[]) : [];
const paired = Array.isArray(obj.paired) ? (obj.paired as PairedNode[]) : [];
return { pending, paired };
}
export function parseNodeList(value: unknown): NodeListNode[] {
const obj = asRecord(value);
return Array.isArray(obj.nodes) ? (obj.nodes as NodeListNode[]) : [];
}