import { stripHeartbeatToken } from "../heartbeat.js"; import { HEARTBEAT_TOKEN, SILENT_REPLY_TOKEN } from "../tokens.js"; import type { ReplyPayload } from "../types.js"; export type NormalizeReplyOptions = { responsePrefix?: string; onHeartbeatStrip?: () => void; stripHeartbeat?: boolean; silentToken?: string; }; export function normalizeReplyPayload( payload: ReplyPayload, opts: NormalizeReplyOptions = {}, ): ReplyPayload | null { const hasMedia = Boolean( payload.mediaUrl || (payload.mediaUrls?.length ?? 0) > 0, ); const trimmed = payload.text?.trim() ?? ""; if (!trimmed && !hasMedia) return null; const silentToken = opts.silentToken ?? SILENT_REPLY_TOKEN; if (trimmed === silentToken && !hasMedia) return null; let text = payload.text ?? undefined; if (text && !trimmed) { // Keep empty text when media exists so media-only replies still send. text = ""; } const shouldStripHeartbeat = opts.stripHeartbeat ?? true; if (shouldStripHeartbeat && text?.includes(HEARTBEAT_TOKEN)) { const stripped = stripHeartbeatToken(text, { mode: "message" }); if (stripped.didStrip) opts.onHeartbeatStrip?.(); if (stripped.shouldSkip && !hasMedia) return null; text = stripped.text; } if ( opts.responsePrefix && text && text.trim() !== HEARTBEAT_TOKEN && !text.startsWith(opts.responsePrefix) ) { text = `${opts.responsePrefix} ${text}`; } return { ...payload, text }; }