import { EventType, MsgType, RelationType, type MatrixActionClientOpts, type MatrixMessageSummary, type MatrixRawEvent, type RoomMessageEventContent, } from "./types.js"; import { resolveActionClient } from "./client.js"; import { summarizeMatrixRawEvent } from "./summary.js"; import { resolveMatrixRoomId, sendMessageMatrix } from "../send.js"; export async function sendMatrixMessage( to: string, content: string, opts: MatrixActionClientOpts & { mediaUrl?: string; replyToId?: string; threadId?: string; } = {}, ) { return await sendMessageMatrix(to, content, { mediaUrl: opts.mediaUrl, replyToId: opts.replyToId, threadId: opts.threadId, client: opts.client, timeoutMs: opts.timeoutMs, }); } export async function editMatrixMessage( roomId: string, messageId: string, content: string, opts: MatrixActionClientOpts = {}, ) { const trimmed = content.trim(); if (!trimmed) throw new Error("Matrix edit requires content"); const { client, stopOnDone } = await resolveActionClient(opts); try { const resolvedRoom = await resolveMatrixRoomId(client, roomId); const newContent = { msgtype: MsgType.Text, body: trimmed, } satisfies RoomMessageEventContent; const payload: RoomMessageEventContent = { msgtype: MsgType.Text, body: `* ${trimmed}`, "m.new_content": newContent, "m.relates_to": { rel_type: RelationType.Replace, event_id: messageId, }, }; const eventId = await client.sendMessage(resolvedRoom, payload); return { eventId: eventId ?? null }; } finally { if (stopOnDone) client.stop(); } } export async function deleteMatrixMessage( roomId: string, messageId: string, opts: MatrixActionClientOpts & { reason?: string } = {}, ) { const { client, stopOnDone } = await resolveActionClient(opts); try { const resolvedRoom = await resolveMatrixRoomId(client, roomId); await client.redactEvent(resolvedRoom, messageId, opts.reason); } finally { if (stopOnDone) client.stop(); } } export async function readMatrixMessages( roomId: string, opts: MatrixActionClientOpts & { limit?: number; before?: string; after?: string; } = {}, ): Promise<{ messages: MatrixMessageSummary[]; nextBatch?: string | null; prevBatch?: string | null; }> { const { client, stopOnDone } = await resolveActionClient(opts); try { const resolvedRoom = await resolveMatrixRoomId(client, roomId); const limit = typeof opts.limit === "number" && Number.isFinite(opts.limit) ? Math.max(1, Math.floor(opts.limit)) : 20; const token = opts.before?.trim() || opts.after?.trim() || undefined; const dir = opts.after ? "f" : "b"; // @vector-im/matrix-bot-sdk uses doRequest for room messages const res = await client.doRequest( "GET", `/_matrix/client/v3/rooms/${encodeURIComponent(resolvedRoom)}/messages`, { dir, limit, from: token, }, ) as { chunk: MatrixRawEvent[]; start?: string; end?: string }; const messages = res.chunk .filter((event) => event.type === EventType.RoomMessage) .filter((event) => !event.unsigned?.redacted_because) .map(summarizeMatrixRawEvent); return { messages, nextBatch: res.end ?? null, prevBatch: res.start ?? null, }; } finally { if (stopOnDone) client.stop(); } }