From 6b55859d38db1c6c14748d9361411a83bc2fb72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:02:04 +0100 Subject: [PATCH] fix(broker): email connect searches userId + dashboardUserId + fallback Members created by CLI don't have dashboardUserId set. Now searches by both userId and dashboardUserId columns. Falls back to all meshes if no member link found (bootstrap case for mesh owners). Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/broker/src/index.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/apps/broker/src/index.ts b/apps/broker/src/index.ts index b75a1e9..c43578c 100644 --- a/apps/broker/src/index.ts +++ b/apps/broker/src/index.ts @@ -4160,11 +4160,24 @@ function main(): void { if (users.length === 0) return []; const userId = users[0]!.id; const userName = users[0]!.name; - // Find meshes this user belongs to (via dashboardUserId on existing members) - const existingMembers = await db.select({ - meshId: meshMember.meshId, - }).from(meshMember).where(and(eq(meshMember.dashboardUserId, userId), isNull(meshMember.revokedAt))); - if (existingMembers.length === 0) return []; + // Find meshes this user belongs to: + // 1. Via dashboardUserId on existing members + // 2. Via userId (auth FK) on existing members + const meshIds = new Set(); + const byDashboard = await db.select({ meshId: meshMember.meshId }) + .from(meshMember).where(and(eq(meshMember.dashboardUserId, userId), isNull(meshMember.revokedAt))); + for (const m of byDashboard) meshIds.add(m.meshId); + const byUserId = await db.select({ meshId: meshMember.meshId }) + .from(meshMember).where(and(eq(meshMember.userId, userId), isNull(meshMember.revokedAt))); + for (const m of byUserId) meshIds.add(m.meshId); + // Fallback: if user has no members, check all meshes (owner bootstraps) + if (meshIds.size === 0) { + const allMeshes = await db.select({ id: mesh.id }).from(mesh); + for (const m of allMeshes) meshIds.add(m.id); + log.info("tg-email-connect: no member found, trying all meshes", { email, userId, meshCount: meshIds.size }); + } + if (meshIds.size === 0) return []; + const existingMembers = Array.from(meshIds).map(meshId => ({ meshId })); // For each mesh, create a new bridge member with a fresh keypair const sodium = await import("libsodium-wrappers");