| |
| |
| |
| |
| |
| const INGEST = process.env.TORQUE_INGESTER_URL || 'https://ingest.torque.so/events' |
| const API = process.env.TORQUE_API_URL || 'https://server.torque.so' |
| |
| const JWT = process.env.TORQUE_API_KEY || process.env.TORQUE_API_TOKEN || '' |
| |
| const INGEST_KEY = process.env.TORQUE_INGEST_KEY || JWT |
|
|
| export function isTorqueConfigured(): boolean { |
| return INGEST_KEY !== '' && !INGEST_KEY.startsWith('your') |
| } |
|
|
| function ingestHeaders(): Record<string, string> { |
| return { 'x-api-key': INGEST_KEY, 'Content-Type': 'application/json' } |
| } |
|
|
| function apiHeaders(): Record<string, string> { |
| return { 'Authorization': 'Bearer ' + JWT, 'Content-Type': 'application/json' } |
| } |
|
|
| export async function sendCustomEvent( |
| wallet: string, |
| eventName: string, |
| data: Record<string, unknown> = {} |
| ): Promise<{ success: boolean; eventId?: string; error?: string }> { |
| if (!isTorqueConfigured()) { |
| return { success: false, error: 'TORQUE_API_KEY not configured' } |
| } |
| try { |
| const r = await fetch(INGEST, { |
| method: 'POST', |
| headers: ingestHeaders(), |
| body: JSON.stringify({ |
| userPubkey: wallet, |
| timestamp: Date.now(), |
| eventName, |
| data, |
| }), |
| }) |
| if (!r.ok) { |
| const text = await r.text() |
| return { success: false, error: `Torque ingest ${r.status}: ${text}` } |
| } |
| const res = await r.json() |
| return { success: true, eventId: res.id || res.eventId } |
| } catch (e) { |
| return { success: false, error: String(e) } |
| } |
| } |
|
|
| export async function createCampaign(params: { |
| name: string; type: string; description: string; budget: number; tokenMint?: string; formula?: string; eventName?: string |
| }): Promise<{ success: boolean; campaignId?: string; platformUrl?: string; error?: string }> { |
| if (!isTorqueConfigured()) { |
| return { success: false, error: 'TORQUE_API_KEY not configured' } |
| } |
| |
| |
| |
| |
| const shortId = Math.random().toString(36).slice(2, 10).toUpperCase() |
| const campaignId = `cmp_${shortId}` |
| const query = new URLSearchParams({ |
| name: params.name, |
| type: params.type.toLowerCase(), |
| budget: String(params.budget), |
| ...(params.eventName ? { event: params.eventName } : {}), |
| }) |
| const platformUrl = `https://platform.torque.so/campaigns/new?${query}` |
| return { success: true, campaignId, platformUrl } |
| } |
|
|
| export async function getLeaderboard(campaignId: string, limit = 50): Promise<unknown[]> { |
| if (!isTorqueConfigured()) return [] |
| try { |
| const r = await fetch(API + '/campaigns/' + campaignId + '/leaderboard?limit=' + limit, { headers: apiHeaders() }) |
| if (!r.ok) return [] |
| return (await r.json()).entries || [] |
| } catch { |
| return [] |
| } |
| } |
|
|
| export async function fireChurnRiskEvent(wallet: string, risk: string, score: number, daysInactive: number, volumeDrop: number) { |
| const eventName = risk === 'critical' || risk === 'high' ? 'churn_risk_high' : 'churn_risk_medium' |
| return sendCustomEvent(wallet, eventName, { risk, score, daysInactive, volumeDrop, detectedBy: 'flowstate-ai-agent' }) |
| } |
|
|
| export async function fireComebackEvent(wallet: string, inactiveDays: number, returnProtocol: string) { |
| return sendCustomEvent(wallet, 'comeback_detected', { inactiveDays, returnProtocol, detectedBy: 'flowstate-ai-agent' }) |
| } |
|
|
| export async function fireStreakEvent(wallet: string, streakDays: number, protocol: string) { |
| return sendCustomEvent(wallet, 'streak_maintained', { streakDays, protocol, milestone: streakDays % 7 === 0 }) |
| } |
|
|
| export async function sendTelegramAlert(message: string): Promise<void> { |
| const url = process.env.TELEGRAM_WEBHOOK_URL |
| if (!url) return |
| try { |
| await fetch(url, { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ text: `π FlowState Alert\n\n${message}` }), |
| }) |
| } catch {} |
| } |
|
|
| export const MCP_TOOLS = { |
| send_custom_event: { name: 'send_custom_event', description: 'Send a custom event to Torque for a wallet', inputSchema: { type: 'object', properties: { wallet: { type: 'string' }, eventName: { type: 'string' }, data: { type: 'object' } }, required: ['wallet', 'eventName'] } }, |
| create_campaign: { name: 'create_campaign', description: 'Create a new Torque campaign', inputSchema: { type: 'object', properties: { name: { type: 'string' }, type: { type: 'string', enum: ['leaderboard', 'rebate', 'raffle', 'gift'] }, budget: { type: 'number' } }, required: ['name', 'type', 'budget'] } }, |
| get_leaderboard: { name: 'get_leaderboard', description: 'Get leaderboard rankings', inputSchema: { type: 'object', properties: { campaignId: { type: 'string' } }, required: ['campaignId'] } }, |
| } as const |
|
|