Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/federation-sdk/src/services/invite.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
RoomVersion,
UserID,
extractDomainFromId,
stateIdSchema,
} from '@rocket.chat/federation-room';
import { singleton } from 'tsyringe';
import { ConfigService } from './config.service';
Expand Down Expand Up @@ -82,7 +83,7 @@ export class InviteService {
}),
},
room_id: roomId,
state_key: userId,
state_key: stateIdSchema.parse(userId),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down
3 changes: 2 additions & 1 deletion packages/federation-sdk/src/services/profiles.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
RoomID,
RoomVersion,
UserID,
stateIdSchema,
} from '@rocket.chat/federation-room';
import { singleton } from 'tsyringe';
import { StateService } from './state.service';
Expand Down Expand Up @@ -90,7 +91,7 @@ export class ProfilesService {
type: 'm.room.member',
content: { membership: 'join' },
room_id: roomId,
state_key: userId,
state_key: stateIdSchema.parse(userId),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down
23 changes: 12 additions & 11 deletions packages/federation-sdk/src/services/room.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
RoomVersion,
UserID,
extractDomainFromId,
stateIdSchema,
} from '@rocket.chat/federation-room';
import { EventStagingRepository } from '../repositories/event-staging.repository';
import { EventRepository } from '../repositories/event.repository';
Expand Down Expand Up @@ -261,7 +262,7 @@ export class RoomService {
type: 'm.room.member',
content: { membership: 'join' },
room_id: roomCreateEvent.roomId,
state_key: username,
state_key: stateIdSchema.parse(username),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down Expand Up @@ -486,7 +487,7 @@ export class RoomService {
const memberAuthResult = this.getEventByType(
authEventIds,
'm.room.member',
(e) => e.event.state_key === senderId,
(e) => e.event.state_key === stateIdSchema.parse(senderId),
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling stateIdSchema.parse(senderId) inside the filter callback causes the parsing to be executed for each event during the search, which is inefficient. Consider parsing once before the callback:

const senderStateId = stateIdSchema.parse(senderId);
const memberAuthResult = this.getEventByType(
  authEventIds,
  'm.room.member',
  (e) => e.event.state_key === senderStateId,
);

Copilot uses AI. Check for mistakes.
);

// Ensure critical auth events were found
Expand Down Expand Up @@ -616,7 +617,7 @@ export class RoomService {
type: 'm.room.member',
content: { membership: 'leave' },
room_id: roomId,
state_key: senderId,
state_key: stateIdSchema.parse(senderId),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down Expand Up @@ -697,7 +698,7 @@ export class RoomService {
reason: reason,
},
room_id: roomId,
state_key: kickedUserId,
state_key: stateIdSchema.parse(kickedUserId),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down Expand Up @@ -740,7 +741,7 @@ export class RoomService {
},
room_id: roomId,
sender: userId,
state_key: userId,
state_key: stateIdSchema.parse(userId),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down Expand Up @@ -823,7 +824,7 @@ export class RoomService {
reason: reason,
},
room_id: roomId,
state_key: bannedUserId,
state_key: stateIdSchema.parse(bannedUserId),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down Expand Up @@ -873,7 +874,7 @@ export class RoomService {
type: 'm.room.member',
content: { membership: 'join' },
room_id: roomId,
state_key: userId,
state_key: stateIdSchema.parse(userId),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down Expand Up @@ -1423,7 +1424,7 @@ export class RoomService {
displayname: creatorDisplayname,
},
room_id: roomCreateEvent.roomId,
state_key: creatorUserId,
state_key: stateIdSchema.parse(creatorUserId),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down Expand Up @@ -1540,7 +1541,7 @@ export class RoomService {
displayname: displayname,
},
room_id: roomCreateEvent.roomId,
state_key: targetUserId,
state_key: stateIdSchema.parse(targetUserId),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down Expand Up @@ -1598,8 +1599,8 @@ export class RoomService {

if (
currentUserIds.length === 2 &&
currentUserIds.includes(userId1) &&
currentUserIds.includes(userId2)
currentUserIds.includes(stateIdSchema.parse(userId1)) &&
currentUserIds.includes(stateIdSchema.parse(userId2))
Comment on lines +1602 to +1603
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling stateIdSchema.parse() inside the includes() check adds unnecessary parsing overhead for each comparison. Consider parsing userId1 and userId2 to StateID once before the comparison:

const stateId1 = stateIdSchema.parse(userId1);
const stateId2 = stateIdSchema.parse(userId2);
if (
  currentUserIds.length === 2 &&
  currentUserIds.includes(stateId1) &&
  currentUserIds.includes(stateId2)
) {
  return roomId;
}

Copilot uses AI. Check for mistakes.
) {
return roomId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
PersistentEventFactory,
RoomID,
UserID,
stateIdSchema,
} from '@rocket.chat/federation-room';
import { federationSDK } from '@rocket.chat/federation-sdk';
import { Elysia } from 'elysia';
Expand Down Expand Up @@ -40,7 +41,7 @@ export const internalInvitePlugin = (app: Elysia) => {
type: 'm.room.member',
content: { membership: 'invite' },
room_id: roomId as RoomID,
state_key: username as UserID,
state_key: stateIdSchema.parse(username),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
PersistentEventFactory,
RoomID,
UserID,
stateIdSchema,
} from '@rocket.chat/federation-room';
import { federationSDK } from '@rocket.chat/federation-sdk';
import { Elysia, t } from 'elysia';
Expand Down Expand Up @@ -354,7 +355,7 @@ export const internalRoomPlugin = (app: Elysia) => {
type: 'm.room.member',
content: { membership: 'ban' },
room_id: roomId as RoomID,
state_key: userIdToBan as UserID,
state_key: stateIdSchema.parse(userIdToBan),
auth_events: [],
depth: 0,
prev_events: [],
Expand Down
8 changes: 4 additions & 4 deletions packages/room/src/types/_common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ export const eventIdSchema = z.string().brand('EventID');

export type EventID = z.infer<typeof eventIdSchema>;

const stateIdSchema = z.string().brand('StateID');

export type StateID = z.infer<typeof stateIdSchema>;

export const roomIdSchema = z.string().brand('RoomID');

export type RoomID = z.infer<typeof roomIdSchema>;
Expand All @@ -19,6 +15,10 @@ export const userIdSchema = z.string().brand('UserID');

export type UserID = z.infer<typeof userIdSchema>;

export const stateIdSchema = z.string().brand('StateID');

export type StateID = z.infer<typeof stateIdSchema>;

export type StateMapKey = `${PduType}:${StateKey}`;

export type State = Map<StateMapKey, EventID>;
Expand Down
3 changes: 2 additions & 1 deletion packages/room/src/types/v3-11.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
PduForType,
eventIdSchema,
roomIdSchema,
stateIdSchema,
userIdSchema,
} from './_common';

Expand Down Expand Up @@ -640,7 +641,7 @@ export const PduNoContentTimelineEventSchema = {

export const PduNoContentStateEventSchema = {
...PduNoContentTimelineEventSchema,
state_key: userIdSchema.describe(
state_key: stateIdSchema.describe(
'The state key of the event. This is an optional field.',
),
};
Expand Down