{"mappings":";AAQA,OAAO,SAAS,iBAAiB,OAA+B;AAC9D,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI;EACF,MAAM,MAAM,IAAI,IAAI,MAAM,MAAM,CAAC;AACjC,MAAI,CAAC,CAAC,UAAU,QAAQ,CAAC,SAAS,IAAI,SAAS,IAAI,IAAI,YAAY,IAAI,SAAU,QAAO;AACxF,SAAO,IAAI;SACL;AACN,SAAO;;;AAIX,SAAS,UAAU,KAAa,MAAgB,OAAyB;CACvE,MAAM,OAAO,IAAI,IAAI,IAAI,CAAC,SAAS,QAAQ,UAAU,GAAG;;AAExD,KAAI;EAAC;EAAS;EAAe;EAAqB,CAAC,SAAS,KAAK,CAAE,QAAO;AAC1E,KAAI;EAAC;EAAQ;EAAe;EAAe,CAAC,SAAS,KAAK,CAAE,QAAO;AACnE,KAAI;EAAC;EAAc;EAAe;EAAiB,CAAC,SAAS,KAAK,CAAE,QAAO;AAC3E,KAAI,CAAC,gBAAgB,gBAAgB,CAAC,SAAS,KAAK,CAAE,QAAO;AAC7D,KAAI,SAAS,aAAc,QAAO;AAClC,KAAI,SAAS,UAAW,QAAO;AAC/B,QAAO,OAAO,UAAU,YAAY,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,GAAG,GAAG,GAAG;;AAGjF,OAAO,SAAS,mBAAmB,MAA8D;CAC/F,MAAM,QAA6B,EAAE;CACrC,MAAM,OAAO,IAAI,KAAa;CAC9B,SAAS,IAAI,OAAgB,MAAgB,OAAiB;EAC5D,MAAM,MAAM,iBAAiB,MAAM;AACnC,MAAI,CAAC,IAAK;EACV,MAAM,MAAM,IAAI,QAAQ,OAAO,GAAG;AAClC,MAAI,KAAK,IAAI,IAAI,CAAE;AACnB,OAAK,IAAI,IAAI;AACb,QAAM,KAAK;GAAE;GAAK,OAAO,UAAU,KAAK,MAAM,MAAM;GAAE,CAAC;;AAEzD,KAAI,KAAK,SAAS,UAAU;AAC5B,KAAI,MAAM,QAAQ,KAAK,QAAQ,EAAE;AAC/B,OAAK,MAAM,UAAU,KAAK,SAAS;AACjC,OAAI,UAAU,OAAO,WAAW,SAAU,KAAI,OAAO,KAAK,OAAO,MAAM,OAAO,MAAM;;YAE7E,KAAK,WAAW,OAAO,KAAK,YAAY,UAAU;AAC3D,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,QAAQ,EAAE;AACvD,OAAI,OAAO,QAAQ,YAAY,YAAY,UAAU;;;AAGzD,QAAO;;AAGT,OAAO,SAAS,iBAAiB,OAAwB;AACvD,QAAO,OAAO,UAAU,WAAW,MAAM,MAAM,CAAC,MAAM,GAAG,KAAK,GAAG;;;;AAKnE,MAAM,iBAAiB,IAAI,IAAoB;CAC7C,CAAC,QAAQ,wBAAwB;CACjC,CAAC,QAAQ,8BAA8B;CACvC,CAAC,WAAW,8BAA8B;CAC1C,CAAC,WAAW,8BAA8B;CAC1C,CAAC,QAAQ,qBAAqB;CAC9B,CAAC,WAAW,sBAAsB;CAClC,CAAC,SAAS,qBAAqB;CAC/B,CAAC,WAAW,uBAAuB;CACnC,CAAC,SAAS,6BAA6B;CACvC,CAAC,kBAAkB,0BAA0B;CAC7C,CAAC,cAAc,yBAAyB;CACzC,CAAC;AAEF,OAAO,SAAS,aAAa,MAAkC;AAC7D,QAAO,eAAe,IAAI,KAAK,MAAM,CAAC,aAAa,CAAC","names":[],"sources":["/assets/app/actions/public/token-metadata.ts"],"version":3,"sourcesContent":["import type { Pair } from './market.ts'\n\nexport interface TokenMetadataLink {\n  label: string\n  url: string\n}\n\n/** Creator links are text/URLs, never markup or executable schemes. */\nexport function externalTokenUrl(value: unknown): string | null {\n  if (typeof value !== 'string') return null\n  try {\n    const url = new URL(value.trim())\n    if (!['https:', 'http:'].includes(url.protocol) || url.username || url.password) return null\n    return url.href\n  } catch {\n    return null\n  }\n}\n\nfunction linkLabel(url: string, type?: unknown, label?: unknown): string {\n  const host = new URL(url).hostname.replace(/^www\\./, '')\n  // Older records may incorrectly label a social profile as \"Website\".\n  if (['x.com', 'twitter.com', 'mobile.twitter.com'].includes(host)) return 'X'\n  if (['t.me', 'telegram.me', 'telegram.org'].includes(host)) return 'Telegram'\n  if (['discord.gg', 'discord.com', 'discordapp.com'].includes(host)) return 'Discord'\n  if (['warpcast.com', 'farcaster.xyz'].includes(host)) return 'Farcaster'\n  if (host === 'github.com') return 'GitHub'\n  if (type === 'website') return 'Website'\n  return typeof label === 'string' && label.trim() ? label.trim().slice(0, 48) : host\n}\n\nexport function tokenMetadataLinks(pair: Pick<Pair, 'website' | 'socials'>): TokenMetadataLink[] {\n  const links: TokenMetadataLink[] = []\n  const seen = new Set<string>()\n  function add(value: unknown, type?: unknown, label?: unknown) {\n    const url = externalTokenUrl(value)\n    if (!url) return\n    const key = url.replace(/\\/$/, '')\n    if (seen.has(key)) return\n    seen.add(key)\n    links.push({ url, label: linkLabel(url, type, label) })\n  }\n  add(pair.website, 'website')\n  if (Array.isArray(pair.socials)) {\n    for (const social of pair.socials) {\n      if (social && typeof social === 'object') add(social.url, social.type, social.label)\n    }\n  } else if (pair.socials && typeof pair.socials === 'object') {\n    for (const [key, value] of Object.entries(pair.socials)) {\n      add(value, key === 'website' ? 'website' : undefined)\n    }\n  }\n  return links\n}\n\nexport function tokenDescription(value: unknown): string {\n  return typeof value === 'string' ? value.trim().slice(0, 4096) : ''\n}\n\n// Platform URLs from research/codex-launchpad-research.md and official sites.\n// Match known names only; API labels must never become arbitrary link targets.\nconst LAUNCHPAD_URLS = new Map<string, string>([\n  ['long', 'https://app.long.xyz/'],\n  ['pons', 'https://www.ponsfamily.com/'],\n  ['pons v1', 'https://www.ponsfamily.com/'],\n  ['pons v2', 'https://www.ponsfamily.com/'],\n  ['pair', 'https://pair.fund/'],\n  ['longbow', 'https://longbow.gg/'],\n  ['lunch', 'https://lunch.fun/'],\n  ['doppler', 'https://doppler.lol/'],\n  ['bankr', 'https://bankr.bot/launches'],\n  ['launchpad.meme', 'https://launchpad.meme/'],\n  ['launch.win', 'https://launchwin.app/'],\n])\n\nexport function launchpadUrl(name: string): string | undefined {\n  return LAUNCHPAD_URLS.get(name.trim().toLowerCase())\n}\n"]}