Implement MatrixClient API methods and add ECA event/action plugins
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3605358. --> Reported by: [freelock](https://www.drupal.org/user/313537) >>> <h3 id="summary-problem-motivation">Problem/Motivation</h3> <p> Several <code>MatrixClient</code> methods existed in the interface but were not implemented &mdash; <code>getState()</code>, <code>setState()</code>, and<br> <code>messages()</code> all contained only a <code>// TODO</code> comment and returned nothing. <code>sendMessage()</code> returned the raw Guzzle response object<br> rather than the event ID string declared in the interface.</p> <p> Additionally, there were no ECA (Event-Condition-Action) plugins for the inbound event side: no ECA event plugin meant ECA models could not react to Matrix events at<br> all. And while a basic <code>SendMessage</code> ECA action existed, there were no actions for thread replies, redacting events, or setting room state.</p> <h4 id="summary-steps-reproduce">Steps to reproduce</h4> <ul> <li>Call <code>$matrixClient-&gt;getState($room, 'm.room.power_levels')</code> &mdash; returns <code>null</code> (method body is empty).</li> <li>Call <code>$matrixClient-&gt;setState(...)</code> &mdash; does nothing.</li> <li>Call <code>$matrixClient-&gt;sendMessage($room, 'hello')</code> &mdash; returns a Guzzle response object, not an event ID string.</li> <li>Try to build an ECA model that reacts to a Matrix message &mdash; no Matrix event plugin appears in the ECA event list.</li> </ul> <h3 id="summary-proposed-resolution">Proposed resolution</h3> <p> <strong>MatrixClient implementations</strong></p> <ul> <li><code>sendMessage()</code> &mdash; now returns <code>$response-&gt;event_id ?? ''</code> (string event ID).</li> <li><code>sendThreadReply(string $roomId, string $threadRootEventId, ?string $inReplyToEventId, array $body): string</code> &mdash; sends <code>m.room.message</code> with<br> a <code>m.thread</code> + <code>m.in_reply_to</code> relation structure per the Matrix spec.</li> <li><code>redactEvent(string $roomId, string $eventId, string $reason = ''): string</code> &mdash; sends a redaction event; returns the redaction event ID.</li> <li><code>getState($room, $eventType, $stateKey = ''): array|false</code> &mdash; fetches room state; returns <code>[]</code> on 404 (state not yet set),<br> <code>false</code> on other errors.</li> <li><code>setState($room, $eventType, $stateKey, array $state): string</code> &mdash; sets room state; handles 403 (insufficient power level) gracefully by logging a<br> warning and returning <code>''</code>.</li> <li><code>messages()</code> &mdash; returns <code>[]</code> (not yet implemented; stub made explicit with proper return type).</li> </ul> <p> <strong>ECA event plugin</strong></p> <ul> <li><code>MatrixEcaEvent</code> &mdash; fires on <code>MatrixEvents::EVENT_RECEIVED</code> and exposes ECA tokens: <code>[matrix_event:body]</code>,<br> <code>[matrix_event:sender]</code>, <code>[matrix_event:room-id]</code>, <code>[matrix_event:event-id]</code>, <code>[matrix_event:thread-root]</code>.</li> <li><code>MatrixEcaEventDeriver</code> &mdash; derives one ECA event variant per Matrix event type (message, reaction, etc.) so ECA models can target specific event<br> types.</li> </ul> <p> <strong>ECA action plugins</strong></p> <ul> <li><code>matrix_api_send_message</code> &mdash; extended to fall back to <code>default_room</code> config when no room is set, and to support<br> <code>com.freelock.data</code> structured payloads (JSON data field).</li> <li><code>matrix_api_send_thread_reply</code> &mdash; send a message as a Matrix thread reply given a thread root event ID.</li> <li><code>matrix_api_redact_event</code> &mdash; redact a Matrix event by event ID.</li> <li><code>matrix_api_set_room_state</code> &mdash; set a Matrix room state event (event type + state key + JSON body).</li> <li><code>matrix_api_trigger_poll</code> &mdash; trigger an immediate inbound sync poll (useful in ECA flows that need to flush pending events).</li> </ul> <h3 id="summary-remaining-tasks">Remaining tasks</h3> <ul> <li>[x] All MatrixClient methods implemented.</li> <li>[x] MatrixEcaEvent and deriver implemented.</li> <li>[x] All ECA action plugins implemented.</li> <li>[ ] <code>messages()</code> pagination is not yet implemented; it returns an empty array with a note in the docblock.</li> </ul> <h3 id="summary-ui-changes">User interface changes</h3> <p> None. ECA actions and events appear in the ECA model builder UI automatically once the module is enabled.</p> <h3 id="summary-api-changes">API changes</h3> <p> <code>MatrixClientInterface</code> method signatures updated:</p> <ul> <li><code>sendMessage($room, $body, array $options = []): string</code> (was untyped return)</li> <li><code>sendThreadReply(string $roomId, string $threadRootEventId, ?string $inReplyToEventId, array $body): string</code> (new)</li> <li><code>redactEvent(string $roomId, string $eventId, string $reason = ''): string</code> (new)</li> <li><code>getState($room, $eventType, $stateKey = ''): array|false</code> (now implemented)</li> <li><code>setState($room, $eventType, $stateKey, array $state): string</code> (now implemented)</li> </ul> <p> ECA tokens available in <code>MatrixEcaEvent</code> handlers:<br> <code>[matrix_event:body]</code>, <code>[matrix_event:sender]</code>, <code>[matrix_event:room-id]</code>, <code>[matrix_event:event-id]</code>,<br> <code>[matrix_event:thread-root]</code></p> <h3 id="summary-data-model-changes">Data model changes</h3> <p> None.</p>
issue