From 5d019566f38e16f4be2430e50d3ae5df7b0c6a0f Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Wed, 11 Mar 2026 20:07:56 -0700 Subject: [PATCH] fix(rnetwork): trust data renders for spaces without CRM token - Restructure graph API so trust enrichment runs regardless of whether Twenty CRM token is configured (demo space has no CRM token) - Add missing listActiveDelegations import in encryptid server Co-Authored-By: Claude Opus 4.6 --- modules/rnetwork/mod.ts | 122 ++++++++++++++-------------------------- src/encryptid/server.ts | 1 + 2 files changed, 43 insertions(+), 80 deletions(-) diff --git a/modules/rnetwork/mod.ts b/modules/rnetwork/mod.ts index e8b1d87..4274ac1 100644 --- a/modules/rnetwork/mod.ts +++ b/modules/rnetwork/mod.ts @@ -199,95 +199,57 @@ routes.get("/api/graph", async (c) => { return c.json(cached.data); } - if (!token) { - return c.json({ - nodes: [ + try { + // Start with CRM data if available, otherwise demo placeholders + const nodes: Array<{ id: string; label: string; type: string; data: unknown }> = []; + const edges: Array<{ source: string; target: string; type: string; weight?: number }> = []; + const nodeIds = new Set(); + let isDemoData = false; + + if (!token) { + isDemoData = true; + nodes.push( { id: "demo-1", label: "Alice", type: "person", data: {} }, { id: "demo-2", label: "Bob", type: "person", data: {} }, { id: "demo-3", label: "Acme Corp", type: "company", data: {} }, - ], - edges: [ + ); + edges.push( { source: "demo-1", target: "demo-3", type: "works_at" }, { source: "demo-2", target: "demo-3", type: "works_at" }, { source: "demo-1", target: "demo-2", type: "contact_of" }, - ], - demo: true, - }); - } - - try { - const data = await twentyQuery(`{ - people(first: 200) { - edges { - node { - id - name { firstName lastName } - emails { primaryEmail } - city - company { id name } - } + ); + for (const n of nodes) nodeIds.add(n.id); + } else { + const data = await twentyQuery(`{ + people(first: 200) { + edges { node { id name { firstName lastName } emails { primaryEmail } city company { id name } } } } - } - companies(first: 200) { - edges { - node { - id - name - domainName { primaryLinkUrl } - employees - address { addressCity addressCountry } - } + companies(first: 200) { + edges { node { id name domainName { primaryLinkUrl } employees address { addressCity addressCountry } } } } - } - opportunities(first: 200) { - edges { - node { - id - name - stage - amount { amountMicros currencyCode } - company { id name } - pointOfContact { id name { firstName lastName } } - } + opportunities(first: 200) { + edges { node { id name stage amount { amountMicros currencyCode } company { id name } pointOfContact { id name { firstName lastName } } } } } - } - }`, undefined, dataSpace); + }`, undefined, dataSpace); - if (!data) return c.json({ nodes: [], edges: [], error: "Twenty API error" }); - - const d = data as any; - const nodes: Array<{ id: string; label: string; type: string; data: unknown }> = []; - const edges: Array<{ source: string; target: string; type: string }> = []; - const nodeIds = new Set(); - - // People → nodes - for (const { node: p } of d.people?.edges || []) { - const label = [p.name?.firstName, p.name?.lastName].filter(Boolean).join(" ") || "Unknown"; - nodes.push({ id: p.id, label, type: "person", data: { email: p.emails?.primaryEmail, location: p.city } }); - nodeIds.add(p.id); - - // Person → Company edge - if (p.company?.id) { - edges.push({ source: p.id, target: p.company.id, type: "works_at" }); - } - } - - // Companies → nodes - for (const { node: co } of d.companies?.edges || []) { - nodes.push({ id: co.id, label: co.name || "Unknown", type: "company", data: { domain: co.domainName?.primaryLinkUrl, employees: co.employees, location: co.address?.addressCity } }); - nodeIds.add(co.id); - } - - // Opportunities → nodes + edges - for (const { node: opp } of d.opportunities?.edges || []) { - nodes.push({ id: opp.id, label: opp.name || "Opportunity", type: "opportunity", data: { stage: opp.stage, amount: opp.amount } }); - nodeIds.add(opp.id); - - if (opp.company?.id && nodeIds.has(opp.company.id)) { - edges.push({ source: opp.id, target: opp.company.id, type: "involves" }); - } - if (opp.pointOfContact?.id && nodeIds.has(opp.pointOfContact.id)) { - edges.push({ source: opp.pointOfContact.id, target: opp.id, type: "involved_in" }); + if (data) { + const d = data as any; + for (const { node: p } of d.people?.edges || []) { + const label = [p.name?.firstName, p.name?.lastName].filter(Boolean).join(" ") || "Unknown"; + nodes.push({ id: p.id, label, type: "person", data: { email: p.emails?.primaryEmail, location: p.city } }); + nodeIds.add(p.id); + if (p.company?.id) edges.push({ source: p.id, target: p.company.id, type: "works_at" }); + } + for (const { node: co } of d.companies?.edges || []) { + nodes.push({ id: co.id, label: co.name || "Unknown", type: "company", data: { domain: co.domainName?.primaryLinkUrl, employees: co.employees, location: co.address?.addressCity } }); + nodeIds.add(co.id); + } + for (const { node: opp } of d.opportunities?.edges || []) { + nodes.push({ id: opp.id, label: opp.name || "Opportunity", type: "opportunity", data: { stage: opp.stage, amount: opp.amount } }); + nodeIds.add(opp.id); + if (opp.company?.id && nodeIds.has(opp.company.id)) edges.push({ source: opp.id, target: opp.company.id, type: "involves" }); + if (opp.pointOfContact?.id && nodeIds.has(opp.pointOfContact.id)) edges.push({ source: opp.pointOfContact.id, target: opp.id, type: "involved_in" }); + } } } @@ -342,7 +304,7 @@ routes.get("/api/graph", async (c) => { } catch (e) { console.error("[Network] Trust enrichment error:", e); } } - const result = { nodes, edges, demo: false }; + const result = { nodes, edges, demo: isDemoData && !includeTrust }; graphCaches.set(cacheKey, { data: result, ts: Date.now() }); c.header("Cache-Control", "public, max-age=60"); return c.json(result); diff --git a/src/encryptid/server.ts b/src/encryptid/server.ts index 59e3c00..45718a3 100644 --- a/src/encryptid/server.ts +++ b/src/encryptid/server.ts @@ -105,6 +105,7 @@ import { getDelegation, listDelegationsFrom, listDelegationsTo, + listActiveDelegations, updateDelegation, revokeDelegation, getTotalDelegatedWeight,