Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Improve types for sendStateEvent (#12331)
Browse files Browse the repository at this point in the history
  • Loading branch information
t3chguy authored Mar 20, 2024
1 parent 4a05de4 commit 2cbf928
Show file tree
Hide file tree
Showing 17 changed files with 89 additions and 44 deletions.
3 changes: 2 additions & 1 deletion playwright/e2e/room/room-header.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Page } from "@playwright/test";

import { test, expect } from "../../element-web-test";
import { ElementAppPage } from "../../pages/ElementAppPage";
import type { Container } from "../../../src/stores/widgets/types";

test.describe("Room Header", () => {
test.use({
Expand Down Expand Up @@ -227,7 +228,7 @@ test.describe("Room Header", () => {
{
widgets: {
[id]: {
container: "top",
container: "top" as Container,
index: 1,
width: 100,
height: 0,
Expand Down
3 changes: 2 additions & 1 deletion playwright/pages/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import type {
Visibility,
UploadOpts,
Upload,
StateEvents,
} from "matrix-js-sdk/src/matrix";
import { Credentials } from "../plugins/homeserver";

Expand Down Expand Up @@ -407,7 +408,7 @@ export class Client {
const client = await this.prepareClient();
return client.evaluate(
async (client, { roomId, eventType, content, stateKey }) => {
return client.sendStateEvent(roomId, eventType, content, stateKey);
return client.sendStateEvent(roomId, eventType as keyof StateEvents, content, stateKey);
},
{ roomId, eventType, content, stateKey },
);
Expand Down
7 changes: 1 addition & 6 deletions src/@types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@ limitations under the License.

import { JSXElementConstructor } from "react";

export type { NonEmptyArray } from "matrix-js-sdk/src/matrix";

// Based on https://stackoverflow.com/a/53229857/3532235
export type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
export type XOR<T, U> = T | U extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;
export type Writeable<T> = { -readonly [P in keyof T]: T[P] };
export type { NonEmptyArray, XOR, Writeable } from "matrix-js-sdk/src/matrix";

export type ComponentClass = keyof JSX.IntrinsicElements | JSXElementConstructor<any>;

Expand Down
4 changes: 2 additions & 2 deletions src/ScalarMessaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ Response:
*/

import { IContent, MatrixEvent, IEvent } from "matrix-js-sdk/src/matrix";
import { IContent, MatrixEvent, IEvent, StateEvents } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";

import { MatrixClientPeg } from "./MatrixClientPeg";
Expand Down Expand Up @@ -721,7 +721,7 @@ async function getOpenIdToken(event: MessageEvent<any>): Promise<void> {

async function sendEvent(
event: MessageEvent<{
type: string;
type: keyof StateEvents;
state_key?: string;
content?: IContent;
}>,
Expand Down
17 changes: 9 additions & 8 deletions src/SlashCommands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ limitations under the License.
*/

import * as React from "react";
import { User, IContent, Direction, ContentHelpers, MRoomTopicEventContent } from "matrix-js-sdk/src/matrix";
import { ContentHelpers, Direction, EventType, IContent, MRoomTopicEventContent, User } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { RoomMemberEventContent } from "matrix-js-sdk/src/types";

import dis from "./dispatcher/dispatcher";
import { _t, _td, UserFriendlyError } from "./languageHandler";
Expand Down Expand Up @@ -239,12 +240,12 @@ export const Commands = [
isEnabled: (cli) => !isCurrentLocalRoom(cli),
runFn: function (cli, roomId, threadId, args) {
if (args) {
const ev = cli.getRoom(roomId)?.currentState.getStateEvents("m.room.member", cli.getSafeUserId());
const content = {
const ev = cli.getRoom(roomId)?.currentState.getStateEvents(EventType.RoomMember, cli.getSafeUserId());
const content: RoomMemberEventContent = {
...(ev ? ev.getContent() : { membership: "join" }),
displayname: args,
};
return success(cli.sendStateEvent(roomId, "m.room.member", content, cli.getSafeUserId()));
return success(cli.sendStateEvent(roomId, EventType.RoomMember, content, cli.getSafeUserId()));
}
return reject(this.getUsage());
},
Expand All @@ -265,7 +266,7 @@ export const Commands = [
return success(
promise.then((url) => {
if (!url) return;
return cli.sendStateEvent(roomId, "m.room.avatar", { url }, "");
return cli.sendStateEvent(roomId, EventType.RoomAvatar, { url }, "");
}),
);
},
Expand All @@ -289,12 +290,12 @@ export const Commands = [
return success(
promise.then((url) => {
if (!url) return;
const ev = room?.currentState.getStateEvents("m.room.member", userId);
const content = {
const ev = room?.currentState.getStateEvents(EventType.RoomMember, userId);
const content: RoomMemberEventContent = {
...(ev ? ev.getContent() : { membership: "join" }),
avatar_url: url,
};
return cli.sendStateEvent(roomId, "m.room.member", content, userId);
return cli.sendStateEvent(roomId, EventType.RoomMember, content, userId);
}),
);
},
Expand Down
3 changes: 2 additions & 1 deletion src/components/structures/SpaceHierarchy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
import classNames from "classnames";
import { sortBy, uniqBy } from "lodash";
import { logger } from "matrix-js-sdk/src/logger";
import { SpaceChildEventContent } from "matrix-js-sdk/src/types";

import defaultDispatcher from "../../dispatcher/dispatcher";
import { _t } from "../../languageHandler";
Expand Down Expand Up @@ -726,7 +727,7 @@ const ManageButtons: React.FC<IManageButtonsProps> = ({ hierarchy, selected, set
const existingContent = hierarchy.getRelation(parentId, childId)?.content;
if (!existingContent || existingContent.suggested === suggested) continue;

const content = {
const content: SpaceChildEventContent = {
...existingContent,
suggested: !selectionAllSuggested,
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/dialogs/devtools/RoomState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const StateEventEditor: React.FC<IEditorProps> = ({ mxEvent, onBack }) =>
);

const onSend = async ([eventType, stateKey]: string[], content: IContent): Promise<void> => {
await cli.sendStateEvent(context.room.roomId, eventType, content, stateKey);
await cli.sendStateEvent(context.room.roomId, eventType as any, content, stateKey);
};

const defaultContent = mxEvent ? stringify(mxEvent.getContent()) : undefined;
Expand Down
7 changes: 4 additions & 3 deletions src/components/views/room_settings/AliasSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ limitations under the License.
*/

import React, { ChangeEvent, ContextType, createRef, SyntheticEvent } from "react";
import { IContent, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { RoomCanonicalAliasEventContent } from "matrix-js-sdk/src/types";

import EditableItemList from "../elements/EditableItemList";
import { _t } from "../../../languageHandler";
Expand Down Expand Up @@ -169,7 +170,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
updatingCanonicalAlias: true,
});

const eventContent: IContent = {
const eventContent: RoomCanonicalAliasEventContent = {
alt_aliases: this.state.altAliases,
};

Expand Down Expand Up @@ -197,7 +198,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
updatingCanonicalAlias: true,
});

const eventContent: IContent = {};
const eventContent: RoomCanonicalAliasEventContent = {};

if (this.state.canonicalAlias) {
eventContent["alias"] = this.state.canonicalAlias;
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/rooms/ThirdPartyMemberInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ limitations under the License.
*/

import React from "react";
import { MatrixEvent, Room, RoomStateEvent, EventType } from "matrix-js-sdk/src/matrix";
import { EventType, MatrixEvent, Room, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { Button, Text } from "@vector-im/compound-web";

Expand Down Expand Up @@ -101,7 +101,7 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState

public onKickClick = (): void => {
MatrixClientPeg.safeGet()
.sendStateEvent(this.state.roomId, "m.room.third_party_invite", {}, this.state.stateKey)
.sendStateEvent(this.state.roomId, EventType.RoomThirdPartyInvite, {}, this.state.stateKey)
.catch((err) => {
logger.error(err);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import React from "react";
import { EventType, RoomMember, RoomState, RoomStateEvent, Room, IContent } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { throttle, get } from "lodash";
import { RoomPowerLevelsEventContent } from "matrix-js-sdk/src/types";

import { _t, _td, TranslationKey } from "../../../../../languageHandler";
import AccessibleButton from "../../../elements/AccessibleButton";
Expand Down Expand Up @@ -178,7 +179,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
const client = this.context;
const room = this.props.room;
const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
let plContent = plEvent?.getContent() ?? {};
let plContent = plEvent?.getContent<RoomPowerLevelsEventContent>() ?? {};

// Clone the power levels just in case
plContent = Object.assign({}, plContent);
Expand All @@ -192,7 +193,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
} else {
const keyPath = powerLevelKey.split(".");
let parentObj: IContent = {};
let currentObj = plContent;
let currentObj: IContent = plContent;
for (const key of keyPath) {
if (!currentObj[key]) {
currentObj[key] = {};
Expand Down Expand Up @@ -222,7 +223,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
const client = this.context;
const room = this.props.room;
const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
let plContent = plEvent?.getContent() ?? {};
let plContent = plEvent?.getContent<RoomPowerLevelsEventContent>() ?? {};

// Clone the power levels just in case
plContent = Object.assign({}, plContent);
Expand Down
14 changes: 9 additions & 5 deletions src/mjolnir/BanList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,24 @@ limitations under the License.

// Inspiration largely taken from Mjolnir itself

import { EventType } from "matrix-js-sdk/src/matrix";

import { ListRule, RECOMMENDATION_BAN, recommendationToStable } from "./ListRule";
import { MatrixClientPeg } from "../MatrixClientPeg";

export const RULE_USER = "m.policy.rule.user";
export const RULE_ROOM = "m.policy.rule.room";
export const RULE_SERVER = "m.policy.rule.server";
export const RULE_USER = EventType.PolicyRuleUser;
export const RULE_ROOM = EventType.PolicyRuleRoom;
export const RULE_SERVER = EventType.PolicyRuleServer;

// m.room.* events are legacy from when MSC2313 changed to m.policy.* last minute.
export const USER_RULE_TYPES = [RULE_USER, "m.room.rule.user", "org.matrix.mjolnir.rule.user"];
export const ROOM_RULE_TYPES = [RULE_ROOM, "m.room.rule.room", "org.matrix.mjolnir.rule.room"];
export const SERVER_RULE_TYPES = [RULE_SERVER, "m.room.rule.server", "org.matrix.mjolnir.rule.server"];
export const ALL_RULE_TYPES = [...USER_RULE_TYPES, ...ROOM_RULE_TYPES, ...SERVER_RULE_TYPES];

export function ruleTypeToStable(rule: string): string | null {
export function ruleTypeToStable(
rule: string,
): EventType.PolicyRuleUser | EventType.PolicyRuleRoom | EventType.PolicyRuleServer | null {
if (USER_RULE_TYPES.includes(rule)) {
return RULE_USER;
}
Expand Down Expand Up @@ -72,7 +76,7 @@ export class BanList {
{
entity: entity,
reason: reason,
recommendation: recommendationToStable(RECOMMENDATION_BAN, true),
recommendation: recommendationToStable(RECOMMENDATION_BAN, true)!,
},
"rule:" + entity,
);
Expand Down
18 changes: 14 additions & 4 deletions src/mjolnir/ListRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,24 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

// We are using experimental APIs here, so we need to disable the linter
// eslint-disable-next-line no-restricted-imports
import { PolicyRecommendation } from "matrix-js-sdk/src/models/invites-ignorer";

import { MatrixGlob } from "../utils/MatrixGlob";

// Inspiration largely taken from Mjolnir itself

export const RECOMMENDATION_BAN = "m.ban";
export const RECOMMENDATION_BAN_TYPES = [RECOMMENDATION_BAN, "org.matrix.mjolnir.ban"];
export const RECOMMENDATION_BAN = PolicyRecommendation.Ban;
export const RECOMMENDATION_BAN_TYPES: PolicyRecommendation[] = [
RECOMMENDATION_BAN,
"org.matrix.mjolnir.ban" as PolicyRecommendation,
];

export function recommendationToStable(recommendation: string, unstable = true): string | null {
export function recommendationToStable(
recommendation: PolicyRecommendation,
unstable = true,
): PolicyRecommendation | null {
if (RECOMMENDATION_BAN_TYPES.includes(recommendation)) {
return unstable ? RECOMMENDATION_BAN_TYPES[RECOMMENDATION_BAN_TYPES.length - 1] : RECOMMENDATION_BAN;
}
Expand All @@ -35,7 +45,7 @@ export class ListRule {
private readonly _reason: string;
private readonly _kind: string;

public constructor(entity: string, action: string, reason: string, kind: string) {
public constructor(entity: string, action: PolicyRecommendation, reason: string, kind: string) {
this._glob = new MatrixGlob(entity);
this._entity = entity;
this._action = recommendationToStable(action, false);
Expand Down
12 changes: 10 additions & 2 deletions src/settings/handlers/RoomSettingsHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { MatrixClient, MatrixEvent, RoomState, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import { MatrixClient, MatrixEvent, RoomState, RoomStateEvent, StateEvents } from "matrix-js-sdk/src/matrix";
import { defer } from "matrix-js-sdk/src/utils";

import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler";
Expand All @@ -24,6 +24,9 @@ import { SettingLevel } from "../SettingLevel";
import { WatchManager } from "../WatchManager";

const DEFAULT_SETTINGS_EVENT_TYPE = "im.vector.web.settings";
const PREVIEW_URLS_EVENT_TYPE = "org.matrix.room.preview_urls";

type RoomSettingsEventType = typeof DEFAULT_SETTINGS_EVENT_TYPE | typeof PREVIEW_URLS_EVENT_TYPE;

/**
* Gets and sets settings at the "room" level.
Expand Down Expand Up @@ -88,7 +91,12 @@ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandl
}

// helper function to send state event then await it being echoed back
private async sendStateEvent(roomId: string, eventType: string, field: string, value: any): Promise<void> {
private async sendStateEvent<K extends RoomSettingsEventType, F extends keyof StateEvents[K]>(
roomId: string,
eventType: K,
field: F,
value: StateEvents[K][F],
): Promise<void> {
const content = this.getSettings(roomId, eventType) || {};
content[field] = value;

Expand Down
15 changes: 14 additions & 1 deletion src/stores/widgets/StopGapWidgetDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
Room,
Direction,
THREAD_RELATION_TYPE,
StateEvents,
} from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import {
Expand Down Expand Up @@ -241,7 +242,19 @@ export class StopGapWidgetDriver extends WidgetDriver {
return allAllowed;
}

public async sendEvent<K extends keyof StateEvents>(
eventType: K,
content: StateEvents[K],
stateKey?: string,
targetRoomId?: string,
): Promise<ISendEventDetails>;
public async sendEvent(
eventType: Exclude<EventType, keyof StateEvents>,
content: IContent,
stateKey: null,
targetRoomId?: string,
): Promise<ISendEventDetails>;
public async sendEvent<K extends keyof StateEvents>(
eventType: string,
content: IContent,
stateKey?: string | null,
Expand All @@ -255,7 +268,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
let r: { event_id: string } | null;
if (stateKey !== null) {
// state event
r = await client.sendStateEvent(roomId, eventType, content, stateKey);
r = await client.sendStateEvent(roomId, eventType as K, content as StateEvents[K], stateKey);
} else if (eventType === EventType.RoomRedaction) {
// special case: extract the `redacts` property and call redact
r = await client.redactEvent(roomId, content["redacts"]);
Expand Down
2 changes: 1 addition & 1 deletion src/utils/RoomUpgrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export async function upgradeRoom(
EventType.SpaceChild,
{
...(currentEv?.getContent() || {}), // copy existing attributes like suggested
via: [cli.getDomain()],
via: [cli.getDomain()!],
},
newRoomId,
);
Expand Down
3 changes: 2 additions & 1 deletion test/components/views/rooms/LegacyRoomHeader-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
RoomStateEvent,
PendingEventOrdering,
ISearchResults,
IContent,
} from "matrix-js-sdk/src/matrix";
import { CallType } from "matrix-js-sdk/src/webrtc/call";
import { ClientWidgetApi, Widget } from "matrix-widget-api";
Expand Down Expand Up @@ -111,7 +112,7 @@ describe("LegacyRoomHeader", () => {
room: roomId,
user: alice.userId,
skey: stateKey,
content,
content: content as IContent,
});
room.addLiveEvents([event]);
return { event_id: event.getId()! };
Expand Down
Loading

0 comments on commit 2cbf928

Please sign in to comment.