@matrix-widget-toolkit/api 4.2.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,13 @@
1
1
  import Joi from 'joi';
2
2
  import { RoomEvent, StateEvent, ToDeviceMessageEvent } from '../types';
3
+ /**
4
+ * The type of the power levels state event.
5
+ */
6
+ export declare const STATE_EVENT_POWER_LEVELS = "m.room.power_levels";
7
+ /**
8
+ * The types of type of the create event.
9
+ */
10
+ export declare const STATE_EVENT_CREATE = "m.room.create";
3
11
  /**
4
12
  * Check if the given event is a {@link StateEvent}.
5
13
  *
@@ -38,3 +46,46 @@ export declare function isValidToDeviceMessageEvent(event: unknown): event is To
38
46
  export declare const roomEventSchema: Joi.ObjectSchema<RoomEvent>;
39
47
  export declare const stateEventSchema: Joi.ObjectSchema<StateEvent>;
40
48
  export declare const toDeviceMessageSchema: Joi.ObjectSchema<ToDeviceMessageEvent>;
49
+ export type StateEventCreateContent = {
50
+ room_version?: string;
51
+ creator?: string;
52
+ additional_creators?: string[];
53
+ };
54
+ export declare const createEventSchema: Joi.ObjectSchema<StateEvent<StateEventCreateContent>>;
55
+ /**
56
+ * Validates that `event` is has a valid structure for a
57
+ * {@link StateEventCreateContent}.
58
+ * @param event - The event to validate.
59
+ * @returns True, if the event is valid.
60
+ */
61
+ export declare function isValidCreateEventSchema(event: StateEvent<unknown> | undefined): event is StateEvent<StateEventCreateContent>;
62
+ /**
63
+ * The types of actions.
64
+ */
65
+ export type PowerLevelsActions = 'invite' | 'kick' | 'ban' | 'redact';
66
+ /**
67
+ * The content of an `m.room.power_levels` event.
68
+ */
69
+ export type PowerLevelsStateEvent = {
70
+ events?: {
71
+ [key: string]: number;
72
+ };
73
+ state_default?: number;
74
+ events_default?: number;
75
+ users?: {
76
+ [key: string]: number;
77
+ };
78
+ users_default?: number;
79
+ ban?: number;
80
+ invite?: number;
81
+ kick?: number;
82
+ redact?: number;
83
+ };
84
+ export declare const powerLevelsEventSchema: Joi.ObjectSchema<StateEvent<PowerLevelsStateEvent>>;
85
+ /**
86
+ * Validates that `event` is has a valid structure for a
87
+ * {@link PowerLevelsStateEvent}.
88
+ * @param event - The event to validate.
89
+ * @returns True, if the event is valid.
90
+ */
91
+ export declare function isValidPowerLevelStateEvent(event: StateEvent<unknown>): event is StateEvent<PowerLevelsStateEvent>;
@@ -1,11 +1,12 @@
1
1
  export { generateRoomTimelineCapabilities } from './capabilities';
2
2
  export { getRoomMemberDisplayName } from './displayName';
3
- export { isRoomEvent, isStateEvent, isValidRoomEvent, isValidStateEvent as isValidStateEVent, isValidToDeviceMessageEvent, } from './events';
3
+ export { STATE_EVENT_CREATE, isRoomEvent, isStateEvent, isValidCreateEventSchema, isValidRoomEvent, isValidStateEvent as isValidStateEVent, isValidToDeviceMessageEvent, } from './events';
4
+ export type { PowerLevelsActions, PowerLevelsStateEvent, StateEventCreateContent, } from './events';
4
5
  export { WIDGET_CAPABILITY_NAVIGATE, navigateToRoom } from './navigateTo';
5
6
  export type { NavigateToRoomOptions } from './navigateTo';
6
7
  export { compareOriginServerTS } from './originServerTs';
7
- export { STATE_EVENT_POWER_LEVELS, calculateUserPowerLevel, hasActionPower, hasRoomEventPower, hasStateEventPower, isValidPowerLevelStateEvent, } from './powerLevel';
8
- export type { PowerLevelsActions, PowerLevelsStateEvent } from './powerLevel';
8
+ export { ROOM_VERSION_12_CREATOR, STATE_EVENT_POWER_LEVELS, calculateUserPowerLevel, compareUserPowerLevelToNormalPowerLevel, hasActionPower, hasRoomEventPower, hasStateEventPower, isValidPowerLevelStateEvent, } from './powerLevel';
9
+ export type { UserPowerLevelType } from './powerLevel';
9
10
  export { ROOM_EVENT_REDACTION, isValidRedactionEvent, observeRedactionEvents, redactEvent, } from './redactions';
10
11
  export type { Redaction, RedactionRoomEvent } from './redactions';
