@@ -1316,13 +1316,39 @@ export function getRelationsById(chainId) {
13161316 * @param {number } maxDepth - Maximum traversal depth (default: 2)
13171317 * @returns {Object|null } Traversal result with nodes and edges, or null if chain not found
13181318 */
1319+ function collectRelationEdges ( chain , chainId , depth , visited , edges , queue , seenEdges ) {
1320+ const relations = chain . relations || [ ] ;
1321+ for ( const rel of relations ) {
1322+ if ( rel . chainId === undefined ) continue ;
1323+
1324+ // Deduplicate bidirectional edges (A→B and B→A with same kind) using O(1) Set lookup
1325+ const a = Math . min ( chainId , rel . chainId ) ;
1326+ const b = Math . max ( chainId , rel . chainId ) ;
1327+ const edgeKey = `${ a } -${ b } -${ rel . kind } ` ;
1328+ if ( ! seenEdges . has ( edgeKey ) ) {
1329+ seenEdges . add ( edgeKey ) ;
1330+ edges . push ( {
1331+ from : chainId ,
1332+ to : rel . chainId ,
1333+ kind : rel . kind ,
1334+ source : rel . source
1335+ } ) ;
1336+ }
1337+
1338+ if ( ! visited . has ( rel . chainId ) ) {
1339+ queue . push ( { chainId : rel . chainId , depth : depth + 1 } ) ;
1340+ }
1341+ }
1342+ }
1343+
13191344export function traverseRelations ( startChainId , maxDepth = 2 ) {
13201345 if ( ! cachedData . indexed ) return null ;
13211346
13221347 const startChain = cachedData . indexed . byChainId [ startChainId ] ;
13231348 if ( ! startChain ) return null ;
13241349
13251350 const visited = new Set ( ) ;
1351+ const seenEdges = new Set ( ) ;
13261352 const queue = [ { chainId : startChainId , depth : 0 } ] ;
13271353 const nodes = [ ] ;
13281354 const edges = [ ] ;
@@ -1342,28 +1368,8 @@ export function traverseRelations(startChainId, maxDepth = 2) {
13421368 depth
13431369 } ) ;
13441370
1345- if ( depth >= maxDepth ) continue ;
1346-
1347- const relations = chain . relations || [ ] ;
1348- for ( const rel of relations ) {
1349- if ( rel . chainId === undefined ) continue ;
1350-
1351- // Deduplicate bidirectional edges (A→B and B→A with same kind)
1352- const a = Math . min ( chainId , rel . chainId ) ;
1353- const b = Math . max ( chainId , rel . chainId ) ;
1354- const isDuplicate = edges . some ( e => Math . min ( e . from , e . to ) === a && Math . max ( e . from , e . to ) === b && e . kind === rel . kind ) ;
1355- if ( ! isDuplicate ) {
1356- edges . push ( {
1357- from : chainId ,
1358- to : rel . chainId ,
1359- kind : rel . kind ,
1360- source : rel . source
1361- } ) ;
1362- }
1363-
1364- if ( ! visited . has ( rel . chainId ) ) {
1365- queue . push ( { chainId : rel . chainId , depth : depth + 1 } ) ;
1366- }
1371+ if ( depth < maxDepth ) {
1372+ collectRelationEdges ( chain , chainId , depth , visited , edges , queue , seenEdges ) ;
13671373 }
13681374 }
13691375
0 commit comments