import { readEnv } from "../env.js"; import { withWhatsAppPrefix } from "../utils.js"; import { createClient } from "./client.js"; export type ListedMessage = { sid: string; status: string | null; direction: string | null; dateCreated: Date | undefined; from?: string | null; to?: string | null; body?: string | null; errorCode: number | null; errorMessage: string | null; }; // Remove duplicates by SID while preserving order. export function uniqueBySid(messages: ListedMessage[]): ListedMessage[] { const seen = new Set(); const deduped: ListedMessage[] = []; for (const m of messages) { if (seen.has(m.sid)) continue; seen.add(m.sid); deduped.push(m); } return deduped; } // Sort messages newest -> oldest by dateCreated. export function sortByDateDesc(messages: ListedMessage[]): ListedMessage[] { return [...messages].sort((a, b) => { const da = a.dateCreated?.getTime() ?? 0; const db = b.dateCreated?.getTime() ?? 0; return db - da; }); } // Merge inbound/outbound messages (recent first) for status commands and tests. export async function listRecentMessages( lookbackMinutes: number, limit: number, clientOverride?: ReturnType, ): Promise { const env = readEnv(); const client = clientOverride ?? createClient(env); const from = withWhatsAppPrefix(env.whatsappFrom); const since = new Date(Date.now() - lookbackMinutes * 60_000); // Fetch inbound (to our WA number) and outbound (from our WA number), merge, sort, limit. const fetchLimit = Math.min(Math.max(limit * 2, limit + 10), 100); const inbound = await client.messages.list({ to: from, dateSentAfter: since, limit: fetchLimit, }); const outbound = await client.messages.list({ from, dateSentAfter: since, limit: fetchLimit, }); const inboundArr = Array.isArray(inbound) ? inbound : []; const outboundArr = Array.isArray(outbound) ? outbound : []; const combined = uniqueBySid( [...inboundArr, ...outboundArr].map((m) => ({ sid: m.sid, status: m.status ?? null, direction: m.direction ?? null, dateCreated: m.dateCreated, from: m.from, to: m.to, body: m.body, errorCode: m.errorCode ?? null, errorMessage: m.errorMessage ?? null, })), ); return sortByDateDesc(combined).slice(0, limit); } // Human-friendly single-line formatter for recent messages. export function formatMessageLine(m: ListedMessage): string { const ts = m.dateCreated?.toISOString() ?? "unknown-time"; const dir = m.direction === "inbound" ? "⬅️ " : m.direction === "outbound-api" || m.direction === "outbound-reply" ? "➡️ " : "↔️ "; const status = m.status ?? "unknown"; const err = m.errorCode != null ? ` error ${m.errorCode}${m.errorMessage ? ` (${m.errorMessage})` : ""}` : ""; const body = (m.body ?? "").replace(/\s+/g, " ").trim(); const bodyPreview = body.length > 140 ? `${body.slice(0, 137)}…` : body || ""; return `[${ts}] ${dir}${m.from ?? "?"} -> ${m.to ?? "?"} | ${status}${err} | ${bodyPreview} (sid ${m.sid})`; }