11
12
  export { getContent, getOriginalEventId, isValidEventWithRelatesTo, } from './relatesTo';
@@ -1,55 +1,39 @@
1
1
  import { StateEvent } from '../types';
2
+ import type { PowerLevelsActions, PowerLevelsStateEvent, StateEventCreateContent } from './events';
3
+ export { isValidPowerLevelStateEvent, STATE_EVENT_POWER_LEVELS, } from './events';
2
4
  /**
3
- * The name of the power levels state event.
5
+ * Room version 12 requires us to have something larger than Max integer for room creators.
6
+ * This is a workaround to allow the room creator to always have the highest power level.
4
7
  */
5
- export declare const STATE_EVENT_POWER_LEVELS = "m.room.power_levels";
8
+ export declare const ROOM_VERSION_12_CREATOR = "ROOM_VERSION_12_CREATOR";
9
+ export type UserPowerLevelType = number | typeof ROOM_VERSION_12_CREATOR;
6
10
  /**
7
- * The types of actions.
11
+ * Compare a user's power level to a normal power level.
12
+ * @param userPowerLevel - The user's power level
13
+ * @param normalPowerLevel - The normal power level
14
+ * @returns True if the user's power level is greater than or equal to the normal power level, false otherwise
8
15
  */
9
- export type PowerLevelsActions = 'invite' | 'kick' | 'ban' | 'redact';
10
- /**
11
- * The content of an `m.room.power_levels` event.
12
- */
13
- export type PowerLevelsStateEvent = {
14
- events?: {
15
- [key: string]: number;
16
- };
17
- state_default?: number;
18
- events_default?: number;
19
- users?: {
20
- [key: string]: number;
21
- };
22
- users_default?: number;
23
- ban?: number;
24
- invite?: number;
25
- kick?: number;
26
- redact?: number;
27
- };
28
- /**
29
- * Validates that `event` is has a valid structure for a
30
- * {@link PowerLevelsStateEvent}.
31
- * @param event - The event to validate.
32
- * @returns True, if the event is valid.
33
- */
34
- export declare function isValidPowerLevelStateEvent(event: StateEvent<unknown>): event is StateEvent<PowerLevelsStateEvent>;
16
+ export declare function compareUserPowerLevelToNormalPowerLevel(userPowerLevel: UserPowerLevelType, normalPowerLevel: number): boolean;
35
17
  /**
36
18
  * Check if a user has the power to send a specific room event.
37
19
  *
38
20
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event
21
+ * @param createRoomStateEvent - the `m.room.create` event for the room
39
22
  * @param userId - the id of the user
40
23
  * @param eventType - the type of room event
41
24
  * @returns if true, the user has the power
42
25
  */
43
- export declare function hasRoomEventPower(powerLevelStateEvent: PowerLevelsStateEvent | undefined, userId: string | undefined, eventType: string): boolean;
26
+ export declare function hasRoomEventPower(powerLevelStateEvent: PowerLevelsStateEvent | undefined, createRoomStateEvent: StateEvent<StateEventCreateContent> | undefined, userId: string | undefined, eventType: string): boolean;
44
27
  /**
45
28
  * Check if a user has the power to send a specific state event.
46
29
  *
47
30
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event
31
+ * @param createRoomStateEvent - the `m.room.create` event for the room
48
32
  * @param userId - the id of the user
49
33
  * @param eventType - the type of state event
50
34
  * @returns if true, the user has the power
51
35
  */
52
- export declare function hasStateEventPower(powerLevelStateEvent: PowerLevelsStateEvent | undefined, userId: string | undefined, eventType: string): boolean;
36
+ export declare function hasStateEventPower(powerLevelStateEvent: PowerLevelsStateEvent | undefined, createRoomStateEvent: StateEvent<StateEventCreateContent> | undefined, userId: string | undefined, eventType: string): boolean;
53
37
  /**
54
38
  * Check if a user has the power to perform a specific action.
55
39
  *
@@ -60,19 +44,25 @@ export declare function hasStateEventPower(powerLevelStateEvent: PowerLevelsStat
60
44
  * * redact: Redact a message from another user
61
45
  *
62
46
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event
47
+ * @param createRoomStateEvent - the `m.room.create` event for the room
63
48
  * @param userId - the id of the user
64
49
  * @param action - the action
65
50
  * @returns if true, the user has the power
66
51
  */
