From 9418d0ee300c803da0f7182e58c859f9d5719723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Sat, 2 May 2026 02:27:50 +0100 Subject: [PATCH] fix(api): dedupe /v1/peers by member (one row per active session) --- packages/api/src/modules/mesh/v1-router.ts | 29 ++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/api/src/modules/mesh/v1-router.ts b/packages/api/src/modules/mesh/v1-router.ts index 5c1513b..a1aa155 100644 --- a/packages/api/src/modules/mesh/v1-router.ts +++ b/packages/api/src/modules/mesh/v1-router.ts @@ -240,21 +240,46 @@ export const v1Router = new Hono() ) // GET /v1/peers — connected peers in the key's mesh + // Dedupe by memberId — a member can have multiple active presence + // rows (one per session). Status reflects the most recent presence; + // summary/groups come from the latest row. .get("/peers", async (c) => { const key = c.var.apiKey; requireCapability(key, "read"); const rows = await db .select({ + memberId: meshMember.id, pubkey: meshMember.peerPubkey, displayName: meshMember.displayName, status: presence.status, summary: presence.summary, groups: presence.groups, + connectedAt: presence.connectedAt, }) .from(presence) .innerJoin(meshMember, eq(presence.memberId, meshMember.id)) .where( and(eq(meshMember.meshId, key.meshId), isNull(presence.disconnectedAt)), - ); - return c.json({ peers: rows }); + ) + .orderBy(desc(presence.connectedAt)); + const seen = new Set(); + const peers: Array<{ + pubkey: string; + displayName: string; + status: string; + summary: string | null; + groups: unknown; + }> = []; + for (const r of rows) { + if (seen.has(r.memberId)) continue; + seen.add(r.memberId); + peers.push({ + pubkey: r.pubkey, + displayName: r.displayName, + status: r.status, + summary: r.summary, + groups: r.groups, + }); + } + return c.json({ peers }); });