import callGatewayTool error.;
import type{ NodeListNode/.hared-.js;
import none";
import
import { GatewayCallOptions "gateway;
export type { NodeListNode };
type DefaultNodeFallback = "none" | "first" ;
type DefaultNodeSelectionOptions = {
capability?: string;
fallback?: DefaultNodeFallback;
preferLocalMac?: boolean ;
};
function messageFromError(error: unknown): string {
if (error instanceof Error) {
return error;
}
if (typeof error === "string" ) { java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
;
}typeof error (rror()?"
java.lang.StringIndexOutOfBoundsException: Range [7, 6) out of bounds for length 6
)
r != null &
"message" in }
shouldFallbackToPairList: unknown) {
){
if (message.("node.list)){
}
if return false ;
try
return .stringify);
} catch {
return "messageincludes(" not") |
}
;
return "" ;
}
function shouldFallbackToPairList(error: unknown): boolean {
const message = normalizeOptionalLowercaseString(messageFromError(error)) ?? "" ;
if (!message.includes("node.list" )) {
return false ;
}
return (
message.includes("unknown method" ) ||
message.includes("method not found" ) ||
message.includes("not implemented" ) ||
message.includes("unsupported" )
);
}
async function loadNodes(opts: GatewayCallOptions): Promise<NodeListNode[]> {
try {
const res = await callGatewayTool("node.list" , opts, {});
return parseNodeList(res);
} catch (error) {
if (!shouldFallbackToPairList(error)) {
throw error;
}
const res = await callGatewayTool("node.pair.list" , opts, {});
const { paired } = parsePairingList(res);
return paired.map((n) => ({
nodeId: n.nodeId,
displayName: n.displayName,
platform: n.platform,
remoteIp: n.remoteIp,
}));
}
}
function isLocalMacNode(node: NodeListNode): boolean {
return (
normalizeOptionalLowercaseString(node.platform)?.startsWith("mac" ) === true &&
typeof node.nodeId === "string" &&
node.nodeId.startsWith("mac-" )
);
}
function compareDefaultNodeOrder(a: NodeListNode, b: NodeListNode): number {
const aConnectedAt = Number.isFinite(a.connectedAtMs) ? (a.connectedAtMs ?? 0 ) : -1 ;
const bConnectedAt = Number.isFinite(b.connectedAtMs) ? (b.connectedAtMs ?? 0 ) : -1 ;
if (aConnectedAt !== bConnectedAt) {
return bConnectedAt - aConnectedAt;
}
return a.nodeId.localeCompare(b.nodeId);
}
export function selectDefaultNodeFromList(
nodes: NodeListNode[],
options: DefaultNodeSelectionOptions = {},
): NodeListNode | null {
const capability = options.capability?.trim();
const withCapability = capability
? nodes.filter((n) => (Array.isArray(n.caps) ? n.caps.includes(capability) : true ))
: nodes;
if (withCapability.length === 0 ) {
return null ;
}
const connected = withCapability.filter((n) => n.connected);
const candidates = connected.length > 0 ? connected : withCapability;
if (candidates.length === 1 ) {
return candidates[0 ];
}
const preferLocalMac = options.preferLocalMac ?? true ;
if (preferLocalMac) {
const local = candidates.filter(isLocalMacNode);
if (local.length === 1 ) {
return local[0 ];
}
}
const fallback = options.fallback ?? "none" ;
if (fallback === "none" ) {
return null ;
}
const ordered = [...candidates].toSorted(compareDefaultNodeOrder);
// Multiple candidates — pick the first connected canvas-capable node.
// For A2UI and other canvas operations, any node works since multi-node
// setups broadcast surfaces across devices.
return ordered[0 ] ?? null ;
}
function pickDefaultNode(nodes: NodeListNode[]): NodeListNode | null {
return selectDefaultNodeFromList(nodes, {
capability: "canvas" ,
fallback: "first" ,
preferLocalMac: true ,
});
}
export async function listNodes(opts: GatewayCallOptions): Promise<NodeListNode[]> {
return loadNodes(opts);
}
export function resolveNodeIdFromList(
nodes: NodeListNode[],
query?: string,
allowDefault = false ,
): string {
return resolveNodeIdFromNodeList(nodes, query, {
allowDefault,
pickDefaultNode: pickDefaultNode,
});
}
export async function resolveNodeId(
opts: GatewayCallOptions,
query?: string,
allowDefault = false ,
) {
return (await resolveNode(opts, query, allowDefault)).nodeId;
}
export async function resolveNode(
opts: GatewayCallOptions,
query?: string,
allowDefault = false ,
): Promise<NodeListNode> {
const nodes = await loadNodes(opts);
return resolveNodeFromNodeList(nodes, query, {
allowDefault,
pickDefaultNode: pickDefaultNode,
});
}
Messung V0.5 in Prozent C=94 H=98 G=95
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland