Skip to content

Commit

Permalink
Improve types for sendStateEvent (#4105)
Browse files Browse the repository at this point in the history
  • Loading branch information
t3chguy committed Mar 20, 2024
1 parent afc3c62 commit d908036
Show file tree
Hide file tree
Showing 12 changed files with 301 additions and 42 deletions.
8 changes: 8 additions & 0 deletions spec/unit/embedded.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ class MockWidgetApi extends EventEmitter {
public transport = { reply: jest.fn() };
}

declare module "../../src/types" {
interface StateEvents {
"org.example.foo": {
hello: string;
};
}
}

describe("RoomWidgetClient", () => {
let widgetApi: MockedObject<WidgetApi>;
let client: MatrixClient;
Expand Down
23 changes: 12 additions & 11 deletions spec/unit/matrix-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,30 +38,31 @@ import * as testUtils from "../test-utils/test-utils";
import { makeBeaconInfoContent } from "../../src/content-helpers";
import { M_BEACON_INFO } from "../../src/@types/beacon";
import {
ContentHelpers,
ClientPrefix,
ConditionKind,
ContentHelpers,
Direction,
EventTimeline,
EventTimelineSet,
getHttpUriForMxc,
ICreateRoomOpts,
IPushRule,
IRequestOpts,
MatrixError,
MatrixHttpApi,
MatrixScheduler,
Method,
Room,
EventTimelineSet,
PushRuleActionName,
TweakName,
Room,
RuleId,
IPushRule,
ConditionKind,
getHttpUriForMxc,
TweakName,
} from "../../src";
import { supportsMatrixCall } from "../../src/webrtc/call";
import { makeBeaconEvent } from "../test-utils/beacon";
import {
IGNORE_INVITES_ACCOUNT_EVENT_KEY,
POLICIES_ACCOUNT_EVENT_TYPE,
PolicyRecommendation,
PolicyScope,
} from "../../src/models/invites-ignorer";
import { IOlmDevice } from "../../src/crypto/algorithms/megolm";
Expand Down Expand Up @@ -2082,10 +2083,10 @@ describe("MatrixClient", function () {
await client.ignoredInvites.addSource(NEW_SOURCE_ROOM_ID);

// Add a rule in the new source room.
await client.sendStateEvent(NEW_SOURCE_ROOM_ID, PolicyScope.User, {
await client.sendStateEvent(NEW_SOURCE_ROOM_ID, EventType.PolicyRuleUser, {
entity: "*:example.org",
reason: "just a test",
recommendation: "m.ban",
recommendation: PolicyRecommendation.Ban,
});

// We should reject this invite.
Expand Down Expand Up @@ -2172,8 +2173,8 @@ describe("MatrixClient", function () {
// Check where it shows up.
const targetRoomId = ignoreInvites2.target;
const targetRoom = client.getRoom(targetRoomId) as WrappedRoom;
expect(targetRoom._state.get(PolicyScope.User)[eventId]).toBeTruthy();
expect(newSourceRoom._state.get(PolicyScope.User)?.[eventId]).toBeFalsy();
expect(targetRoom._state.get(EventType.PolicyRuleUser)[eventId]).toBeTruthy();
expect(newSourceRoom._state.get(EventType.PolicyRuleUser)?.[eventId]).toBeFalsy();
});
});

Expand Down
5 changes: 5 additions & 0 deletions src/@types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ limitations under the License.
*/

export type NonEmptyArray<T> = [T, ...T[]];

// 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] };
68 changes: 68 additions & 0 deletions src/@types/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@ limitations under the License.
*/

import { UnstableValue } from "../NamespacedValue";
import {
PolicyRuleEventContent,
RoomAvatarEventContent,
RoomCanonicalAliasEventContent,
RoomCreateEventContent,
RoomEncryptionEventContent,
RoomGuestAccessEventContent,
RoomHistoryVisibilityEventContent,
RoomJoinRulesEventContent,
RoomMemberEventContent,
RoomNameEventContent,
RoomPinnedEventsEventContent,
RoomPowerLevelsEventContent,
RoomServerAclEventContent,
RoomThirdPartyInviteEventContent,
RoomTombstoneEventContent,
RoomTopicEventContent,
SpaceChildEventContent,
SpaceParentEventContent,
} from "./state_events";
import {
ExperimentalGroupCallRoomMemberState,
IGroupCallRoomMemberState,
IGroupCallRoomState,
} from "../webrtc/groupCall";
import { MSC3089EventContent } from "../models/MSC3089Branch";
import { M_BEACON_INFO, MBeaconInfoEventContent } from "./beacon";
import { XOR } from "./common";

export enum EventType {
// Room state events
Expand All @@ -35,6 +63,11 @@ export enum EventType {
RoomTombstone = "m.room.tombstone",
RoomPredecessor = "org.matrix.msc3946.room_predecessor",

// Moderation policy lists
PolicyRuleUser = "m.policy.rule.user",
PolicyRuleRoom = "m.policy.rule.room",
PolicyRuleServer = "m.policy.rule.server",

SpaceChild = "m.space.child",
SpaceParent = "m.space.parent",

Expand Down Expand Up @@ -260,3 +293,38 @@ export interface IEncryptedFile {
hashes: { [alg: string]: string };
v: string;
}

export interface StateEvents {
[EventType.RoomCanonicalAlias]: RoomCanonicalAliasEventContent;
[EventType.RoomCreate]: RoomCreateEventContent;
[EventType.RoomJoinRules]: RoomJoinRulesEventContent;
[EventType.RoomMember]: RoomMemberEventContent;
// XXX: Spec says this event has 3 required fields but kicking such an invitation requires sending `{}`
[EventType.RoomThirdPartyInvite]: XOR<RoomThirdPartyInviteEventContent, {}>;
[EventType.RoomPowerLevels]: RoomPowerLevelsEventContent;
[EventType.RoomName]: RoomNameEventContent;
[EventType.RoomTopic]: RoomTopicEventContent;
[EventType.RoomAvatar]: RoomAvatarEventContent;
[EventType.RoomPinnedEvents]: RoomPinnedEventsEventContent;
[EventType.RoomEncryption]: RoomEncryptionEventContent;
[EventType.RoomHistoryVisibility]: RoomHistoryVisibilityEventContent;
[EventType.RoomGuestAccess]: RoomGuestAccessEventContent;
[EventType.RoomServerAcl]: RoomServerAclEventContent;
[EventType.RoomTombstone]: RoomTombstoneEventContent;
[EventType.SpaceChild]: SpaceChildEventContent;
[EventType.SpaceParent]: SpaceParentEventContent;

[EventType.PolicyRuleUser]: XOR<PolicyRuleEventContent, {}>;
[EventType.PolicyRuleRoom]: XOR<PolicyRuleEventContent, {}>;
[EventType.PolicyRuleServer]: XOR<PolicyRuleEventContent, {}>;

// MSC3401
[EventType.GroupCallPrefix]: IGroupCallRoomState;
[EventType.GroupCallMemberPrefix]: XOR<IGroupCallRoomMemberState, ExperimentalGroupCallRoomMemberState>;

// MSC3089
[UNSTABLE_MSC3089_BRANCH.name]: MSC3089EventContent;

// MSC3672
[M_BEACON_INFO.name]: MBeaconInfoEventContent;
}
19 changes: 6 additions & 13 deletions src/@types/partials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

export interface IImageInfo {
size?: number;
mimetype?: string;
thumbnail_info?: {
// eslint-disable-line camelcase
w?: number;
h?: number;
size?: number;
mimetype?: string;
};
w?: number;
h?: number;
}
import { ImageInfo } from "./media";

/**
* @deprecated use {@link ImageInfo} instead.
*/
export type IImageInfo = ImageInfo;

export enum Visibility {
Public = "public",
Expand Down
144 changes: 144 additions & 0 deletions src/@types/state_events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
Copyright 2024 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import { RoomType } from "./event";
import { GuestAccess, HistoryVisibility, RestrictedAllowType } from "./partials";
import { ImageInfo } from "./media";
import { PolicyRecommendation } from "../models/invites-ignorer";

export interface RoomCanonicalAliasEventContent {
alias?: string;
alt_aliases?: string[];
}

export interface RoomCreateEventContent {
"creator"?: string;
"m.federate"?: boolean;
"predecessor"?: {
event_id: string;
room_id: string;
};
"room_version"?: string;
"type"?: RoomType;
}

export interface RoomJoinRulesEventContent {
allow?: {
room_id: string;
type: RestrictedAllowType;
}[];
}

export interface RoomMemberEventContent {
avatar_url?: string;
displayname?: string;
is_direct?: boolean;
join_authorised_via_users_server?: string;
membership: "invite" | "join" | "knock" | "leave" | "ban";
reason?: string;
third_party_invite?: {
display_name: string;
signed: {
mxid: string;
token: string;
ts: number;
};
};
}

export interface RoomThirdPartyInviteEventContent {
display_name: string;
key_validity_url: string;
public_key: string;
public_keys: {
key_validity_url?: string;
public_key: string;
}[];
}

export interface RoomPowerLevelsEventContent {
ban?: number;
events?: { [eventType: string]: number };
events_default?: number;
invite?: number;
kick?: number;
notifications?: {
room?: number;
};
redact?: number;
state_default?: number;
users?: { [userId: string]: number };
users_default?: number;
}

export interface RoomNameEventContent {
name: string;
}

export interface RoomTopicEventContent {
topic: string;
}

export interface RoomAvatarEventContent {
url?: string;
info?: ImageInfo;
}

export interface RoomPinnedEventsEventContent {
pinned: string[];
}

export interface RoomEncryptionEventContent {
algorithm: "m.megolm.v1.aes-sha2";
rotation_period_ms?: number;
rotation_period_msgs?: number;
}

export interface RoomHistoryVisibilityEventContent {
history_visibility: HistoryVisibility;
}

export interface RoomGuestAccessEventContent {
guest_access: GuestAccess;
}

export interface RoomServerAclEventContent {
allow?: string[];
allow_ip_literals?: boolean;
deny?: string[];
}

export interface RoomTombstoneEventContent {
body: string;
replacement_room: string;
}

export interface SpaceChildEventContent {
order?: string;
suggested?: boolean;
via?: string[];
}

export interface SpaceParentEventContent {
canonical?: boolean;
via?: string[];
}

export interface PolicyRuleEventContent {
entity: string;
reason: string;
recommendation: PolicyRecommendation;
}

0 comments on commit d908036

Please sign in to comment.