-
Notifications
You must be signed in to change notification settings - Fork 19
fix: add workaround for missing first message #208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -17,6 +17,7 @@ export class EventStagingRepository { | |||||||||||||||||||||||||||||||||||||||||||||
| eventId: EventID, | ||||||||||||||||||||||||||||||||||||||||||||||
| origin: string, | ||||||||||||||||||||||||||||||||||||||||||||||
| event: Pdu, | ||||||||||||||||||||||||||||||||||||||||||||||
| pendingInvite = false, | ||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<UpdateResult> { | ||||||||||||||||||||||||||||||||||||||||||||||
| // We use an upsert here to handle the case where we see the same event | ||||||||||||||||||||||||||||||||||||||||||||||
| // from the same server multiple times. | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -32,6 +33,7 @@ export class EventStagingRepository { | |||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| $set: { | ||||||||||||||||||||||||||||||||||||||||||||||
| event, | ||||||||||||||||||||||||||||||||||||||||||||||
| pendingInvite, | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -48,6 +50,7 @@ export class EventStagingRepository { | |||||||||||||||||||||||||||||||||||||||||||||
| return this.collection.findOne( | ||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||
| roomId, | ||||||||||||||||||||||||||||||||||||||||||||||
| pendingInvite: false, | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||
| sort: { createdAt: 1 }, | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -58,4 +61,11 @@ export class EventStagingRepository { | |||||||||||||||||||||||||||||||||||||||||||||
| async getDistinctStagedRooms(): Promise<string[]> { | ||||||||||||||||||||||||||||||||||||||||||||||
| return this.collection.distinct('roomId'); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| async unmarkInvitePending(eventId: EventID): Promise<UpdateResult> { | ||||||||||||||||||||||||||||||||||||||||||||||
| return this.collection.updateOne( | ||||||||||||||||||||||||||||||||||||||||||||||
| { _id: eventId }, | ||||||||||||||||||||||||||||||||||||||||||||||
| { $set: { pendingInvite: false } }, | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+70
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unmarking by eventId is insufficient; add a bulk clear by room+sender. Multiple PDUs may be flagged. Provide an updateMany helper. async unmarkInvitePending(eventId: EventID): Promise<UpdateResult> {
return this.collection.updateOne(
{ _id: eventId },
{ $set: { pendingInvite: false } },
);
}
+
+ async unmarkInvitePendingForRoomAndSender(
+ roomId: string,
+ sender: string,
+ ): Promise<UpdateResult> {
+ return this.collection.updateMany(
+ { roomId, 'event.sender': sender, pendingInvite: true },
+ { $set: { pendingInvite: false } },
+ );
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,40 @@ | ||||||||||||||||||||||||||||||
| import { EventID, Pdu } from '@hs/room'; | ||||||||||||||||||||||||||||||
| import { Collection } from 'mongodb'; | ||||||||||||||||||||||||||||||
| import { inject, singleton } from 'tsyringe'; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export type PendingInvite = { | ||||||||||||||||||||||||||||||
| event: Pdu; | ||||||||||||||||||||||||||||||
| _id: EventID; | ||||||||||||||||||||||||||||||
| createdAt: Date; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @singleton() | ||||||||||||||||||||||||||||||
| export class PendingInviteRepository { | ||||||||||||||||||||||||||||||
| constructor( | ||||||||||||||||||||||||||||||
| @inject('PendingInviteCollection') | ||||||||||||||||||||||||||||||
| private readonly collection: Collection<PendingInvite>, | ||||||||||||||||||||||||||||||
| ) {} | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| async add(eventId: EventID, event: Pdu): Promise<void> { | ||||||||||||||||||||||||||||||
| await this.collection.insertOne({ | ||||||||||||||||||||||||||||||
| _id: eventId, | ||||||||||||||||||||||||||||||
| event, | ||||||||||||||||||||||||||||||
| createdAt: new Date(), | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+18
to
+24
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make add idempotent. Use upsert to tolerate retries. - async add(eventId: EventID, event: Pdu): Promise<void> {
- await this.collection.insertOne({
- _id: eventId,
- event,
- createdAt: new Date(),
- });
- }
+ async add(eventId: EventID, event: Pdu): Promise<void> {
+ await this.collection.updateOne(
+ { _id: eventId },
+ { $setOnInsert: { _id: eventId, event, createdAt: new Date() } },
+ { upsert: true },
+ );
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| async findByUserIdAndRoomId( | ||||||||||||||||||||||||||||||
| userId: string, | ||||||||||||||||||||||||||||||
| roomId: string, | ||||||||||||||||||||||||||||||
| ): Promise<PendingInvite | null> { | ||||||||||||||||||||||||||||||
| return this.collection.findOne({ | ||||||||||||||||||||||||||||||
| 'event.type': 'm.room.member', | ||||||||||||||||||||||||||||||
| 'event.state_key': userId, | ||||||||||||||||||||||||||||||
| 'event.room_id': roomId, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| async remove(eventId: EventID): Promise<void> { | ||||||||||||||||||||||||||||||
| await this.collection.deleteOne({ _id: eventId }); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -22,6 +22,7 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type Pdu, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type PduForType, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type PduType, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PersistentEventBase, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PersistentEventFactory, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getAuthChain, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '@hs/room'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -32,6 +33,7 @@ import { EventStagingRepository } from '../repositories/event-staging.repository | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { EventRepository } from '../repositories/event.repository'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { KeyRepository } from '../repositories/key.repository'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { LockRepository } from '../repositories/lock.repository'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { PendingInviteRepository } from '../repositories/pending-invite.repository'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { eventSchemas } from '../utils/event-schemas'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ConfigService } from './config.service'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { EventEmitterService } from './event-emitter.service'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -59,6 +61,8 @@ export class EventService { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly stateService: StateService, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly eventEmitterService: EventEmitterService, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly pendingInviteRepository: PendingInviteRepository, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // on startup we look for old staged events and try to process them | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -196,8 +200,22 @@ export class EventService { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const pendingInvite = await this.isSenderInvitePending( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| event.sender, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| event.room_id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // save the event as staged to be processed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.eventStagingRepository.create(eventId, origin, event); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.eventStagingRepository.create( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eventId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| origin, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| event, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pendingInvite, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pendingInvite) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+203
to
219
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainPending-invite short-circuit: confirm join events aren’t blocked. This will stage and skip any PDU from a sender with a pending invite. Ensure membership “join” events aren’t accidentally deferred, or they may never clear the block. Run a quick scan to see if join PDUs enter this path: 🏁 Script executed: #!/bin/bash
rg -nP --type=ts -C3 "processIncomingPDUs|persistStateEvent\(.+m\.room\.member.+join" packagesLength of output: 1134 🏁 Script executed: #!/bin/bash
rg -n -C30 "isSenderInvitePending" packages/federation-sdk/src/services/event.service.tsLength of output: 2991 Add join-event exemption to pending-invite short-circuit const isJoin = event.type === 'm.room.member'
&& (event.content as any).membership === 'join';
if (pendingInvite && !isJoin) {
continue;
}This ensures join events are processed immediately. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // acquire a lock for processing the event | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const lock = await this.lockRepository.getLock( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -806,4 +824,37 @@ export class EventService { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw error; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async addPendingInvite(event: PersistentEventBase): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.pendingInviteRepository.add(event.eventId, event.event as Pdu); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async removePendingInvite(eventId: EventID, roomId: string): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await Promise.all([ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.pendingInviteRepository.remove(eventId), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.eventStagingRepository.unmarkInvitePending(eventId), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // acquire a lock for processing the event | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const lock = await this.lockRepository.getLock( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| roomId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.configService.instanceId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!lock) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.debug(`Couldn't acquire a lock for room ${roomId}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO change this to call stagingAreaService directly | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.stagingAreaQueue.enqueue(roomId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+832
to
+850
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix: remove by user+room and unmark all staged events. Current implementation removes by eventId and unmarks a single staged doc, which doesn’t map to how invites and staged PDUs are keyed. - async removePendingInvite(eventId: EventID, roomId: string): Promise<void> {
- await Promise.all([
- this.pendingInviteRepository.remove(eventId),
- this.eventStagingRepository.unmarkInvitePending(eventId),
- ]);
-
- // acquire a lock for processing the event
- const lock = await this.lockRepository.getLock(
- roomId,
- this.configService.instanceId,
- );
- if (!lock) {
- this.logger.debug(`Couldn't acquire a lock for room ${roomId}`);
- return;
- }
-
- // TODO change this to call stagingAreaService directly
- this.stagingAreaQueue.enqueue(roomId);
- }
+ async resolvePendingInvitesForUser(roomId: string, userId: string): Promise<void> {
+ // Remove the invite entry (by user+room) if present
+ const invite = await this.pendingInviteRepository.findByUserIdAndRoomId(userId, roomId);
+ if (invite?._id) {
+ await this.pendingInviteRepository.remove(invite._id);
+ }
+ // Unblock all staged PDUs from this user in this room
+ await this.eventStagingRepository.unmarkInvitePendingForRoomAndSender(roomId, userId);
+
+ const lock = await this.lockRepository.getLock(roomId, this.configService.instanceId);
+ if (!lock) {
+ this.logger.debug(`Couldn't acquire a lock for room ${roomId}`);
+ return;
+ }
+ this.stagingAreaQueue.enqueue(roomId);
+ }📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async isSenderInvitePending(sender: string, roomId: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const invite = await this.pendingInviteRepository.findByUserIdAndRoomId( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sender, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| roomId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return !!invite; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,10 +1,5 @@ | ||||||||||||||||||||||
| import { EventBase, HttpException, HttpStatus } from '@hs/core'; | ||||||||||||||||||||||
| import { | ||||||||||||||||||||||
| PduForType, | ||||||||||||||||||||||
| PersistentEventBase, | ||||||||||||||||||||||
| PersistentEventFactory, | ||||||||||||||||||||||
| RoomVersion, | ||||||||||||||||||||||
| } from '@hs/room'; | ||||||||||||||||||||||
| import { PduForType, PersistentEventFactory, RoomVersion } from '@hs/room'; | ||||||||||||||||||||||
| import { singleton } from 'tsyringe'; | ||||||||||||||||||||||
| import { createLogger } from '../utils/logger'; | ||||||||||||||||||||||
| import { ConfigService } from './config.service'; | ||||||||||||||||||||||
|
|
@@ -70,7 +65,7 @@ export class InviteService { | |||||||||||||||||||||
| sender: sender, | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| roomInformation.room_version, | ||||||||||||||||||||||
| roomInformation.room_version as RoomVersion, | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // SPEC: Invites a remote user to a room. Once the event has been signed by both the inviting homeserver and the invited homeserver, it can be sent to all of the servers in the room by the inviting homeserver. | ||||||||||||||||||||||
|
|
@@ -113,7 +108,7 @@ export class InviteService { | |||||||||||||||||||||
| await stateService.persistStateEvent( | ||||||||||||||||||||||
| PersistentEventFactory.createFromRawEvent( | ||||||||||||||||||||||
| inviteResponse.event, | ||||||||||||||||||||||
| roomInformation.room_version, | ||||||||||||||||||||||
| roomInformation.room_version as RoomVersion, | ||||||||||||||||||||||
| ), | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
@@ -185,7 +180,11 @@ export class InviteService { | |||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // we are not the host of the server | ||||||||||||||||||||||
| // so being the origin of the user, we sign the event and send it to the asking server, let them handle the transactions | ||||||||||||||||||||||
| // nor are we part of the room now. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| await this.eventService.addPendingInvite(inviteEvent); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
Comment on lines
+183
to
+186
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Idempotency: guard against duplicate inserts.
Apply in repository (see pending-invite.repository.ts comment) or wrap call: - await this.eventService.addPendingInvite(inviteEvent);
+ try {
+ await this.eventService.addPendingInvite(inviteEvent);
+ } catch (e: any) {
+ if (!/E11000/.test(String(e?.code) + String(e?.message))) throw e;
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| // being the origin of the user, we sign the event and send it to the asking server, let them handle the transactions | ||||||||||||||||||||||
| return inviteEvent; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -989,6 +989,11 @@ export class RoomService { | |||||||||||||||||
| throw new Error(joinEventFinal.rejectedReason); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| await this.eventService.removePendingInvite( | ||||||||||||||||||
| joinEventFinal.eventId, | ||||||||||||||||||
| joinEventFinal.roomId, | ||||||||||||||||||
| ); | ||||||||||||||||||
|
Comment on lines
+992
to
+995
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: wrong identifier used to clear pending invite and unblock staged events.
Apply: - await this.eventService.removePendingInvite(
- joinEventFinal.eventId,
- joinEventFinal.roomId,
- );
+ await this.eventService.resolvePendingInvitesForUser(
+ joinEventFinal.roomId,
+ userId,
+ );Supporting changes are proposed in event.service.ts and event-staging.repository.ts comments below. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| return joinEventFinal.eventId; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Backfill or tolerant query needed for new required field.
Adding
pendingInvite: booleanmakes legacy staged docs (without this field) invisible to queries that matchpendingInvite: false. Ensure downstream queries treat missing as false or run a one-off backfill/migration.I’ve proposed tolerant query changes under event-staging.repository.ts.
🤖 Prompt for AI Agents