erc8004-identity-viewer / tree / app.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
// The page: reads the form, calls loadAgent and renders the result with textContent only (no HTML injection).
import { loadAgent, httpRpc, httpFetchJson, resolveUri, REGISTRIES } from './viewer.js';
import { DEFAULT_IPFS_GATEWAY } from './config.js';

const $ = (id) => document.getElementById(id);
const el = (tag, props = {}, ...kids) => {
  const n = document.createElement(tag);
  for (const [k, v] of Object.entries(props)) if (v != null) n[k] = v;
  for (const k of kids) n.append(k instanceof Node ? k : document.createTextNode(String(k)));
  return n;
};
const short = (a) => (a && a.length > 14 ? `${a.slice(0, 8)}...${a.slice(-6)}` : a || '');
const safeHttp = (u) => (/^https?:\/\//i.test(u || '') ? u : null);
const safeImg = (u, gw) => {
  const r = resolveUri(u, gw);
  return /^https:\/\//i.test(r || '') || /^data:image\/(png|jpe?g|gif|webp|svg\+xml);/i.test(r || '') ? r : null;
};

$('registries').textContent = Object.entries(REGISTRIES).map(([k, v]) => `${k} identity ${short(v.identity)}, reputation ${short(v.reputation)}`).join('; ');

function render(r, net, gw) {
  const box = $('result');
  box.replaceChildren();
  const label = { ok: 'Found', empty: 'No such agent', error: 'Could not load' }[r.status];
  const head = el('div', { className: 'card' }, el('div', { className: `status ${r.status}` }, `${label}: agent ${r.agentId ?? ''} on ${net}`));
  if (r.error) head.append(el('p', {}, r.error));
  box.append(head);
  if (r.status === 'empty' || !r.owner) return;

  const explorer = REGISTRIES[net]?.explorer;
  const reg = r.registration;
  const id = el('div', { className: 'card' });
  const top = el('div', { className: 'agent' });
  const img = reg && safeImg(reg.image, gw);
  if (img) {
    const pic = el('img', { src: img, alt: '', loading: 'lazy', referrerPolicy: 'no-referrer' });
    pic.onerror = () => pic.remove();
    top.append(pic);
  }
  top.append(el('div', {}, el('h2', {}, reg?.name || 'Unnamed agent'), el('p', {}, reg?.description || 'No description.')));
  id.append(top);
  const dl = el('dl');
  const ownerLink = explorer ? el('a', { href: `${explorer}/address/${r.owner}`, target: '_blank', rel: 'noopener' }, r.owner) : r.owner;
  dl.append(el('dt', {}, 'Owner'), el('dd', {}, ownerLink));
  dl.append(el('dt', {}, 'tokenURI'), el('dd', {}, r.tokenURI && r.tokenURI.startsWith('data:') ? `${r.tokenURI.slice(0, 40)}... (inline data)` : r.tokenURI || ''));
  if (reg) {
    dl.append(el('dt', {}, 'Supported trust'), el('dd', {}, reg.supportedTrust.length ? reg.supportedTrust.join(', ') : 'none declared'));
  }
  id.append(dl);
  if (reg) {
    id.append(el('h2', {}, 'Endpoints'));
    if (!reg.endpoints.length) id.append(el('p', { className: 'muted' }, 'No endpoints declared.'));
    else {
      const ul = el('ul');
      for (const e of reg.endpoints) {
        const href = safeHttp(e.endpoint);
        ul.append(el('li', {}, `${e.name || 'endpoint'}${e.version ? ` v${e.version}` : ''}: `, href ? el('a', { href, target: '_blank', rel: 'noopener nofollow' }, e.endpoint) : e.endpoint));
      }
      id.append(ul);
    }
  }
  box.append(id);

  const rep = el('div', { className: 'card' }, el('h2', {}, 'Reputation'));
  const f = r.feedback;
  if (!f) rep.append(el('p', { className: 'muted' }, 'No reputation registry configured.'));
  else if (f.error) rep.append(el('p', { className: 'status error' }, f.error));
  else if (!f.count) rep.append(el('p', {}, 'This agent has no feedback yet.'));
  else {
    rep.append(el('p', {}, `${f.count} feedback entries, average score ${f.average}.`));
    const t = el('table', {}, el('thead', {}, el('tr', {}, el('th', {}, 'Client'), el('th', {}, 'Score'), el('th', {}, 'Tags'))));
    const tb = el('tbody');
    for (const i of f.items) {
      const tags = el('td');
      for (const tag of i.tags) tags.append(el('span', { className: 'tag' }, tag));
      tb.append(el('tr', {}, el('td', {}, short(i.client)), el('td', {}, String(i.score)), tags));
    }
    t.append(tb);
    rep.append(el('p', { className: 'muted' }, 'Latest entries:'), t);
  }
  box.append(rep);
}

async function show(net, agentId, rpcUrl, gateway) {
  const cfg = REGISTRIES[net];
  const gw = gateway || DEFAULT_IPFS_GATEWAY;
  $('result').replaceChildren(el('div', { className: 'card muted' }, 'Loading...'));
  const r = await loadAgent({
    agentId, network: net, identityRegistry: cfg.identity, reputationRegistry: cfg.reputation,
    rpc: httpRpc(rpcUrl || cfg.rpcUrl), fetchJson: httpFetchJson(), ipfsGateway: gw,
  });
  render(r, net, gw);
}

$('lookup').addEventListener('submit', (ev) => {
  ev.preventDefault();
  const net = $('network').value, id = $('agentId').value.trim();
  const u = new URL(location.href);
  u.searchParams.set('network', net); u.searchParams.set('agent', id);
  history.replaceState(null, '', u);
  show(net, id, $('rpcUrl').value.trim(), $('gateway').value.trim());
});

const q = new URLSearchParams(location.search);
if (q.get('network') && REGISTRIES[q.get('network')]) $('network').value = q.get('network');
if (q.get('agent')) { $('agentId').value = q.get('agent'); show($('network').value, q.get('agent'), '', ''); }

agentgate-source: code mirror on Cloudflare Pages. All repos