@@ -29,6 +29,7 @@ import {
2929 IWidgetApiResponse ,
3030 IWidgetApiResponseData ,
3131 IUpdateStateToWidgetActionRequest ,
32+ UnstableApiVersion ,
3233} from "matrix-widget-api" ;
3334
3435import { MatrixEvent , IEvent , IContent , EventStatus } from "./models/event.ts" ;
@@ -260,6 +261,10 @@ export class RoomWidgetClient extends MatrixClient {
260261 if ( sendContentLoaded ) widgetApi . sendContentLoaded ( ) ;
261262 }
262263
264+ public async supportUpdateState ( ) : Promise < boolean > {
265+ return ( await this . widgetApi . getClientVersions ( ) ) ?. includes ( UnstableApiVersion . MSC2762_UPDATE_STATE ) ;
266+ }
267+
263268 public async startClient ( opts : IStartClientOpts = { } ) : Promise < void > {
264269 this . lifecycle = new AbortController ( ) ;
265270
@@ -284,14 +289,41 @@ export class RoomWidgetClient extends MatrixClient {
284289
285290 await this . widgetApiReady ;
286291
292+ // sync room state:
293+ if ( await this . supportUpdateState ( ) ) {
294+ // This will resolve once the client driver has sent us all the allowed room state.
295+ await this . roomStateSynced ;
296+ } else {
297+ // Backfill the requested events
298+ // We only get the most recent event for every type + state key combo,
299+ // so it doesn't really matter what order we inject them in
300+ await Promise . all (
301+ this . capabilities . receiveState ?. map ( async ( { eventType, stateKey } ) => {
302+ const rawEvents = await this . widgetApi . readStateEvents ( eventType , undefined , stateKey , [
303+ this . roomId ,
304+ ] ) ;
305+ const events = rawEvents . map ( ( rawEvent ) => new MatrixEvent ( rawEvent as Partial < IEvent > ) ) ;
306+
307+ if ( this . syncApi instanceof SyncApi ) {
308+ // Passing events as `stateAfterEventList` will update the state.
309+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , events ) ;
310+ } else {
311+ await this . syncApi ! . injectRoomEvents ( this . room ! , events ) ; // Sliding Sync
312+ }
313+ events . forEach ( ( event ) => {
314+ this . emit ( ClientEvent . Event , event ) ;
315+ logger . info ( `Backfilled event ${ event . getId ( ) } ${ event . getType ( ) } ${ event . getStateKey ( ) } ` ) ;
316+ } ) ;
317+ } ) ?? [ ] ,
318+ ) ;
319+ }
320+
287321 if ( opts . clientWellKnownPollPeriod !== undefined ) {
288322 this . clientWellKnownIntervalID = setInterval ( ( ) => {
289323 this . fetchClientWellKnown ( ) ;
290324 } , 1000 * opts . clientWellKnownPollPeriod ) ;
291325 this . fetchClientWellKnown ( ) ;
292326 }
293-
294- await this . roomStateSynced ;
295327 this . setSyncState ( SyncState . Syncing ) ;
296328 logger . info ( "Finished initial sync" ) ;
297329
@@ -563,11 +595,24 @@ export class RoomWidgetClient extends MatrixClient {
563595 await this . updateTxId ( event ) ;
564596
565597 if ( this . syncApi instanceof SyncApi ) {
566- await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ ] , [ event ] ) ;
598+ if ( await this . supportUpdateState ( ) ) {
599+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ ] , [ event ] ) ;
600+ } else {
601+ // Passing undefined for `stateAfterEventList` will make `injectRoomEvents` run in legacy mode
602+ // -> state events in `timelineEventList` will update the state.
603+ await this . syncApi . injectRoomEvents ( this . room ! , [ ] , undefined , [ event ] ) ;
604+ }
567605 } else {
568606 // Sliding Sync
569- await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ;
607+ if ( await this . supportUpdateState ( ) ) {
608+ await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ;
609+ } else {
610+ logger . error (
611+ "slididng sync cannot be used in widget mode if the client widget driver does not support the version: 'org.matrix.msc2762_update_state'" ,
612+ ) ;
613+ }
570614 }
615+
571616 this . emit ( ClientEvent . Event , event ) ;
572617 this . setSyncState ( SyncState . Syncing ) ;
573618 logger . info ( `Received event ${ event . getId ( ) } ${ event . getType ( ) } ` ) ;
@@ -597,7 +642,11 @@ export class RoomWidgetClient extends MatrixClient {
597642
598643 private onStateUpdate = async ( ev : CustomEvent < IUpdateStateToWidgetActionRequest > ) : Promise < void > => {
599644 ev . preventDefault ( ) ;
600-
645+ if ( ! ( await this . supportUpdateState ( ) ) ) {
646+ logger . warn (
647+ "received update_state widget action but the widget driver did not claim to support 'org.matrix.msc2762_update_state'" ,
648+ ) ;
649+ }
601650 for ( const rawEvent of ev . detail . data . state ) {
602651 // Verify the room ID matches, since it's possible for the client to
603652 // send us state updates from other rooms if this widget is always
0 commit comments