{"version":3,"file":"graph-normalizer-BA3Rbd6l.mjs","names":[],"sources":["../src/viz/graph-normalizer.ts"],"sourcesContent":["const GRAPH_TYPE_LABELS = new Set(['Address', 'Exchange', 'Miner', 'Validator', 'Hotkey', 'Subnet', 'IPAddress'])\nconst FLOW_EDGE_TYPES = new Set(['flows_to', 'transfer', 'transfer_to', 'transfers_to'])\n\ntype GraphRecord = Record<string, unknown>\n\nexport type NormalizedGraphPayload = {\n  schema: 'chain-insights.graph.v1'\n  nodes: GraphRecord[]\n  edges: GraphRecord[]\n  flows: unknown[]\n  edge_anchors: unknown[]\n  [key: string]: unknown\n}\n\nfunction isRecord(value: unknown): value is GraphRecord {\n  return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction stringArray(value: unknown): string[] {\n  return Array.isArray(value) ? value.map(String).filter(Boolean) : []\n}\n\nfunction unique(values: string[]): string[] {\n  return [...new Set(values)]\n}\n\nfunction lowerSnake(value: string): string {\n  return value\n    .trim()\n    .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n    .replace(/[^A-Za-z0-9]+/g, '_')\n    .replace(/^_+|_+$/g, '')\n    .toLowerCase()\n}\n\nfunction isGraphTypeLabel(label: string): boolean {\n  return GRAPH_TYPE_LABELS.has(label)\n}\n\nfunction displayLabels(node: GraphRecord): string[] {\n  return unique(stringArray(node['labels'])).filter((label) => !isGraphTypeLabel(label))\n}\n\nfunction systemLabels(node: GraphRecord): string[] {\n  return unique([\n    ...stringArray(node['system_labels']),\n    ...stringArray(node['graph_labels']),\n    ...stringArray(node['raw_labels']),\n    ...stringArray(node['labels']).filter(isGraphTypeLabel),\n  ])\n}\n\nfunction normalizeRoles(node: GraphRecord): string[] {\n  const roles = stringArray(node['roles'])\n  const role = typeof node['role'] === 'string' ? node['role'] : ''\n  if (role === 'source_exchange') roles.push('exchange')\n  else if (role) roles.push(role)\n\n  const display = stringArray(node['labels']).map(lowerSnake)\n  if (systemLabels(node).some((label) => lowerSnake(label) === 'exchange') || display.includes('exchange')) {\n    roles.push('exchange')\n  }\n\n  return unique(roles.map(lowerSnake).filter(Boolean))\n}\n\nfunction normalizeNodeType(node: GraphRecord): string {\n  if (typeof node['node_type'] === 'string' && node['node_type'].trim()) {\n    return lowerSnake(node['node_type'])\n  }\n  if (typeof node['address'] === 'string' || typeof node['id'] === 'string') return 'address'\n  const labels = systemLabels(node)\n  if (labels.length > 0) return lowerSnake(labels[0]!)\n  return 'unknown'\n}\n\nfunction normalizeNode(node: unknown): GraphRecord {\n  if (!isRecord(node)) return {}\n\n  const normalized: GraphRecord = {}\n  for (const [key, value] of Object.entries(node)) {\n    if (\n      [\n        'address_subtypes',\n        'entity_kind',\n        'graph_labels',\n        'labels',\n        'node_type',\n        'pattern_flags',\n        'raw_labels',\n        'role',\n        'roles',\n        'system_labels',\n        'type',\n      ].includes(key)\n    ) {\n      continue\n    }\n    normalized[key] = value\n  }\n\n  const id = typeof node['id'] === 'string' ? node['id'] : typeof node['address'] === 'string' ? node['address'] : undefined\n  if (id) normalized['id'] = id\n\n  const address = typeof node['address'] === 'string' ? node['address'] : id\n  if (address) normalized['address'] = address\n\n  normalized['node_type'] = normalizeNodeType(node)\n  normalized['labels'] = displayLabels(node)\n\n  const addressSubtypes = unique(stringArray(node['address_subtypes']))\n  if (addressSubtypes.length > 0) normalized['address_subtypes'] = addressSubtypes\n\n  const roles = normalizeRoles(node)\n  if (roles.length > 0) normalized['roles'] = roles\n\n  if (!Array.isArray(node['flags']) && Array.isArray(node['pattern_flags']) && node['pattern_flags'].length > 0) {\n    normalized['flags'] = node['pattern_flags'].map(String)\n  }\n\n  return normalized\n}\n\nfunction normalizeEdgeType(edge: GraphRecord): string {\n  const rawType =\n    typeof edge['edge_type'] === 'string' && edge['edge_type'].trim()\n      ? edge['edge_type']\n      : typeof edge['type'] === 'string' && edge['type'].trim()\n        ? edge['type']\n        : typeof edge['relationship_type'] === 'string' && edge['relationship_type'].trim()\n          ? edge['relationship_type']\n          : 'related_to'\n  const edgeType = lowerSnake(rawType)\n  return FLOW_EDGE_TYPES.has(edgeType) ? 'flows_to' : edgeType\n}\n\nfunction normalizeEdge(edge: unknown): GraphRecord {\n  if (!isRecord(edge)) return {}\n\n  const normalized: GraphRecord = {}\n  for (const [key, value] of Object.entries(edge)) {\n    if (['edge_type', 'from_address', 'relationship_type', 'to_address', 'type'].includes(key)) continue\n    normalized[key] = value\n  }\n\n  if (typeof normalized['source'] !== 'string' && typeof edge['from_address'] === 'string') {\n    normalized['source'] = edge['from_address']\n  }\n  if (typeof normalized['target'] !== 'string' && typeof edge['to_address'] === 'string') {\n    normalized['target'] = edge['to_address']\n  }\n  normalized['edge_type'] = normalizeEdgeType(edge)\n\n  return normalized\n}\n\nexport function normalizeGraphPayload(payload: unknown): NormalizedGraphPayload {\n  if (!isRecord(payload) || payload['schema'] !== 'chain-insights.graph.v1') {\n    throw new Error('Unsupported graph payload schema')\n  }\n\n  return {\n    ...payload,\n    schema: 'chain-insights.graph.v1',\n    nodes: Array.isArray(payload['nodes']) ? payload['nodes'].map(normalizeNode) : [],\n    edges: Array.isArray(payload['edges']) ? payload['edges'].map(normalizeEdge) : [],\n    flows: Array.isArray(payload['flows']) ? payload['flows'] : [],\n    edge_anchors: Array.isArray(payload['edge_anchors']) ? payload['edge_anchors'] : [],\n  }\n}\n"],"mappings":";AAAA,MAAM,oCAAoB,IAAI,IAAI;CAAC;CAAW;CAAY;CAAS;CAAa;CAAU;CAAU;AAAW,CAAC;AAChH,MAAM,kCAAkB,IAAI,IAAI;CAAC;CAAY;CAAY;CAAe;AAAc,CAAC;AAavF,SAAS,SAAS,OAAsC;CACtD,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,YAAY,OAA0B;CAC7C,OAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,OAAO,OAAO,IAAI,CAAC;AACrE;AAEA,SAAS,OAAO,QAA4B;CAC1C,OAAO,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC;AAC5B;AAEA,SAAS,WAAW,OAAuB;CACzC,OAAO,MACJ,KAAK,CAAC,CACN,QAAQ,sBAAsB,OAAO,CAAC,CACtC,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,QAAQ,YAAY,EAAE,CAAC,CACvB,YAAY;AACjB;AAEA,SAAS,iBAAiB,OAAwB;CAChD,OAAO,kBAAkB,IAAI,KAAK;AACpC;AAEA,SAAS,cAAc,MAA6B;CAClD,OAAO,OAAO,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,UAAU,CAAC,iBAAiB,KAAK,CAAC;AACvF;AAEA,SAAS,aAAa,MAA6B;CACjD,OAAO,OAAO;EACZ,GAAG,YAAY,KAAK,gBAAgB;EACpC,GAAG,YAAY,KAAK,eAAe;EACnC,GAAG,YAAY,KAAK,aAAa;EACjC,GAAG,YAAY,KAAK,SAAS,CAAC,CAAC,OAAO,gBAAgB;CACxD,CAAC;AACH;AAEA,SAAS,eAAe,MAA6B;CACnD,MAAM,QAAQ,YAAY,KAAK,QAAQ;CACvC,MAAM,OAAO,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;CAC/D,IAAI,SAAS,mBAAmB,MAAM,KAAK,UAAU;MAChD,IAAI,MAAM,MAAM,KAAK,IAAI;CAE9B,MAAM,UAAU,YAAY,KAAK,SAAS,CAAC,CAAC,IAAI,UAAU;CAC1D,IAAI,aAAa,IAAI,CAAC,CAAC,MAAM,UAAU,WAAW,KAAK,MAAM,UAAU,KAAK,QAAQ,SAAS,UAAU,GACrG,MAAM,KAAK,UAAU;CAGvB,OAAO,OAAO,MAAM,IAAI,UAAU,CAAC,CAAC,OAAO,OAAO,CAAC;AACrD;AAEA,SAAS,kBAAkB,MAA2B;CACpD,IAAI,OAAO,KAAK,iBAAiB,YAAY,KAAK,YAAY,CAAC,KAAK,GAClE,OAAO,WAAW,KAAK,YAAY;CAErC,IAAI,OAAO,KAAK,eAAe,YAAY,OAAO,KAAK,UAAU,UAAU,OAAO;CAClF,MAAM,SAAS,aAAa,IAAI;CAChC,IAAI,OAAO,SAAS,GAAG,OAAO,WAAW,OAAO,EAAG;CACnD,OAAO;AACT;AAEA,SAAS,cAAc,MAA4B;CACjD,IAAI,CAAC,SAAS,IAAI,GAAG,OAAO,CAAC;CAE7B,MAAM,aAA0B,CAAC;CACjC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,GAAG;EAC/C,IACE;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,CAAC,CAAC,SAAS,GAAG,GAEd;EAEF,WAAW,OAAO;CACpB;CAEA,MAAM,KAAK,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa,KAAA;CACjH,IAAI,IAAI,WAAW,QAAQ;CAE3B,MAAM,UAAU,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;CACxE,IAAI,SAAS,WAAW,aAAa;CAErC,WAAW,eAAe,kBAAkB,IAAI;CAChD,WAAW,YAAY,cAAc,IAAI;CAEzC,MAAM,kBAAkB,OAAO,YAAY,KAAK,mBAAmB,CAAC;CACpE,IAAI,gBAAgB,SAAS,GAAG,WAAW,sBAAsB;CAEjE,MAAM,QAAQ,eAAe,IAAI;CACjC,IAAI,MAAM,SAAS,GAAG,WAAW,WAAW;CAE5C,IAAI,CAAC,MAAM,QAAQ,KAAK,QAAQ,KAAK,MAAM,QAAQ,KAAK,gBAAgB,KAAK,KAAK,gBAAgB,CAAC,SAAS,GAC1G,WAAW,WAAW,KAAK,gBAAgB,CAAC,IAAI,MAAM;CAGxD,OAAO;AACT;AAEA,SAAS,kBAAkB,MAA2B;CASpD,MAAM,WAAW,WAPf,OAAO,KAAK,iBAAiB,YAAY,KAAK,YAAY,CAAC,KAAK,IAC5D,KAAK,eACL,OAAO,KAAK,YAAY,YAAY,KAAK,OAAO,CAAC,KAAK,IACpD,KAAK,UACL,OAAO,KAAK,yBAAyB,YAAY,KAAK,oBAAoB,CAAC,KAAK,IAC9E,KAAK,uBACL,YACyB;CACnC,OAAO,gBAAgB,IAAI,QAAQ,IAAI,aAAa;AACtD;AAEA,SAAS,cAAc,MAA4B;CACjD,IAAI,CAAC,SAAS,IAAI,GAAG,OAAO,CAAC;CAE7B,MAAM,aAA0B,CAAC;CACjC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,GAAG;EAC/C,IAAI;GAAC;GAAa;GAAgB;GAAqB;GAAc;EAAM,CAAC,CAAC,SAAS,GAAG,GAAG;EAC5F,WAAW,OAAO;CACpB;CAEA,IAAI,OAAO,WAAW,cAAc,YAAY,OAAO,KAAK,oBAAoB,UAC9E,WAAW,YAAY,KAAK;CAE9B,IAAI,OAAO,WAAW,cAAc,YAAY,OAAO,KAAK,kBAAkB,UAC5E,WAAW,YAAY,KAAK;CAE9B,WAAW,eAAe,kBAAkB,IAAI;CAEhD,OAAO;AACT;AAEA,SAAgB,sBAAsB,SAA0C;CAC9E,IAAI,CAAC,SAAS,OAAO,KAAK,QAAQ,cAAc,2BAC9C,MAAM,IAAI,MAAM,kCAAkC;CAGpD,OAAO;EACL,GAAG;EACH,QAAQ;EACR,OAAO,MAAM,QAAQ,QAAQ,QAAQ,IAAI,QAAQ,QAAQ,CAAC,IAAI,aAAa,IAAI,CAAC;EAChF,OAAO,MAAM,QAAQ,QAAQ,QAAQ,IAAI,QAAQ,QAAQ,CAAC,IAAI,aAAa,IAAI,CAAC;EAChF,OAAO,MAAM,QAAQ,QAAQ,QAAQ,IAAI,QAAQ,WAAW,CAAC;EAC7D,cAAc,MAAM,QAAQ,QAAQ,eAAe,IAAI,QAAQ,kBAAkB,CAAC;CACpF;AACF"}