Skip to content

Commit 89bb192

Browse files
committed
Let the client only send UpdateState if the widget supports it.
1 parent 08ca89b commit 89bb192

File tree

1 file changed

+39
-14
lines changed

1 file changed

+39
-14
lines changed

src/ClientWidgetApi.ts

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import {
4040
ISupportedVersionsActionRequest,
4141
ISupportedVersionsActionResponseData,
4242
} from "./interfaces/SupportedVersionsAction";
43-
import { CurrentApiVersions } from "./interfaces/ApiVersion";
43+
import { ApiVersion, CurrentApiVersions, UnstableApiVersion } from "./interfaces/ApiVersion";
4444
import { IScreenshotActionResponseData } from "./interfaces/ScreenshotAction";
4545
import { IVisibilityActionRequestData } from "./interfaces/VisibilityAction";
4646
import { IWidgetApiAcknowledgeResponseData, IWidgetApiResponseData } from "./interfaces/IWidgetApiResponse";
@@ -138,6 +138,7 @@ import { IUpdateStateToWidgetRequestData } from "./interfaces/UpdateStateAction"
138138
export class ClientWidgetApi extends EventEmitter {
139139
public readonly transport: ITransport;
140140

141+
private cachedWidgetVersions: ApiVersion[] | null = null;
141142
// contentLoadedActionSent is used to check that only one ContentLoaded request is send.
142143
private contentLoadedActionSent = false;
143144
private allowedCapabilities = new Set<Capability>();
@@ -227,6 +228,24 @@ export class ClientWidgetApi extends EventEmitter {
227228
this.transport.stop();
228229
}
229230

231+
public async getWidgetVersions(): Promise<ApiVersion[]> {
232+
if (Array.isArray(this.cachedWidgetVersions)) {
233+
return Promise.resolve(this.cachedWidgetVersions);
234+
}
235+
236+
try {
237+
const r = await this.transport.send<IWidgetApiRequestEmptyData, ISupportedVersionsActionResponseData>(
238+
WidgetApiToWidgetAction.SupportedApiVersions,
239+
{},
240+
);
241+
this.cachedWidgetVersions = r.supported_versions;
242+
return r.supported_versions;
243+
} catch (e) {
244+
console.warn("non-fatal error getting supported widget versions: ", e);
245+
return [];
246+
}
247+
}
248+
230249
private beginCapabilities(): void {
231250
// widget has loaded - tell all the listeners that
232251
this.emit("preparing");
@@ -1013,7 +1032,7 @@ export class ClientWidgetApi extends EventEmitter {
10131032
public async feedEvent(rawEvent: IRoomEvent, currentViewedRoomId: string): Promise<void>;
10141033
/**
10151034
* Feeds an event to the widget. As a client you are expected to call this
1016-
* for every new event in every room to which you are joined or invited.
1035+
* for every new event (including state events) in every room to which you are joined or invited.
10171036
* @param {IRoomEvent} rawEvent The event to (try to) send to the widget.
10181037
* @returns {Promise<void>} Resolves when delivered or if the widget is not
10191038
* able to read the event due to permissions, rejects if the widget failed
@@ -1082,6 +1101,7 @@ export class ClientWidgetApi extends EventEmitter {
10821101
}
10831102

10841103
private async flushRoomState(): Promise<void> {
1104+
const useUpdateState = (await this.getWidgetVersions()).includes(UnstableApiVersion.MSC2762_UPDATE_STATE);
10851105
try {
10861106
// Only send a single action once all concurrent tasks have completed
10871107
do await Promise.all([...this.pushRoomStateTasks]);
@@ -1093,10 +1113,11 @@ export class ClientWidgetApi extends EventEmitter {
10931113
events.push(...stateKeyMap.values());
10941114
}
10951115
}
1096-
await this.transport.send<IUpdateStateToWidgetRequestData>(
1097-
WidgetApiToWidgetAction.UpdateState,
1098-
{ state: events },
1099-
);
1116+
if (useUpdateState) {
1117+
await this.transport.send<IUpdateStateToWidgetRequestData>(WidgetApiToWidgetAction.UpdateState, {
1118+
state: events,
1119+
});
1120+
}
11001121
} finally {
11011122
this.flushRoomStateTask = null;
11021123
}
@@ -1146,7 +1167,7 @@ export class ClientWidgetApi extends EventEmitter {
11461167
// Assuming no other tasks are already happening concurrently,
11471168
// schedule the widget action that actually pushes the events
11481169
this.flushRoomStateTask ??= this.flushRoomState();
1149-
this.flushRoomStateTask.catch(e => console.error('Failed to push room state', e));
1170+
this.flushRoomStateTask.catch((e) => console.error("Failed to push room state", e));
11501171
}
11511172
}
11521173
}
@@ -1162,18 +1183,22 @@ export class ClientWidgetApi extends EventEmitter {
11621183
widget failed to handle the update.
11631184
*/
11641185
public async feedStateUpdate(rawEvent: IRoomEvent): Promise<void> {
1165-
if (rawEvent.state_key === undefined) throw new Error('Not a state event');
1186+
const useUpdateState = (await this.getWidgetVersions()).includes(UnstableApiVersion.MSC2762_UPDATE_STATE);
1187+
1188+
if (rawEvent.state_key === undefined) throw new Error("Not a state event");
11661189
if (
1167-
(rawEvent.room_id === this.viewedRoomId || this.canUseRoomTimeline(rawEvent.room_id))
1168-
&& this.canReceiveStateEvent(rawEvent.type, rawEvent.state_key)
1190+
(rawEvent.room_id === this.viewedRoomId || this.canUseRoomTimeline(rawEvent.room_id)) &&
1191+
this.canReceiveStateEvent(rawEvent.type, rawEvent.state_key)
11691192
) {
11701193
// Updates could race with the initial push of the room's state
11711194
if (this.pushRoomStateTasks.size === 0) {
11721195
// No initial push tasks are pending; safe to send immediately
1173-
await this.transport.send<IUpdateStateToWidgetRequestData>(
1174-
WidgetApiToWidgetAction.UpdateState,
1175-
{ state: [rawEvent] },
1176-
);
1196+
if (useUpdateState) {
1197+
// Only send state updates when using UpdateState. Otherwise we will use SendEvent.
1198+
await this.transport.send<IUpdateStateToWidgetRequestData>(WidgetApiToWidgetAction.UpdateState, {
1199+
state: [rawEvent],
1200+
});
1201+
}
11771202
} else {
11781203
// Lump the update in with whatever data will be sent in the
11791204
// initial push later. Even if we set it to an "outdated" entry

0 commit comments

Comments
 (0)