67
- export declare function hasActionPower(powerLevelStateEvent: PowerLevelsStateEvent | undefined, userId: string | undefined, action: PowerLevelsActions): boolean;
52
+ export declare function hasActionPower(powerLevelStateEvent: PowerLevelsStateEvent | undefined, createRoomStateEvent: StateEvent<StateEventCreateContent> | undefined, userId: string | undefined, action: PowerLevelsActions): boolean;
68
53
  /**
69
54
  * Calculate the power level of the user based on a `m.room.power_levels` event.
70
55
  *
56
+ * Note that we return the @see UserPowerLevelType type instead of a number as Room Version 12
57
+ * gives a Room creator (and additionalCreators) always the highest power level regardless
58
+ * of the highest next Powerlevel number.
59
+ *
71
60
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event.
61
+ * @param createRoomStateEvent - the `m.room.create` event for the room.
72
62
  * @param userId - the ID of the user.
73
63
  * @returns the power level of the user.
74
64
  */
75
- export declare function calculateUserPowerLevel(powerLevelStateEvent: PowerLevelsStateEvent, userId?: string): number;
65
+ export declare function calculateUserPowerLevel(powerLevelStateEvent: PowerLevelsStateEvent | undefined, createRoomStateEvent: StateEvent<StateEventCreateContent> | undefined, userId: string): UserPowerLevelType;
76
66
  /**
77
67
  * Calculate the power level that a user needs send a specific room event.
78
68
  *
@@ -80,15 +70,16 @@ export declare function calculateUserPowerLevel(powerLevelStateEvent: PowerLevel
80
70
  * @param eventType - the type of room event
81
71
  * @returns the power level that is needed
82
72
  */
83
- export declare function calculateRoomEventPowerLevel(powerLevelStateEvent: PowerLevelsStateEvent, eventType: string): number;
73
+ export declare function calculateRoomEventPowerLevel(powerLevelStateEvent: PowerLevelsStateEvent | undefined, eventType: string): number;
84
74
  /**
85
75
  * Calculate the power level that a user needs send a specific state event.
86
76
  *
87
77
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event
78
+ * @param createRoomStateEvent - the `m.room.create` event
88
79
  * @param eventType - the type of state event
89
80
  * @returns the power level that is needed
90
81
  */
91
- export declare function calculateStateEventPowerLevel(powerLevelStateEvent: PowerLevelsStateEvent, eventType: string): number;
82
+ export declare function calculateStateEventPowerLevel(powerLevelStateEvent: PowerLevelsStateEvent | undefined, createRoomStateEvent: StateEvent<StateEventCreateContent> | undefined, eventType: string): number;
92
83
  /**
93
84
  * Calculate the power level that a user needs to perform an action.
94
85
  *
@@ -102,4 +93,4 @@ export declare function calculateStateEventPowerLevel(powerLevelStateEvent: Powe
102
93
  * @param action - the action
103
94
  * @returns the power level that is needed
104
95
  */
105
- export declare function calculateActionPowerLevel(powerLevelStateEvent: PowerLevelsStateEvent, action: PowerLevelsActions): number;
96
+ export declare function calculateActionPowerLevel(powerLevelStateEvent: PowerLevelsStateEvent | undefined, action: PowerLevelsActions): number;
@@ -118,6 +118,14 @@ var __assign$2 = (undefined && undefined.__assign) || function () {
118
118
  };
119
119
  return __assign$2.apply(this, arguments);
120
120
  };
121
+ /**
122
+ * The type of the power levels state event.
123
+ */
124
+ var STATE_EVENT_POWER_LEVELS = 'm.room.power_levels';
125
+ /**
126
+ * The types of type of the create event.
127
+ */
128
+ var STATE_EVENT_CREATE = 'm.room.create';
121
129
  /**
122
130
  * Check if the given event is a {@link StateEvent}.
123
131
  *
@@ -145,7 +153,12 @@ function isRoomEvent(event) {
145
153
  // Allow any here, so that the validation works for every event
146
154
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
147
155
  function isValidRoomEvent(event) {
148
- return roomEventSchema.validate(event).error === undefined;
156
+ var result = roomEventSchema.validate(event);
157
+ if (result.error) {
158
+ console.warn('Invalid room event:', result.error.details, { event: event });
159
+ return false;
160
+ }
161
+ return true;
149
162
  }
150
163
  /**
151
164
  * Check if the given value is a valid {@link StateEvent}.
@@ -156,7 +169,12 @@ function isValidRoomEvent(event) {
156
169
  // Allow any here, so that the validation works for every event
157
170
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
158
171
  function isValidStateEvent(event) {
159
- return stateEventSchema.validate(event).error === undefined;
172
+ var result = stateEventSchema.validate(event);
173
+ if (result.error) {
174
+ console.warn('Invalid state event:', result.error.details, { event: event });
175
+ return false;
176
+ }
177
+ return true;
160
178
  }
161
179
  /**
162
180
  * Check if the given value is a valid {@link ToDeviceMessageEvent}.
@@ -165,19 +183,26 @@ function isValidStateEvent(event) {
165
183
  * @returns true if value is a valid to device message, else false.
166
184
  */
