import crypto from 'node:crypto';
const AGENT_ID = process.env.AGENT_ID;
const EZW_SECRET = process.env.EZW_SECRET;
const TARGET = `https://mcp.echozero.app/api/public/agent-signals/${AGENT_ID}`;
const STRUCTURED_KEYS = [
'action', 'amount', 'chain', 'changes', 'clientTimestamp', 'confidence', 'context',
'currentPnlPct', 'entryPrice', 'entryZone', 'eventType', 'exitPrice', 'exitReason',
'expiresAt', 'ideaId', 'instrument', 'leverageX', 'metadata', 'orderType', 'pnlPct',
'positionRef', 'reasoning', 'relatedTradeId', 'riskMgmt', 'sellSizePct', 'side',
'symbol', 'tokenAddress', 'tradeType', 'triggers', 'urgency', 'version',
];
function stableJson(value) {
if (value === null || typeof value !== 'object') return JSON.stringify(value);
if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`;
return `{${Object.keys(value)
.sort()
.filter((k) => value[k] !== undefined)
.map((k) => `${JSON.stringify(k)}:${stableJson(value[k])}`)
.join(',')}}`;
}
function canonicalBody(body) {
const out = {};
if (body.text !== undefined) out.text = body.text;
if (body.idempotencyKey?.trim()) out.idempotencyKey = body.idempotencyKey.trim();
for (const key of STRUCTURED_KEYS.sort()) {
if (body[key] !== undefined) out[key] = body[key];
}
return stableJson(out);
}
function sign(body) {
const ts = String(Math.floor(Date.now() / 1000));
const canon = canonicalBody(body);
const sig = crypto
.createHmac('sha256', EZW_SECRET)
.update(`${ts}.${canon}`)
.digest('hex');
return { ts, sig, canon };
}
export default async function handler(req, res) {
const tv = req.body ?? {};
const idempotencyKey = `tv-${tv.alert_id ?? tv.timenow ?? Date.now()}`;
const text = `BUY ${tv.ticker ?? 'SOL'} $500`;
const body = { text, idempotencyKey };
const { ts, sig } = sign(body);
const upstream = await fetch(TARGET, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-EZ-Timestamp': ts,
'X-EZ-Signature': sig,
},
body: JSON.stringify(body),
});
res.status(upstream.status).send(await upstream.text());
}