@@ -29,6 +29,7 @@ import {
2929 type IWidgetApiResponse ,
3030 type IWidgetApiResponseData ,
3131 type IUpdateStateToWidgetActionRequest ,
32+ UnstableApiVersion ,
3233} from "matrix-widget-api" ;
3334
3435import { MatrixEvent , type IEvent , type IContent , EventStatus } from "./models/event.ts" ;
@@ -259,6 +260,10 @@ export class RoomWidgetClient extends MatrixClient {
259260 if ( sendContentLoaded ) widgetApi . sendContentLoaded ( ) ;
260261 }
261262
263+ public async supportUpdateState ( ) : Promise < boolean > {
264+ return ( await this . widgetApi . getClientVersions ( ) ) ?. includes ( UnstableApiVersion . MSC2762_UPDATE_STATE ) ;
265+ }
266+
262267 public async startClient ( opts : IStartClientOpts = { } ) : Promise < void > {
263268 this . lifecycle = new AbortController ( ) ;
264269
@@ -283,6 +288,31 @@ export class RoomWidgetClient extends MatrixClient {
283288
284289 await this . widgetApiReady ;
285290
291+ if ( ! ( await this . supportUpdateState ( ) ) ) {
292+ // Backfill the requested events
293+ // We only get the most recent event for every type + state key combo,
294+ // so it doesn't really matter what order we inject them in
295+ await Promise . all (
296+ this . capabilities . receiveState ?. map ( async ( { eventType, stateKey } ) => {
297+ const rawEvents = await this . widgetApi . readStateEvents ( eventType , undefined , stateKey , [
298+ this . roomId ,
299+ ] ) ;
300+ const events = rawEvents . map ( ( rawEvent ) => new MatrixEvent ( rawEvent as Partial < IEvent > ) ) ;
301+
302+ if ( this . syncApi instanceof SyncApi ) {
303+ // Passing events as `stateAfterEventList` will update the state.
304+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , events ) ;
305+ } else {
306+ await this . syncApi ! . injectRoomEvents ( this . room ! , events ) ; // Sliding Sync
307+ }
308+ events . forEach ( ( event ) => {
309+ this . emit ( ClientEvent . Event , event ) ;
310+ logger . info ( `Backfilled event ${ event . getId ( ) } ${ event . getType ( ) } ${ event . getStateKey ( ) } ` ) ;
311+ } ) ;
312+ } ) ?? [ ] ,
313+ ) ;
314+ }
315+
286316 if ( opts . clientWellKnownPollPeriod !== undefined ) {
287317 this . clientWellKnownIntervalID = setInterval ( ( ) => {
288318 this . fetchClientWellKnown ( ) ;
@@ -589,11 +619,24 @@ export class RoomWidgetClient extends MatrixClient {
589619 await this . updateTxId ( event ) ;
590620
591621 if ( this . syncApi instanceof SyncApi ) {
592- await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ ] , [ event ] ) ;
622+ if ( await this . supportUpdateState ( ) ) {
623+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ ] , [ event ] ) ;
624+ } else {
625+ // Passing undefined for `stateAfterEventList` will make `injectRoomEvents` run in legacy mode
626+ // -> state events in `timelineEventList` will update the state.
627+ await this . syncApi . injectRoomEvents ( this . room ! , [ ] , undefined , [ event ] ) ;
628+ }
593629 } else {
594630 // Sliding Sync
595- await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ;
631+ if ( await this . supportUpdateState ( ) ) {
632+ await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ;
633+ } else {
634+ logger . error (
635+ "slididng sync cannot be used in widget mode if the client widget driver does not support the version: 'org.matrix.msc2762_update_state'" ,
636+ ) ;
637+ }
596638 }
639+
597640 this . emit ( ClientEvent . Event , event ) ;
598641 this . setSyncState ( SyncState . Syncing ) ;
599642 logger . info ( `Received event ${ event . getId ( ) } ${ event . getType ( ) } ` ) ;
@@ -623,7 +666,11 @@ export class RoomWidgetClient extends MatrixClient {
623666
624667 private onStateUpdate = async ( ev : CustomEvent < IUpdateStateToWidgetActionRequest > ) : Promise < void > => {
625668 ev . preventDefault ( ) ;
626-
669+ if ( ! ( await this . supportUpdateState ( ) ) ) {
670+ logger . warn (
671+ "received update_state widget action but the widget driver did not claim to support 'org.matrix.msc2762_update_state'" ,
672+ ) ;
673+ }
627674 for ( const rawEvent of ev . detail . data . state ) {
628675 // Verify the room ID matches, since it's possible for the client to
629676 // send us state updates from other rooms if this widget is always
0 commit comments