167
185
  function isValidToDeviceMessageEvent(event) {
168
- return toDeviceMessageSchema.validate(event).error === undefined;
186
+ var result = toDeviceMessageSchema.validate(event);
187
+ if (result.error) {
188
+ console.warn('Invalid to device message event:', result.error.details, {
189
+ event: event,
190
+ });
191
+ return false;
192
+ }
193
+ return true;
169
194
  }
170
- /**
171
- * Base properties to validate for all events.
172
- */
173
- var eventSchemaProps = {
174
- type: Joi.string().required(),
195
+ var eventSchemaBasicProps = {
175
196
  // Do roughly check against the format
176
197
  // https://spec.matrix.org/v1.13/appendices/#common-identifier-format
177
198
  sender: Joi.string().pattern(new RegExp('^@[^\\s:]*:\\S*$')).required(),
178
- room_id: Joi.string().pattern(new RegExp('^![^:]*:\\S*')).required(),
179
- content: Joi.object().required(),
199
+ // Prior versions of the code had checked for a server_name. However in room version 12+ this got dropped. There is no way for us to check this here.
200
+ room_id: Joi.string().pattern(new RegExp('^!')).required(),
180
201
  };
202
+ /**
203
+ * Base properties to validate for all events.
204
+ */
205
+ var eventSchemaProps = __assign$2({ type: Joi.string().required(), content: Joi.object().required() }, eventSchemaBasicProps);
181
206
  var roomEventSchema = Joi.object(__assign$2(__assign$2({}, eventSchemaProps), { event_id: Joi.string().pattern(new RegExp('^\\$.*')).required(), origin_server_ts: Joi.date().timestamp('javascript').required() })).unknown();
182
207
  var stateEventSchema = Joi.object(__assign$2(__assign$2({}, eventSchemaProps), { event_id: Joi.string().pattern(new RegExp('^\\$.*')), origin_server_ts: Joi.date().timestamp('javascript'), state_key: Joi.string().allow('').required() })).unknown();
183
208
  var toDeviceMessageSchema = Joi.object({
@@ -186,6 +211,71 @@ var toDeviceMessageSchema = Joi.object({
186
211
  encrypted: Joi.boolean().required(),
187
212
  content: Joi.object().required(),
188
213
  }).unknown();
214
+ var createEventSchema = Joi.object(__assign$2(__assign$2({}, eventSchemaBasicProps), { type: Joi.string().equal(STATE_EVENT_CREATE).required(), content: Joi.object({
215
+ // Room version 1 does not have a room version, so we allow it to be undefined.
216
+ room_version: Joi.string().optional(),
217
+ // The user ID of the creator of the room. (only from 1-10. after that we must use the sender field)
218
+ creator: Joi.string().optional(),
219
+ // Room version 12 introduces the additional_creators field.
220
+ additional_creators: Joi.array().items(Joi.string()).optional(),
221
+ })
222
+ .unknown()
223
+ .required() })).unknown();
224
+ /**
225
+ * Validates that `event` is has a valid structure for a
226
+ * {@link StateEventCreateContent}.
227
+ * @param event - The event to validate.
228
+ * @returns True, if the event is valid.
229
+ */
230
+ function isValidCreateEventSchema(event) {
231
+ if (!event) {
232
+ return true;
233
+ }
234
+ var result = createEventSchema.validate(event);
235
+ if (result.error) {
236
+ console.warn('Invalid room create message event:', result.error.details, {
237
+ event: event,
238
+ });
239
+ return false;
240
+ }
241
+ return true;
242
+ }
243
+ var powerLevelsEventSchema = Joi.object(__assign$2(__assign$2({}, eventSchemaBasicProps), {
244
+ // Strictly require to match the power levels event type
245
+ type: Joi.string().equal(STATE_EVENT_POWER_LEVELS).required(), content: Joi.object({
246
+ ban: Joi.number().optional().default(50),
247
+ events: Joi.object().pattern(Joi.string(), Joi.number()).optional(),
248
+ events_default: Joi.number().optional().default(0),
249
+ invite: Joi.number().optional().default(0),
250
+ kick: Joi.number().optional().default(50),
251
+ notifications: Joi.object({
252
+ room: Joi.number().optional().default(50),
253
+ })
254
+ .unknown()
255
+ .optional(),
256
+ redact: Joi.number().optional().default(50),
257
+ state_default: Joi.number().optional().default(50),
258
+ users: Joi.object().pattern(Joi.string(), Joi.number()).optional(),
259
+ users_default: Joi.number().optional().default(0),
260
+ })
261
+ .unknown()
262
+ .required() })).unknown();
263
+ /**
264
+ * Validates that `event` is has a valid structure for a
265
+ * {@link PowerLevelsStateEvent}.
266
+ * @param event - The event to validate.
267
+ * @returns True, if the event is valid.
268
+ */
269
+ function isValidPowerLevelStateEvent(event) {
270
+ var result = powerLevelsEventSchema.validate(event);
271
+ if (result.error) {
272
+ console.warn('Invalid powerlevel event:', result.error.details, {
273
+ event: event,
274
+ });
275
+ return false;
276
+ }
277
+ return true;
278
+ }
189
279
 
190
280
  /*
191
281
  * Copyright 2022 Nordeck IT + Consulting GmbH
@@ -313,95 +403,63 @@ function compareOriginServerTS(a, b) {
313
403
  * limitations under the License.
314
404
  */
315
405
  /**
316
- * The name of the power levels state event.
406
+ * Room version 12 requires us to have something larger than Max integer for room creators.
407
+ * This is a workaround to allow the room creator to always have the highest power level.
317
408
  */
318
- var STATE_EVENT_POWER_LEVELS = 'm.room.power_levels';
319
- function isNumberOrUndefined(value) {
320
- return value === undefined || typeof value === 'number';
321
- }
322
- function isStringToNumberMapOrUndefined(value) {
323
- return (value === undefined ||
324
- (value !== null &&
325
- typeof value === 'object' &&
326
- Object.entries(value).every(function (_a) {
327
- var k = _a[0], v = _a[1];
328
- return typeof k === 'string' && typeof v === 'number';
329
- })));
330
- }
409
+ var ROOM_VERSION_12_CREATOR = 'ROOM_VERSION_12_CREATOR';
331
410
  /**
332
- * Validates that `event` is has a valid structure for a
333
- * {@link PowerLevelsStateEvent}.
334
- * @param event - The event to validate.
335
- * @returns True, if the event is valid.
411
+ * Compare a user's power level to a normal power level.
412
+ * @param userPowerLevel - The user's power level
413
+ * @param normalPowerLevel - The normal power level
414
+ * @returns True if the user's power level is greater than or equal to the normal power level, false otherwise
336
415
  */
337
- function isValidPowerLevelStateEvent(event) {
338
- if (event.type !== STATE_EVENT_POWER_LEVELS ||
339
- typeof event.content !== 'object') {
340
- return false;
341
- }
342
- var content = event.content;
343
- if (!isStringToNumberMapOrUndefined(content.events)) {
344
- return false;
345
- }
346
- if (!isNumberOrUndefined(content.state_default)) {
347
- return false;
348
- }
349
- if (!isNumberOrUndefined(content.events_default)) {
350
- return false;
351
- }
352
- if (!isStringToNumberMapOrUndefined(content.users)) {
353
- return false;
354
- }
355
- if (!isNumberOrUndefined(content.users_default)) {
356
- return false;
357
- }
358
- if (!isNumberOrUndefined(content.ban)) {
359
- return false;
360
- }
361
- if (!isNumberOrUndefined(content.invite)) {
362
- return false;
363
- }
364
- if (!isNumberOrUndefined(content.kick)) {
365
- return false;
416
+ function compareUserPowerLevelToNormalPowerLevel(userPowerLevel, normalPowerLevel) {
417
+ if (userPowerLevel === ROOM_VERSION_12_CREATOR) {
418
+ // Room version 12 creator has the highest power level.
419
+ return true;
366
420
  }
367
- if (!isNumberOrUndefined(content.redact)) {
421
+ if (typeof userPowerLevel !== 'number') {
422
+ // If the user power level is not a number, we cannot compare it to a normal power level.
368
423
  return false;
369
424
  }
370
- return true;
425
+ // Compare the user power level to the normal power level.
426
+ return userPowerLevel >= normalPowerLevel;
371
427
  }
372
428
  /**
373
429
  * Check if a user has the power to send a specific room event.
374
430
  *
375
431
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event
432
+ * @param createRoomStateEvent - the `m.room.create` event for the room
376
433
  * @param userId - the id of the user
377
434
  * @param eventType - the type of room event
378
435
  * @returns if true, the user has the power
379
436
  */
380
- function hasRoomEventPower(powerLevelStateEvent, userId, eventType) {
381
- if (!powerLevelStateEvent) {
382
- // See https://github.com/matrix-org/matrix-spec/blob/203b9756f52adfc2a3b63d664f18cdbf9f8bf126/data/event-schemas/schema/m.room.power_levels.yaml#L36-L43
383
- return true;
437
+ function hasRoomEventPower(powerLevelStateEvent, createRoomStateEvent, userId, eventType) {
438
+ if (!userId) {
439
+ // This is invalid but required to be checked due to widget API which may not know it
440
+ throw new Error('Cannot check action power without a user ID. Please provide a user ID.');
384
441
  }
385
- var userLevel = calculateUserPowerLevel(powerLevelStateEvent, userId);
442
+ var userLevel = calculateUserPowerLevel(powerLevelStateEvent, createRoomStateEvent, userId);
386
443
  var eventLevel = calculateRoomEventPowerLevel(powerLevelStateEvent, eventType);
387
- return userLevel >= eventLevel;
444
+ return compareUserPowerLevelToNormalPowerLevel(userLevel, eventLevel);
388
445
  }
389
446
  /**
390
447
  * Check if a user has the power to send a specific state event.
391
448
  *
392
449
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event
450
+ * @param createRoomStateEvent - the `m.room.create` event for the room
393
451
  * @param userId - the id of the user
394
452
  * @param eventType - the type of state event
395
453
  * @returns if true, the user has the power
396
454
  */
397
- function hasStateEventPower(powerLevelStateEvent, userId, eventType) {
398
- if (!powerLevelStateEvent) {
399
- // See https://github.com/matrix-org/matrix-spec/blob/203b9756f52adfc2a3b63d664f18cdbf9f8bf126/data/event-schemas/schema/m.room.power_levels.yaml#L36-L43
400
- return true;
455
+ function hasStateEventPower(powerLevelStateEvent, createRoomStateEvent, userId, eventType) {
456
+ if (!userId) {
457
+ // This is invalid but required to be checked due to widget API which may not know it
458
+ throw new Error('Cannot check action power without a user ID. Please provide a user ID.');
401
459
  }
402
- var userLevel = calculateUserPowerLevel(powerLevelStateEvent, userId);
403
- var eventLevel = calculateStateEventPowerLevel(powerLevelStateEvent, eventType);
404
- return userLevel >= eventLevel;
460
+ var userLevel = calculateUserPowerLevel(powerLevelStateEvent, createRoomStateEvent, userId);
461
+ var eventLevel = calculateStateEventPowerLevel(powerLevelStateEvent, createRoomStateEvent, eventType);
462
+ return compareUserPowerLevelToNormalPowerLevel(userLevel, eventLevel);
405
463
  }
406
464
  /**
407
465
  * Check if a user has the power to perform a specific action.
@@ -413,30 +471,74 @@ function hasStateEventPower(powerLevelStateEvent, userId, eventType) {
413
471
  * * redact: Redact a message from another user
414
472
  *
415
473
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event
474
+ * @param createRoomStateEvent - the `m.room.create` event for the room
416
475
  * @param userId - the id of the user
417
476
  * @param action - the action
418
477
  * @returns if true, the user has the power
419
478
  */
420
- function hasActionPower(powerLevelStateEvent, userId, action) {
421
- if (!powerLevelStateEvent) {
422
- // See https://github.com/matrix-org/matrix-spec/blob/203b9756f52adfc2a3b63d664f18cdbf9f8bf126/data/event-schemas/schema/m.room.power_levels.yaml#L36-L43
423
- return true;
479
+ function hasActionPower(powerLevelStateEvent, createRoomStateEvent, userId, action) {
480
+ if (!userId) {
481
+ // This is invalid but required to be checked due to widget API which may not know it
482
+ throw new Error('Cannot check action power without a user ID. Please provide a user ID.');
424
483
  }
425
- var userLevel = calculateUserPowerLevel(powerLevelStateEvent, userId);
484
+ var userLevel = calculateUserPowerLevel(powerLevelStateEvent, createRoomStateEvent, userId);
426
485
  var eventLevel = calculateActionPowerLevel(powerLevelStateEvent, action);
427
- return userLevel >= eventLevel;
486
+ return compareUserPowerLevelToNormalPowerLevel(userLevel, eventLevel);
428
487
  }
429
488
  /**
430
489
  * Calculate the power level of the user based on a `m.room.power_levels` event.
431
490
  *
491
+ * Note that we return the @see UserPowerLevelType type instead of a number as Room Version 12
492
+ * gives a Room creator (and additionalCreators) always the highest power level regardless
493
+ * of the highest next Powerlevel number.
494
+ *
432
495
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event.
496
+ * @param createRoomStateEvent - the `m.room.create` event for the room.
433
497
  * @param userId - the ID of the user.
434
498
  * @returns the power level of the user.
435
499
  */
436
- function calculateUserPowerLevel(powerLevelStateEvent, userId) {
437
- var _a, _b, _c;
438
- // See https://github.com/matrix-org/matrix-spec/blob/203b9756f52adfc2a3b63d664f18cdbf9f8bf126/data/event-schemas/schema/m.room.power_levels.yaml#L8-L12
439
- return ((_c = (_b = (userId ? (_a = powerLevelStateEvent.users) === null || _a === void 0 ? void 0 : _a[userId] : undefined)) !== null && _b !== void 0 ? _b : powerLevelStateEvent.users_default) !== null && _c !== void 0 ? _c : 0);
500
+ function calculateUserPowerLevel(powerLevelStateEvent, createRoomStateEvent, userId) {
501
+ var _a, _b, _c, _d, _e, _f;
502
+ // This is practically not allowed and therefor not covered by the spec. However a js consumer could still pass an undefined userId so we handle it gracefully.
503
+ if (!userId) {
504
+ // If no user ID is provided, we return the default user power level or 0 if not set.
505
+ return 0;
506
+ }
507
+ // If we have room version 12 we must check if the user is the creator of the room and needs to have the highest power level.
508
+ if (((_a = createRoomStateEvent === null || createRoomStateEvent === void 0 ? void 0 : createRoomStateEvent.content) === null || _a === void 0 ? void 0 : _a.room_version) === '12' ||
509
+ ((_b = createRoomStateEvent === null || createRoomStateEvent === void 0 ? void 0 : createRoomStateEvent.content) === null || _b === void 0 ? void 0 : _b.room_version) === 'org.matrix.hydra.11') {
510
+ // If the user is the creator of the room, we return the special ROOM_VERSION_12_CREATOR value.
511
+ if (createRoomStateEvent.sender === userId) {
512
+ return ROOM_VERSION_12_CREATOR;
513
+ }
514
+ if ((_c = createRoomStateEvent.content.additional_creators) === null || _c === void 0 ? void 0 : _c.includes(userId)) {
515
+ // If the user is an additional creator of the room, we return the special ROOM_VERSION_12_CREATOR value.
516
+ return ROOM_VERSION_12_CREATOR;
517
+ }
518
+ }
519
+ // If there is no power level state event, we assume the user has no power unless they are the room creator in which case they get PL 100.
520
+ if (!powerLevelStateEvent) {
521
+ if (['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'].includes((_e = (_d = createRoomStateEvent === null || createRoomStateEvent === void 0 ? void 0 : createRoomStateEvent.content) === null || _d === void 0 ? void 0 : _d.room_version) !== null && _e !== void 0 ? _e : '1')) {
522
+ // Room version 1-10 does not have a room version, so we assume the creator has power level 100.
523
+ return ((_f = createRoomStateEvent === null || createRoomStateEvent === void 0 ? void 0 : createRoomStateEvent.content) === null || _f === void 0 ? void 0 : _f.creator) === userId ? 100 : 0;
524
+ }
525
+ else {
526
+ // For room versions 11 and above, we assume the sender has power level 100.
527
+ return (createRoomStateEvent === null || createRoomStateEvent === void 0 ? void 0 : createRoomStateEvent.sender) === userId ? 100 : 0;
528
+ }
529
+ }
530
+ if (powerLevelStateEvent.users && userId in powerLevelStateEvent.users) {
531
+ // If the user is explicitly listed in the users map, return their power level.
532
+ return powerLevelStateEvent.users[userId];
533
+ }
534
+ else if (powerLevelStateEvent.users_default !== undefined) {
535
+ // If the user is not explicitly listed, return the default user power level.
536
+ return powerLevelStateEvent.users_default;
537
+ }
538
+ else {
539
+ // If no users or default is set, return 0.
540
+ return 0;
541
+ }
440
542
  }
441
543
  /**
442
544
  * Calculate the power level that a user needs send a specific room event.
@@ -448,19 +550,26 @@ function calculateUserPowerLevel(powerLevelStateEvent, userId) {
448
550
  function calculateRoomEventPowerLevel(powerLevelStateEvent, eventType) {
449
551
  var _a, _b, _c;
450
552
  // See https://github.com/matrix-org/matrix-spec/blob/203b9756f52adfc2a3b63d664f18cdbf9f8bf126/data/event-schemas/schema/m.room.power_levels.yaml#L14-L19
451
- return ((_c = (_b = (_a = powerLevelStateEvent.events) === null || _a === void 0 ? void 0 : _a[eventType]) !== null && _b !== void 0 ? _b : powerLevelStateEvent.events_default) !== null && _c !== void 0 ? _c : 0);
553
+ return ((_c = (_b = (_a = powerLevelStateEvent === null || powerLevelStateEvent === void 0 ? void 0 : powerLevelStateEvent.events) === null || _a === void 0 ? void 0 : _a[eventType]) !== null && _b !== void 0 ? _b : powerLevelStateEvent === null || powerLevelStateEvent === void 0 ? void 0 : powerLevelStateEvent.events_default) !== null && _c !== void 0 ? _c : 0);
452
554
  }
453
555
  /**
454
556
  * Calculate the power level that a user needs send a specific state event.
455
557
  *
456
558
  * @param powerLevelStateEvent - the content of the `m.room.power_levels` event
559
+ * @param createRoomStateEvent - the `m.room.create` event
457
560
  * @param eventType - the type of state event
458
561
  * @returns the power level that is needed
459
562
  */
460
- function calculateStateEventPowerLevel(powerLevelStateEvent, eventType) {
461
- var _a, _b, _c;
563
+ function calculateStateEventPowerLevel(powerLevelStateEvent, createRoomStateEvent, eventType) {
564
+ var _a, _b, _c, _d, _e;
565
+ // In room version 12 (and the beta org.matrix.hydra.11 version) we need 150 for m.room.tombstone events and it cant be changed by the user.
566
+ if ((((_a = createRoomStateEvent === null || createRoomStateEvent === void 0 ? void 0 : createRoomStateEvent.content) === null || _a === void 0 ? void 0 : _a.room_version) === '12' ||
567
+ ((_b = createRoomStateEvent === null || createRoomStateEvent === void 0 ? void 0 : createRoomStateEvent.content) === null || _b === void 0 ? void 0 : _b.room_version) === 'org.matrix.hydra.11') &&
568
+ eventType === 'm.room.tombstone') {
569
+ return 150;
570
+ }
462
571
  // See https://github.com/matrix-org/matrix-spec/blob/203b9756f52adfc2a3b63d664f18cdbf9f8bf126/data/event-schemas/schema/m.room.power_levels.yaml#L14-L19
463
- return ((_c = (_b = (_a = powerLevelStateEvent.events) === null || _a === void 0 ? void 0 : _a[eventType]) !== null && _b !== void 0 ? _b : powerLevelStateEvent.state_default) !== null && _c !== void 0 ? _c : 50);
572
+ return ((_e = (_d = (_c = powerLevelStateEvent === null || powerLevelStateEvent === void 0 ? void 0 : powerLevelStateEvent.events) === null || _c === void 0 ? void 0 : _c[eventType]) !== null && _d !== void 0 ? _d : powerLevelStateEvent === null || powerLevelStateEvent === void 0 ? void 0 : powerLevelStateEvent.state_default) !== null && _e !== void 0 ? _e : 50);
464
573
  }
465
574
  /**
466
575
  * Calculate the power level that a user needs to perform an action.
@@ -1907,4 +2016,4 @@ var WidgetApiImpl = /** @class */ (function () {
1907
2016
  return WidgetApiImpl;
1908
2017
  }());
1909
2018
 
1910
- export { ROOM_EVENT_REDACTION, STATE_EVENT_POWER_LEVELS, STATE_EVENT_ROOM_MEMBER, WIDGET_CAPABILITY_NAVIGATE, WidgetApiImpl, WidgetParameter, calculateUserPowerLevel, compareOriginServerTS, extractRawWidgetParameters, extractWidgetApiParameters, extractWidgetParameters, generateRoomTimelineCapabilities, generateWidgetRegistrationUrl, getContent, getOriginalEventId, getRoomMemberDisplayName, hasActionPower, hasRoomEventPower, hasStateEventPower, hasWidgetParameters, isRoomEvent, isStateEvent, isValidEventWithRelatesTo, isValidPowerLevelStateEvent, isValidRedactionEvent, isValidRoomEvent, isValidRoomMemberStateEvent, isValidStateEvent as isValidStateEVent, isValidToDeviceMessageEvent, makeEventFromSendStateEventResult, navigateToRoom, observeRedactionEvents, parseWidgetId, redactEvent, repairWidgetRegistration, sendStateEventWithEventResult };
2019
+ export { ROOM_EVENT_REDACTION, ROOM_VERSION_12_CREATOR, STATE_EVENT_CREATE, STATE_EVENT_POWER_LEVELS, STATE_EVENT_ROOM_MEMBER, WIDGET_CAPABILITY_NAVIGATE, WidgetApiImpl, WidgetParameter, calculateUserPowerLevel, compareOriginServerTS, compareUserPowerLevelToNormalPowerLevel, extractRawWidgetParameters, extractWidgetApiParameters, extractWidgetParameters, generateRoomTimelineCapabilities, generateWidgetRegistrationUrl, getContent, getOriginalEventId, getRoomMemberDisplayName, hasActionPower, hasRoomEventPower, hasStateEventPower, hasWidgetParameters, isRoomEvent, isStateEvent, isValidCreateEventSchema, isValidEventWithRelatesTo, isValidPowerLevelStateEvent, isValidRedactionEvent, isValidRoomEvent, isValidRoomMemberStateEvent, isValidStateEvent as isValidStateEVent, isValidToDeviceMessageEvent, makeEventFromSendStateEventResult, navigateToRoom, observeRedactionEvents, parseWidgetId, redactEvent, repairWidgetRegistration, sendStateEventWithEventResult };