@@ -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,6 +289,31 @@ export class RoomWidgetClient extends MatrixClient {
284289
285290 await this . widgetApiReady ;
286291
292+ if ( ! ( await this . supportUpdateState ( ) ) ) {
293+ // Backfill the requested events
294+ // We only get the most recent event for every type + state key combo,
295+ // so it doesn't really matter what order we inject them in
296+ await Promise . all (
297+ this . capabilities . receiveState ?. map ( async ( { eventType, stateKey } ) => {
298+ const rawEvents = await this . widgetApi . readStateEvents ( eventType , undefined , stateKey , [
299+ this . roomId ,
300+ ] ) ;
301+ const events = rawEvents . map ( ( rawEvent ) => new MatrixEvent ( rawEvent as Partial < IEvent > ) ) ;
302+
303+ if ( this . syncApi instanceof SyncApi ) {
304+ // Passing events as `stateAfterEventList` will update the state.
305+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , events ) ;
306+ } else {
307+ await this . syncApi ! . injectRoomEvents ( this . room ! , events ) ; // Sliding Sync
308+ }
309+ events . forEach ( ( event ) => {
310+ this . emit ( ClientEvent . Event , event ) ;
311+ logger . info ( `Backfilled event ${ event . getId ( ) } ${ event . getType ( ) } ${ event . getStateKey ( ) } ` ) ;
312+ } ) ;
313+ } ) ?? [ ] ,
314+ ) ;
315+ }
316+
287317 if ( opts . clientWellKnownPollPeriod !== undefined ) {
288318 this . clientWellKnownIntervalID = setInterval ( ( ) => {
289319 this . fetchClientWellKnown ( ) ;
@@ -563,11 +593,24 @@ export class RoomWidgetClient extends MatrixClient {
563593 await this . updateTxId ( event ) ;
564594
565595 if ( this . syncApi instanceof SyncApi ) {
566- await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ ] , [ event ] ) ;
596+ if ( await this . supportUpdateState ( ) ) {
597+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ ] , [ event ] ) ;
598+ } else {
599+ // Passing undefined for `stateAfterEventList` will make `injectRoomEvents` run in legacy mode
600+ // -> state events in `timelineEventList` will update the state.
601+ await this . syncApi . injectRoomEvents ( this . room ! , [ ] , undefined , [ event ] ) ;
602+ }
567603 } else {
568604 // Sliding Sync
569- await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ;
605+ if ( await this . supportUpdateState ( ) ) {
606+ await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ;
607+ } else {
608+ logger . error (
609+ "slididng sync cannot be used in widget mode if the client widget driver does not support the version: 'org.matrix.msc2762_update_state'" ,
610+ ) ;
611+ }
570612 }
613+
571614 this . emit ( ClientEvent . Event , event ) ;
572615 this . setSyncState ( SyncState . Syncing ) ;
573616 logger . info ( `Received event ${ event . getId ( ) } ${ event . getType ( ) } ` ) ;
@@ -597,7 +640,11 @@ export class RoomWidgetClient extends MatrixClient {
597640
598641 private onStateUpdate = async ( ev : CustomEvent < IUpdateStateToWidgetActionRequest > ) : Promise < void > => {
599642 ev . preventDefault ( ) ;
600-
643+ if ( ! ( await this . supportUpdateState ( ) ) ) {
644+ logger . warn (
645+ "received update_state widget action but the widget driver did not claim to support 'org.matrix.msc2762_update_state'" ,
646+ ) ;
647+ }
601648 for ( const rawEvent of ev . detail . data . state ) {
602649 // Verify the room ID matches, since it's possible for the client to
603650 // send us state updates from other rooms if this widget is always
0 commit comments