@@ -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,14 +288,41 @@ export class RoomWidgetClient extends MatrixClient {
283288
284289 await this . widgetApiReady ;
285290
291+ // sync room state:
292+ if ( await this . supportUpdateState ( ) ) {
293+ // This will resolve once the client driver has sent us all the allowed room state.
294+ await this . roomStateSynced ;
295+ } else {
296+ // Backfill the requested events
297+ // We only get the most recent event for every type + state key combo,
298+ // so it doesn't really matter what order we inject them in
299+ await Promise . all (
300+ this . capabilities . receiveState ?. map ( async ( { eventType, stateKey } ) => {
301+ const rawEvents = await this . widgetApi . readStateEvents ( eventType , undefined , stateKey , [
302+ this . roomId ,
303+ ] ) ;
304+ const events = rawEvents . map ( ( rawEvent ) => new MatrixEvent ( rawEvent as Partial < IEvent > ) ) ;
305+
306+ if ( this . syncApi instanceof SyncApi ) {
307+ // Passing events as `stateAfterEventList` will update the state.
308+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , events ) ;
309+ } else {
310+ await this . syncApi ! . injectRoomEvents ( this . room ! , events ) ; // Sliding Sync
311+ }
312+ events . forEach ( ( event ) => {
313+ this . emit ( ClientEvent . Event , event ) ;
314+ logger . info ( `Backfilled event ${ event . getId ( ) } ${ event . getType ( ) } ${ event . getStateKey ( ) } ` ) ;
315+ } ) ;
316+ } ) ?? [ ] ,
317+ ) ;
318+ }
319+
286320 if ( opts . clientWellKnownPollPeriod !== undefined ) {
287321 this . clientWellKnownIntervalID = setInterval ( ( ) => {
288322 this . fetchClientWellKnown ( ) ;
289323 } , 1000 * opts . clientWellKnownPollPeriod ) ;
290324 this . fetchClientWellKnown ( ) ;
291325 }
292-
293- await this . roomStateSynced ;
294326 this . setSyncState ( SyncState . Syncing ) ;
295327 logger . info ( "Finished initial sync" ) ;
296328
@@ -589,11 +621,24 @@ export class RoomWidgetClient extends MatrixClient {
589621 await this . updateTxId ( event ) ;
590622
591623 if ( this . syncApi instanceof SyncApi ) {
592- await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ ] , [ event ] ) ;
624+ if ( await this . supportUpdateState ( ) ) {
625+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ ] , [ event ] ) ;
626+ } else {
627+ // Passing undefined for `stateAfterEventList` will make `injectRoomEvents` run in legacy mode
628+ // -> state events in `timelineEventList` will update the state.
629+ await this . syncApi . injectRoomEvents ( this . room ! , [ ] , undefined , [ event ] ) ;
630+ }
593631 } else {
594632 // Sliding Sync
595- await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ;
633+ if ( await this . supportUpdateState ( ) ) {
634+ await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ;
635+ } else {
636+ logger . error (
637+ "slididng sync cannot be used in widget mode if the client widget driver does not support the version: 'org.matrix.msc2762_update_state'" ,
638+ ) ;
639+ }
596640 }
641+
597642 this . emit ( ClientEvent . Event , event ) ;
598643 this . setSyncState ( SyncState . Syncing ) ;
599644 logger . info ( `Received event ${ event . getId ( ) } ${ event . getType ( ) } ` ) ;
@@ -623,7 +668,11 @@ export class RoomWidgetClient extends MatrixClient {
623668
624669 private onStateUpdate = async ( ev : CustomEvent < IUpdateStateToWidgetActionRequest > ) : Promise < void > => {
625670 ev . preventDefault ( ) ;
626-
671+ if ( ! ( await this . supportUpdateState ( ) ) ) {
672+ logger . warn (
673+ "received update_state widget action but the widget driver did not claim to support 'org.matrix.msc2762_update_state'" ,
674+ ) ;
675+ }
627676 for ( const rawEvent of ev . detail . data . state ) {
628677 // Verify the room ID matches, since it's possible for the client to
629678 // send us state updates from other rooms if this widget is always
0 commit comments