{"version":3,"file":"farcaster.mjs","names":[],"sources":["../../../src/tools/farcaster.ts"],"sourcesContent":["/**\n * Farcaster Tool — social actions on the Farcaster protocol via Neynar API.\n *\n * Actions:\n *   post        — Publish a cast\n *   feed        — Get a user's casts or home feed\n *   search      — Search casts by keyword\n *   user        — Get user profile info\n *   channel     — Get channel info and casts\n *   trending    — Get trending casts\n *   like        — Like a cast\n *   recast      — Recast (retweet equivalent)\n *   follow      — Follow a user\n *   unfollow    — Unfollow a user\n *\n * Uses Neynar API (api.neynar.com). Requires NEYNAR_API_KEY env var.\n * Mirrors the structure of the ClawnX (X/Twitter) tool.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, errorResult, readStringParam, readNumberParam } from '../lib/tool-helpers.js';\nimport { guardedFetch } from '../services/endpoint-allowlist.js';\nimport { checkToolConfig } from '../services/tool-config-service.js';\nimport { getCredentialVault } from '../services/credential-vault.js';\n\nconst ACTIONS = [\n  'post', 'feed', 'search', 'user', 'channel',\n  'trending', 'like', 'recast', 'follow', 'unfollow',\n] as const;\n\nconst FarcasterSchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description:\n      'post: publish a cast. feed: get user/home feed. search: search casts. ' +\n      'user: get profile. channel: channel info + casts. trending: trending casts. ' +\n      'like/recast: engage with cast. follow/unfollow: manage follows.',\n  }),\n  text: Type.Optional(Type.String({\n    description: 'Cast text content. Required for post. Max 320 characters.',\n  })),\n  username: Type.Optional(Type.String({\n    description: 'Farcaster username (without @). Used for feed/user/follow/unfollow.',\n  })),\n  fid: Type.Optional(Type.Number({\n    description: 'Farcaster ID (numeric). Alternative to username.',\n  })),\n  query: Type.Optional(Type.String({\n    description: 'Search query. Required for search action.',\n  })),\n  channel_id: Type.Optional(Type.String({\n    description: 'Channel ID (e.g. \"base\", \"farcaster\", \"memes\"). Required for channel action.',\n  })),\n  cast_hash: Type.Optional(Type.String({\n    description: 'Cast hash for like/recast actions.',\n  })),\n  parent_hash: Type.Optional(Type.String({\n    description: 'Parent cast hash for replying. Optional for post.',\n  })),\n  parent_url: Type.Optional(Type.String({\n    description: 'Channel URL for posting to a channel. Optional for post.',\n  })),\n  limit: Type.Optional(Type.Number({\n    description: 'Max results. Default: 20.',\n  })),\n  cursor: Type.Optional(Type.String({\n    description: 'Pagination cursor for next page of results.',\n  })),\n});\n\nexport function createFarcasterTool() {\n  return {\n    name: 'farcaster',\n    label: 'Farcaster',\n    ownerOnly: true,\n    description:\n      'Social actions on Farcaster: post casts, browse feeds, search, follow users, ' +\n      'engage with content (like/recast), and explore channels and trending casts. ' +\n      'Requires NEYNAR_API_KEY.',\n    parameters: FarcasterSchema,\n    execute: async (_toolCallId: string, args: unknown) => {\n      const configCheck = checkToolConfig('farcaster');\n      if (configCheck) return configCheck;\n\n      const params = args as Record<string, unknown>;\n      const action = readStringParam(params, 'action', { required: true })!;\n\n      try {\n        switch (action) {\n          case 'post':\n            return handlePost(params);\n          case 'feed':\n            return handleFeed(params);\n          case 'search':\n            return handleSearch(params);\n          case 'user':\n            return handleUser(params);\n          case 'channel':\n            return handleChannel(params);\n          case 'trending':\n            return handleTrending(params);\n          case 'like':\n            return handleLike(params);\n          case 'recast':\n            return handleRecast(params);\n          case 'follow':\n            return handleFollow(params);\n          case 'unfollow':\n            return handleUnfollow(params);\n          default:\n            return errorResult(`Unknown action: ${action}.`);\n        }\n      } catch (err) {\n        return errorResult(`Farcaster error: ${err instanceof Error ? err.message : String(err)}`);\n      }\n    },\n  };\n}\n\n// ── API Helpers ──────────────────────────────────────────────────────────\n\nfunction getApiKey(): string {\n  const vault = getCredentialVault();\n  const key = vault.getSecret('farcaster.neynar.apiKey', 'farcaster') ?? process.env.NEYNAR_API_KEY;\n  if (!key) throw new Error('NEYNAR_API_KEY not set.');\n  return key;\n}\n\nfunction getSignerUuid(): string {\n  const vault = getCredentialVault();\n  const uuid = vault.getSecret('farcaster.neynar.signerUuid', 'farcaster') ?? process.env.NEYNAR_SIGNER_UUID;\n  if (!uuid) throw new Error('NEYNAR_SIGNER_UUID not set. Required for write operations.');\n  return uuid;\n}\n\nasync function neynarGet(path: string, params?: Record<string, string>): Promise<any> {\n  const url = new URL(`https://api.neynar.com/v2/farcaster/${path}`);\n  if (params) {\n    for (const [k, v] of Object.entries(params)) {\n      if (v) url.searchParams.set(k, v);\n    }\n  }\n\n  const response = await guardedFetch(url.toString(), {\n    headers: {\n      accept: 'application/json',\n      api_key: getApiKey(),\n    },\n    signal: AbortSignal.timeout(15_000),\n  });\n\n  if (!response.ok) {\n    const text = await response.text().catch(() => '');\n    throw new Error(`Neynar API ${response.status}: ${text.slice(0, 200)}`);\n  }\n\n  return response.json();\n}\n\nasync function neynarPost(path: string, body: Record<string, unknown>): Promise<any> {\n  const response = await guardedFetch(`https://api.neynar.com/v2/farcaster/${path}`, {\n    method: 'POST',\n    headers: {\n      accept: 'application/json',\n      'content-type': 'application/json',\n      api_key: getApiKey(),\n    },\n    body: JSON.stringify(body),\n    signal: AbortSignal.timeout(15_000),\n  });\n\n  if (!response.ok) {\n    const text = await response.text().catch(() => '');\n    throw new Error(`Neynar API ${response.status}: ${text.slice(0, 200)}`);\n  }\n\n  return response.json();\n}\n\n// ── Resolve FID from username ────────────────────────────────────────────\n\nasync function resolveFid(params: Record<string, unknown>): Promise<number> {\n  const fid = readNumberParam(params, 'fid');\n  if (fid) return fid;\n\n  const username = readStringParam(params, 'username');\n  if (!username) throw new Error('Either username or fid is required.');\n\n  const data = await neynarGet('user/by_username', { username });\n  const user = data?.user;\n  if (!user?.fid) throw new Error(`User \"${username}\" not found.`);\n  return user.fid;\n}\n\n// ── Action Handlers ─────────────────────────────────────────────────────\n\nasync function handlePost(params: Record<string, unknown>) {\n  const text = readStringParam(params, 'text');\n  if (!text) return errorResult('text is required for post (max 320 characters).');\n  if (text.length > 320) return errorResult(`Cast too long (${text.length}/320). Shorten your text.`);\n\n  const body: Record<string, unknown> = {\n    signer_uuid: getSignerUuid(),\n    text,\n  };\n\n  const parentHash = readStringParam(params, 'parent_hash');\n  const parentUrl = readStringParam(params, 'parent_url');\n  if (parentHash) body.parent = parentHash;\n  if (parentUrl) body.channel_id = parentUrl;\n\n  const data = await neynarPost('cast', body);\n  const cast = data?.cast;\n\n  return jsonResult({\n    status: 'success',\n    action: 'post',\n    hash: cast?.hash,\n    text: cast?.text ?? text,\n    author: cast?.author?.username,\n    parentHash: parentHash ?? undefined,\n    channel: parentUrl ?? undefined,\n  });\n}\n\nasync function handleFeed(params: Record<string, unknown>) {\n  const limit = readNumberParam(params, 'limit') ?? 20;\n  const cursor = readStringParam(params, 'cursor');\n\n  const username = readStringParam(params, 'username');\n  const fid = readNumberParam(params, 'fid');\n\n  let data: any;\n  if (username || fid) {\n    const resolvedFid = fid ?? await resolveFid(params);\n    data = await neynarGet('feed/user/casts', {\n      fid: String(resolvedFid),\n      limit: String(limit),\n      ...(cursor ? { cursor } : {}),\n    });\n  } else {\n    // Home feed requires signer\n    data = await neynarGet('feed', {\n      feed_type: 'following',\n      fid: String(getCredentialVault().getSecret('farcaster.neynar.fid', 'farcaster') ?? process.env.NEYNAR_FID ?? '0'),\n      limit: String(limit),\n      ...(cursor ? { cursor } : {}),\n    });\n  }\n\n  const casts: any[] = data?.casts ?? [];\n\n  return jsonResult({\n    count: casts.length,\n    casts: casts.map(formatCast),\n    nextCursor: data?.next?.cursor ?? null,\n  });\n}\n\nasync function handleSearch(params: Record<string, unknown>) {\n  const query = readStringParam(params, 'query');\n  if (!query) return errorResult('query is required for search.');\n\n  const limit = readNumberParam(params, 'limit') ?? 20;\n\n  const data = await neynarGet('cast/search', {\n    q: query,\n    limit: String(limit),\n  });\n\n  const casts: any[] = data?.result?.casts ?? [];\n\n  return jsonResult({\n    query,\n    count: casts.length,\n    casts: casts.map(formatCast),\n  });\n}\n\nasync function handleUser(params: Record<string, unknown>) {\n  const username = readStringParam(params, 'username');\n  const fid = readNumberParam(params, 'fid');\n\n  if (!username && !fid) return errorResult('username or fid is required for user lookup.');\n\n  let data: any;\n  if (username) {\n    data = await neynarGet('user/by_username', { username });\n  } else {\n    data = await neynarGet('user/bulk', { fids: String(fid) });\n    data = { user: data?.users?.[0] };\n  }\n\n  const user = data?.user;\n  if (!user) return errorResult(`User not found.`);\n\n  return jsonResult({\n    fid: user.fid,\n    username: user.username,\n    displayName: user.display_name,\n    bio: user.profile?.bio?.text,\n    pfpUrl: user.pfp_url,\n    followerCount: user.follower_count,\n    followingCount: user.following_count,\n    verifiedAddresses: user.verified_addresses?.eth_addresses ?? [],\n    activeStatus: user.active_status,\n    powerBadge: user.power_badge,\n  });\n}\n\nasync function handleChannel(params: Record<string, unknown>) {\n  const channelId = readStringParam(params, 'channel_id');\n  if (!channelId) return errorResult('channel_id is required (e.g. \"base\", \"farcaster\", \"memes\").');\n\n  const limit = readNumberParam(params, 'limit') ?? 20;\n\n  // Get channel info + recent casts\n  const [channelData, castsData] = await Promise.all([\n    neynarGet('channel', { id: channelId }),\n    neynarGet('feed/channels', {\n      channel_ids: channelId,\n      limit: String(limit),\n    }),\n  ]);\n\n  const channel = channelData?.channel;\n  const casts: any[] = castsData?.casts ?? [];\n\n  return jsonResult({\n    channel: channel ? {\n      id: channel.id,\n      name: channel.name,\n      description: channel.description,\n      imageUrl: channel.image_url,\n      followerCount: channel.follower_count,\n      leadFid: channel.lead?.fid,\n    } : { id: channelId },\n    casts: casts.map(formatCast),\n    count: casts.length,\n  });\n}\n\nasync function handleTrending(params: Record<string, unknown>) {\n  const limit = readNumberParam(params, 'limit') ?? 20;\n\n  const data = await neynarGet('feed/trending', {\n    limit: String(limit),\n  });\n\n  const casts: any[] = data?.casts ?? [];\n\n  return jsonResult({\n    trending: true,\n    count: casts.length,\n    casts: casts.map(formatCast),\n  });\n}\n\nasync function handleLike(params: Record<string, unknown>) {\n  const castHash = readStringParam(params, 'cast_hash');\n  if (!castHash) return errorResult('cast_hash is required for like.');\n\n  await neynarPost('reaction', {\n    signer_uuid: getSignerUuid(),\n    reaction_type: 'like',\n    target: castHash,\n  });\n\n  return jsonResult({ status: 'success', action: 'like', castHash });\n}\n\nasync function handleRecast(params: Record<string, unknown>) {\n  const castHash = readStringParam(params, 'cast_hash');\n  if (!castHash) return errorResult('cast_hash is required for recast.');\n\n  await neynarPost('reaction', {\n    signer_uuid: getSignerUuid(),\n    reaction_type: 'recast',\n    target: castHash,\n  });\n\n  return jsonResult({ status: 'success', action: 'recast', castHash });\n}\n\nasync function handleFollow(params: Record<string, unknown>) {\n  const targetFid = await resolveFid(params);\n\n  await neynarPost('user/follow', {\n    signer_uuid: getSignerUuid(),\n    target_fids: [targetFid],\n  });\n\n  return jsonResult({ status: 'success', action: 'follow', targetFid });\n}\n\nasync function handleUnfollow(params: Record<string, unknown>) {\n  const targetFid = await resolveFid(params);\n\n  await neynarPost('user/unfollow', {\n    signer_uuid: getSignerUuid(),\n    target_fids: [targetFid],\n  });\n\n  return jsonResult({ status: 'success', action: 'unfollow', targetFid });\n}\n\n// ── Formatting ──────────────────────────────────────────────────────────\n\nfunction formatCast(cast: any) {\n  return {\n    hash: cast.hash,\n    text: cast.text,\n    author: cast.author?.username ?? cast.author?.display_name ?? 'unknown',\n    authorFid: cast.author?.fid,\n    timestamp: cast.timestamp,\n    likes: cast.reactions?.likes_count ?? 0,\n    recasts: cast.reactions?.recasts_count ?? 0,\n    replies: cast.replies?.count ?? 0,\n    channel: cast.channel?.id ?? null,\n    embeds: cast.embeds?.length > 0\n      ? cast.embeds.map((e: any) => e.url ?? e.cast_id?.hash).filter(Boolean)\n      : undefined,\n  };\n}\n"],"mappings":"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"}