--- name: matrix_message_send kind: function lang: go domain: infra version: "0.1.0" purity: impure signature: | func MatrixSendText(ctx context.Context, client *mautrix.Client, roomID id.RoomID, body string) (id.EventID, error) func MatrixSendMarkdown(ctx context.Context, client *mautrix.Client, roomID id.RoomID, markdown string) (id.EventID, error) func MatrixSendReply(ctx context.Context, client *mautrix.Client, roomID id.RoomID, replyTo id.EventID, body string) (id.EventID, error) func MatrixEditMessage(ctx context.Context, client *mautrix.Client, roomID id.RoomID, eventID id.EventID, newBody string) (id.EventID, error) func MatrixSendReaction(ctx context.Context, client *mautrix.Client, roomID id.RoomID, targetEventID id.EventID, key string) (id.EventID, error) description: "Envía mensajes Matrix con todas las variantes del compositor: texto plain, markdown con HTML sanitizado, reply con m.in_reply_to, edit (m.replace) y reaction (m.annotation). Si el room es E2EE y client.Crypto está configurado via matrix_crypto_init, mautrix cifra automáticamente." tags: [matrix, mautrix, send, message, markdown, reply, edit, reaction, infra, matrix-mas] params: - name: ctx desc: "Context para cancelación y timeout de la petición HTTP a Synapse." - name: client desc: "*mautrix.Client autenticado. Debe tener AccessToken, UserID y DeviceID. Si es nil, error inmediato." - name: roomID desc: "ID del room Matrix destino. Formato: !xxx:server." - name: body / markdown / newBody desc: "Contenido del mensaje. Para MatrixSendMarkdown se parsea con goldmark y se sanitiza con bluemonday UGCPolicy." - name: replyTo / eventID / targetEventID desc: "ID del evento referenciado (para reply, edit y reaction)." - name: key desc: "Emoji unicode raw para reaction (ej. '👍'). No shortcodes (:thumbsup:)." output: "id.EventID del evento enviado por Synapse + error. El EventID permite referenciar el mensaje para edits, replies o reactions posteriores." uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: - "context" - "bytes" - "fmt" - "github.com/microcosm-cc/bluemonday" - "github.com/yuin/goldmark" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" tested: true tests: - "SendText body correcto y EventID parseado" - "SendMarkdown bold convierte a HTML strong y sanitiza script" - "SendReply m.relates_to m.in_reply_to presente" - "EditMessage rel_type m.replace y m.new_content" - "SendReaction tipo m.reaction con m.annotation y key" - "SendText client nil devuelve error" - "SendMarkdown client nil devuelve error" - "SendReply client nil devuelve error" - "EditMessage client nil devuelve error" - "SendReaction client nil devuelve error" test_file_path: "functions/infra/matrix_message_send_test.go" file_path: "functions/infra/matrix_message_send.go" --- ## Ejemplo ```go import ( "context" infra "fn-registry/functions/infra" "maunium.net/go/mautrix/id" ) ctx := context.Background() roomID := id.RoomID("!abc123:organic-machine.com") // Texto plain evID, err := infra.MatrixSendText(ctx, client, roomID, "Hola") // Markdown: **bold**, `code`, > quote -> HTML sanitizado evID, err = infra.MatrixSendMarkdown(ctx, client, roomID, "**bold** + `code`") // Reply a un evento existente evID, err = infra.MatrixSendReply(ctx, client, roomID, id.EventID("$orig:server"), "Si, totalmente") // Edit de un mensaje ya enviado evID, err = infra.MatrixEditMessage(ctx, client, roomID, id.EventID("$msg:server"), "texto corregido") // Reaction emoji evID, err = infra.MatrixSendReaction(ctx, client, roomID, id.EventID("$msg:server"), "👍") ``` ## Cuando usarla Llamar desde el compositor del cliente Matrix (`matrix_client_pc`) tras inicializar el cliente con `matrix_client_init`. Si el room es E2EE, llamar primero a `matrix_crypto_init` para que `client.Crypto` esté configurado — el cifrado es transparente, no requiere código extra en estas funciones. ## Gotchas - **Markdown sanitization**: goldmark puede emitir tags HTML arbitrarios si el input los contiene. Esta función aplica `bluemonday.UGCPolicy()` + allowlist extra (`details`, `summary`, `code`, `pre`). Tags fuera de la allowlist como `