Skip to content

Conversation

@ggazzo
Copy link
Member

@ggazzo ggazzo commented Sep 14, 2025

…ntFactory

Updated the RoomService and PersistentEventFactory to use a new unified method for creating events, enhancing code consistency and readability. This change replaces multiple event creation methods with a single newEvent method, streamlining the process of generating various room-related events.

Summary by CodeRabbit

  • New Features

    • Expanded message content schema to support more types (text, images, files, audio, video, emote, notice, location) and cleaner message edits.
    • Direct message invites now include display names for clearer context.
  • Refactor

    • Unified event creation across messaging, room management, invites, joins, bans, and redactions for more consistent behavior and timestamps.
    • Streamlined persistence and federation flows to reduce duplication and improve reliability.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 14, 2025

Walkthrough

Refactors event construction across services to use a unified builder (StateService.buildEvent / PersistentEventFactory.newEvent), replacing numerous specialized factory methods. Updates schemas and types (message content unions, empty state_key constraint; tombstone auth fields required). Adjusts controllers and services to the new build-and-persist flow, removing manual auth/prev wiring and signing calls.

Changes

Cohort / File(s) Summary
Schema and type updates
packages/room/src/types/v3-11.ts, packages/core/src/events/m.room.tombstone.ts
Message content reworked into union schemas; introduced File/Location schemas and NewContent schema; added EmptyStateKey state schema and applied to create/join_rules/power_levels. TombstoneAuthEvents fields made required strings.
StateService orchestration
packages/federation-sdk/src/services/state.service.ts
Added buildEvent() that creates, augments (auth/prev), and signs events; made addAuthEvents/addPrevEvents private; minor visibility tweak for signEvent; updated imports.
Factory consolidation
packages/room/src/manager/factory.ts
Removed many specialized event builders; added generic newEvent() delegating to createFromRawEvent; retained createFromRawEvent; eliminated DM-specific and message helper constructors.
Federation SDK services migration
packages/federation-sdk/src/services/invite.service.ts, .../message.service.ts, .../profiles.service.ts, .../room.service.ts, .../send-join.service.ts
Replaced factory-based constructions with stateService.buildEvent for member/message/redaction/reaction/room-state/tombstone events; removed explicit addAuthEvents/addPrevEvents/signing; standardized timestamps and roomVersion usage; added relations handling and file content typing; preserved persistence/broadcast flows.
Homeserver controllers alignment
packages/homeserver/src/controllers/internal/invite.controller.ts, .../room.controller.ts
Switched to PersistentEventFactory.newEvent for m.room.member invite/ban; explicit payloads with origin_server_ts and room_version; rest of auth/persist logic unchanged.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Caller as Service/Controller
  participant State as StateService
  participant Factory as PersistentEventFactory
  participant Store as Persistence

  Caller->>State: buildEvent(rawEvent, roomVersion)
  State->>Factory: createFromRawEvent(rawEvent, roomVersion)
  Factory-->>State: PersistentEventBase
  State->>State: addAuthEvents(event)
  State->>State: addPrevEvents(event)
  State->>State: signEvent(event)
  State-->>Caller: event
  Caller->>Store: persistStateEvent/persistTimelineEvent(event)
  Store-->>Caller: event_id
Loading
sequenceDiagram
  autonumber
  participant Client as MessageService
  participant State as StateService
  participant Store as EventStore
  participant Fed as Federation

  Client->>State: buildEvent<'m.room.message'>(content+relations)
  State-->>Client: event
  Client->>Store: persistTimelineEvent(event)
  Store-->>Client: event_id
  Client->>Fed: notify/broadcast(event)
  Fed-->>Client: ack
Loading
sequenceDiagram
  autonumber
  participant InvSvc as InviteService
  participant State as StateService
  participant Fed as FederationService
  participant Store as EventStore

  alt Local invite
    InvSvc->>State: buildEvent<'m.room.member'>(membership: invite)
    State-->>InvSvc: event
    InvSvc->>Store: persistStateEvent(event)
    InvSvc->>Fed: notifyAllServers(event)
  else Remote invite
    InvSvc->>Fed: inviteUser(rawInvite)
    Fed-->>InvSvc: signedInviteEvent
    InvSvc->>Store: persistStateEvent(signedInviteEvent)
    InvSvc->>Fed: notifyAllServers(signedInviteEvent)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • feat: state endpoints #164 — Also modifies StateService, focusing on state reconstruction methods; related at the class level and may interact with the new buildEvent flow.

Poem

A rabbit taps keys with delighted paws,
One builder to rule the eventful laws.
Threads and invites hop in line,
Schemas trimmed, their fields align.
With timestamps fresh and signatures neat,
The warren hums—refactors complete. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title accurately summarizes the primary change: a refactor to standardize event creation in RoomService and PersistentEventFactory by consolidating many per-event constructors into a unified builder. It is concise, focused on the main intent, and free of irrelevant details. The visible ellipsis appears to be a UI truncation and does not obscure the intent of the change.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/simplfy-factory

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7848ef and ef3796d.

📒 Files selected for processing (1)
  • packages/federation-sdk/src/services/state.service.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/federation-sdk/src/services/state.service.ts

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link

codecov-commenter commented Sep 14, 2025

Codecov Report

❌ Patch coverage is 72.72727% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.41%. Comparing base (0dedc4c) to head (ef3796d).

Files with missing lines Patch % Lines
packages/room/src/manager/factory.ts 25.00% 3 Missing ⚠️
Additional details and impacted files
@@                   Coverage Diff                   @@
##           chore/message-type     #188       +/-   ##
=======================================================
+ Coverage               68.94%   80.41%   +11.46%     
=======================================================
  Files                      58       58               
  Lines                    5288     4514      -774     
=======================================================
- Hits                     3646     3630       -16     
+ Misses                   1642      884      -758     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/room/src/types/v3-11.ts (1)

553-557: Bug: m.room.tombstone must be an empty-state-key state event

Modeled as a timeline event here; switch to the empty-state-key state schema to match core and avoid validation/build-id mismatches.

File: packages/room/src/types/v3-11.ts:553-557

Apply:

-const EventPduTypeRoomTombstone = z.object({
-	...PduNoContentTimelineEventSchema,
+const EventPduTypeRoomTombstone = z.object({
+	...PduNoContentEmptyStateKeyStateEventSchema,
 	type: z.literal('m.room.tombstone'),
 	content: PduRoomTombstoneEventContentSchema,
});
🧹 Nitpick comments (6)
packages/federation-sdk/src/services/send-join.service.ts (1)

35-38: Unified builder: OK — stateService signs events before persisting; remove redundant explicit sign

buildEvent calls this.signEvent (state.service.ts:353) and persistStateEvent also signs before storing (state.service.ts:453), so persisting joinEvent at send-join.service.ts:49 is safe; remove the redundant stateService.signEvent(joinEvent) at send-join.service.ts:71.

packages/federation-sdk/src/services/invite.service.ts (1)

44-69: Robust localpart extraction for DM invites

Use a safe regex to extract the localpart and only include displayname when present.

-const displayname = isDirectMessage
-  ? userId.split(':').shift()?.slice(1)
-  : undefined;
+const displayname = isDirectMessage
+  ? (() => {
+      const m = userId.match(/^@([^:]+):/);
+      return m ? m[1] : undefined;
+    })()
+  : undefined;

buildEvent (StateService.buildEvent) populates auth_events and prev_events via addAuthEvents/addPrevEvents, but it does NOT compute/set depth — callers must provide the correct depth when constructing the raw event.

packages/federation-sdk/src/services/state.service.ts (2)

371-384: Cap prev_events and avoid overriding provided prev_events.
Spec and interop benefit from a small prev set. Also, if caller set prev_events, skip recomputing.

Apply:

-	private async addPrevEvents(event: PersistentEventBase) {
+	private async addPrevEvents(event: PersistentEventBase) {
+		// If caller supplied prev_events, don't override.
+		if ((event.event.prev_events?.length ?? 0) > 0) {
+			return;
+		}
 		const roomVersion = await this.getRoomVersion(event.roomId);
 		if (!roomVersion) {
 			throw new Error('Room version not found while filling prev events');
 		}
 
 		const prevEvents = await this.eventRepository.findPrevEvents(event.roomId);
 
-		event.addPrevEvents(
-			prevEvents.map((e) =>
-				PersistentEventFactory.createFromRawEvent(e.event, roomVersion),
-			),
-		);
+		const MAX_PREV = 10;
+		event.addPrevEvents(
+			prevEvents.slice(0, MAX_PREV).map((e) =>
+				PersistentEventFactory.createFromRawEvent(e.event, roomVersion),
+			),
+		);
 	}

386-406: Harden signing: validate serverName and key; check returned signature.
Prevents silent failures on misconfig.

Apply:

-	async signEvent(event: PersistentEventBase) {
-		const signingKey = await this.configService.getSigningKey();
-
-		const origin = this.configService.serverName;
+	async signEvent(event: PersistentEventBase) {
+		const signingKey = await this.configService.getSigningKey();
+		const origin = this.configService.serverName;
+		if (!origin) {
+			throw new Error('Server name is not configured; cannot sign event');
+		}
+		if (!Array.isArray(signingKey) || !signingKey[0]) {
+			throw new Error('Signing key not available; cannot sign event');
+		}
@@
-		const keyId = `${signingKey[0].algorithm}:${signingKey[0].version}`;
-
-		event.addSignature(origin, keyId, result.signatures[origin][keyId]);
+		const keyId = `${signingKey[0].algorithm}:${signingKey[0].version}`;
+		const sig = result.signatures?.[origin]?.[keyId];
+		if (!sig) {
+			throw new Error('Signing failed: missing signature in result');
+		}
+		event.addSignature(origin, keyId, sig);
 
 		return event;
 	}
packages/federation-sdk/src/services/message.service.ts (1)

376-403: Rename variable: redactionEvent → messageUpdateEvent.
This block creates a message replacement, not a redaction.

Apply:

-		const redactionEvent = await this.stateService.buildEvent<'m.room.message'>(
+		const messageUpdateEvent = await this.stateService.buildEvent<'m.room.message'>(
@@
-		await this.stateService.persistTimelineEvent(redactionEvent);
+		await this.stateService.persistTimelineEvent(messageUpdateEvent);
@@
-		void this.federationService.sendEventToAllServersInRoom(redactionEvent);
+		void this.federationService.sendEventToAllServersInRoom(messageUpdateEvent);
@@
-		return redactionEvent.eventId;
+		return messageUpdateEvent.eventId;
packages/federation-sdk/src/services/room.service.ts (1)

1226-1227: Displayname extraction: avoid slice(1) pitfalls.
User IDs may not start with '@' in all cases.

Apply:

-		const creatorDisplayname = creatorUserId.split(':').shift()?.slice(1);
+		const creatorDisplayname = creatorUserId.split(':',1)[0]?.replace(/^@/, '');
@@
-			const displayname = targetUserId.split(':').shift()?.slice(1);
+			const displayname = targetUserId.split(':',1)[0]?.replace(/^@/, '');

Also applies to: 1343-1344

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f43238 and a562524.

📒 Files selected for processing (11)
  • packages/core/src/events/m.room.tombstone.ts (1 hunks)
  • packages/federation-sdk/src/services/invite.service.ts (1 hunks)
  • packages/federation-sdk/src/services/message.service.ts (9 hunks)
  • packages/federation-sdk/src/services/profiles.service.ts (1 hunks)
  • packages/federation-sdk/src/services/room.service.ts (13 hunks)
  • packages/federation-sdk/src/services/send-join.service.ts (1 hunks)
  • packages/federation-sdk/src/services/state.service.ts (4 hunks)
  • packages/homeserver/src/controllers/internal/invite.controller.ts (1 hunks)
  • packages/homeserver/src/controllers/internal/room.controller.ts (1 hunks)
  • packages/room/src/manager/factory.ts (1 hunks)
  • packages/room/src/types/v3-11.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
packages/federation-sdk/src/services/profiles.service.ts (1)
packages/room/src/manager/event-wrapper.ts (1)
  • roomId (72-74)
packages/homeserver/src/controllers/internal/invite.controller.ts (2)
packages/room/src/manager/factory.ts (1)
  • PersistentEventFactory (37-144)
packages/room/src/types/v3-11.ts (1)
  • PduCreateEventContent (148-148)
packages/homeserver/src/controllers/internal/room.controller.ts (3)
packages/room/src/manager/factory.ts (1)
  • PersistentEventFactory (37-144)
packages/room/src/manager/event-wrapper.ts (1)
  • roomId (72-74)
packages/room/src/types/v3-11.ts (1)
  • PduCreateEventContent (148-148)
packages/federation-sdk/src/services/state.service.ts (5)
packages/room/src/types/v3-11.ts (1)
  • PduType (45-45)
packages/room/src/manager/event-wrapper.ts (2)
  • event (102-112)
  • PduWithHashesAndSignaturesOptional (33-35)
packages/room/src/types/_common.ts (1)
  • PduForType (11-11)
packages/room/src/manager/type.ts (1)
  • RoomVersion (14-14)
packages/room/src/manager/factory.ts (1)
  • PersistentEventFactory (37-144)
packages/federation-sdk/src/services/message.service.ts (4)
packages/room/src/manager/event-wrapper.ts (2)
  • event (102-112)
  • roomId (72-74)
packages/core/src/events/m.reaction.ts (1)
  • reactionEvent (51-94)
packages/room/src/manager/v3.ts (1)
  • eventId (21-33)
packages/core/src/events/m.room.redaction.ts (1)
  • redactionEvent (36-87)
packages/federation-sdk/src/services/room.service.ts (3)
packages/core/src/events/m.room.create.ts (1)
  • roomCreateEvent (26-43)
packages/room/src/manager/factory.ts (1)
  • PersistentEventFactory (37-144)
packages/room/src/manager/event-wrapper.ts (3)
  • roomId (72-74)
  • sender (76-78)
  • event (102-112)
packages/room/src/manager/factory.ts (4)
packages/room/src/types/v3-11.ts (1)
  • PduType (45-45)
packages/room/src/manager/event-wrapper.ts (2)
  • event (102-112)
  • PduWithHashesAndSignaturesOptional (33-35)
packages/room/src/types/_common.ts (1)
  • PduForType (11-11)
packages/room/src/manager/type.ts (1)
  • RoomVersion (14-14)
🔇 Additional comments (11)
packages/room/src/types/v3-11.ts (3)

476-480: Good addition: empty state_key state schema

Introducing PduNoContentEmptyStateKeyStateEventSchema is correct and aligns with spec for state events that must use an empty state_key.


482-485: m.room.create: enforce empty state_key

Switching to the empty-state-key schema is correct; create events must have state_key ''.


494-497: join_rules and power_levels: enforce empty state_key

Both event types must use state_key ''. This narrows types safely and prevents accidental non-empty keys.

Also applies to: 500-503

packages/core/src/events/m.room.tombstone.ts (1)

23-26: Stronger typing for auth_events

Requiring strings here is good; it ensures compile-time presence. Keeping the isTruthy filter still guards against empty strings.

packages/homeserver/src/controllers/internal/room.controller.ts (1)

372-386: Ban membership event: align with builder path

Same as invites — replace the manual PersistentEventFactory.newEvent with stateService.buildEvent so prev/auth events and canonical fields are handled consistently.

-const membershipEvent =
-  PersistentEventFactory.newEvent<'m.room.member'>(/* payload */, roomVersion);
+const membershipEvent =
+  await stateService.buildEvent<'m.room.member'>(/* payload */, roomVersion);

Verify event_id stability after the change (compare generated event_id or run unit/integration tests).

packages/homeserver/src/controllers/internal/invite.controller.ts (1)

39-52: Prefer stateService.buildEvent for consistency

Using PersistentEventFactory.newEvent bypasses StateService's auth/prev enrichment and canonicalization — switch to stateService.buildEvent (async) to match other invite paths.

File: packages/homeserver/src/controllers/internal/invite.controller.ts (lines 39-52)

-const membershipEvent = PersistentEventFactory.newEvent<'m.room.member'>(
-  { /* payload */ },
-  createEvent.getContent<PduCreateEventContent>().room_version,
-);
+const membershipEvent = await stateService.buildEvent<'m.room.member'>(
+  { /* same payload */ },
+  createEvent.getContent<PduCreateEventContent>().room_version,
+);

Verify that the resulting event_id for invites from this route matches pre-change behavior; if it differs, standardize all invite paths to use buildEvent.

packages/federation-sdk/src/services/state.service.ts (2)

8-14: Types import LGTM.
The new generics enable strongly typed build flow.


358-369: Auth wiring centralization LGTM.
This keeps timeline/state validation happy.

packages/federation-sdk/src/services/room.service.ts (1)

1064-1082: Avoid overriding provided prev/auth in buildEvent for tombstone.
This payload already supplies prev_events, depth, and auth_events. Ensure StateService.addAuthEvents/addPrevEvents are no-ops when fields are prefilled to avoid duplication/mismatch.

Would you like me to adjust buildEvent to skip add* steps when arrays are non-empty?

packages/room/src/manager/factory.ts (1)

138-143: Unified newEvent wrapper LGTM.
Thin delegate to createFromRawEvent keeps API consistent and typed.

packages/federation-sdk/src/services/message.service.ts (1)

57-74: Resolved — buildEvent already populates prev_events and updates depth before signing.
StateService.buildEvent calls addPrevEvents (which uses eventRepository.findPrevEvents) and PersistentEventBase.addPrevEvents bumps rawEvent.depth based on prev events, so the depth: 0 placeholders in message.service are overridden and no change is required.

Comment on lines +82 to 95
const membershipEvent = await stateService.buildEvent<'m.room.member'>(
{
type: 'm.room.member',
content: { membership: 'join' },
room_id: roomId,
state_key: userId,
auth_events: [],
depth: 0,
prev_events: [],
origin_server_ts: Date.now(),
sender: userId,
},
roomInformation.room_version,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Confirm make_join template vs fully-built event

Using stateService.buildEvent centralizes logic—good. For federation “make_join”, confirm we should populate origin_server_ts/depth and compute IDs/signatures here vs returning a minimal template to the joiner.


🌐 Web query:

Matrix federation make_join: What fields must the returned event include? Should auth_events, prev_events, depth, origin_server_ts be populated by the resident server, or left for the joining server?

💡 Result:

Short answer: the resident must return a proto-event that includes auth_events, prev_events, depth and the other common PDU fields (type, sender, state_key, content, room_id, origin, signatures/ hashes may be present in some room-versions). The joining server is expected to fill in (or replace) the event_id, origin and origin_server_ts on that template and then sign the resulting event before calling send_join. Room-version details can change exact format, so follow the room-version rules when building the final PDU.

Sources: Matrix Server‑Server API (make_join / send_join) and legacy make_join description. [1][2]

References
[1] Matrix Spec — Server‑Server API (make_join / send_join) — describes the template, and states the joining server should add/replace origin, origin_server_ts and event_id.
[2] Legacy make_join description — lists required proto-event fields (type, auth_events, content, depth, origin, origin_server_ts, prev_events, room_id, sender, state_key) and shows the joining server adds event_id/origin/origin_server_ts.


Do not populate origin/origin_server_ts/event_id in the make_join proto-event — return a template only.

Matrix spec: the resident should return a proto-event containing type, sender, state_key, content, room_id, auth_events, prev_events and depth; the joining server must add/replace origin, origin_server_ts and event_id and sign before send_join.
File: packages/federation-sdk/src/services/profiles.service.ts (lines 82–95) — remove origin_server_ts: Date.now() (and avoid setting event_id/origin/signatures) while keeping auth_events/prev_events/depth per room-version rules.

🤖 Prompt for AI Agents
In packages/federation-sdk/src/services/profiles.service.ts around lines 82–95,
the make_join proto-event is being populated with origin_server_ts (and must not
set event_id/origin/signatures); change the function to return only the
proto-event template containing type, sender, state_key, content, room_id,
auth_events, prev_events and depth (per room version rules) and remove
origin_server_ts: Date.now() and any assignment of event_id/origin/signatures so
the joining server can add/replace origin, origin_server_ts and event_id and
sign before send_join.

Comment on lines +1346 to 1363
await stateService.buildEvent<'m.room.member'>(
{
type: 'm.room.member',
content: {
membership: 'join',
is_direct: true,
displayname: displayname,
},
room_id: roomCreateEvent.roomId,
state_key: targetUserId,
auth_events: [],
depth: 0,
prev_events: [],
origin_server_ts: Date.now(),
sender: creatorUserId,
},
PersistentEventFactory.defaultRoomVersion,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Join event sender/state_key mismatch for local DM target.
A join should be authored by the joining user; current code sets sender to creatorUserId. Either:

  • change to sender: targetUserId for membership: 'join', or
  • switch to an invite flow (membership: 'invite', sender: creatorUserId) and let the target join.

Apply minimal fix:

-						sender: creatorUserId,
+						sender: targetUserId,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await stateService.buildEvent<'m.room.member'>(
{
type: 'm.room.member',
content: {
membership: 'join',
is_direct: true,
displayname: displayname,
},
room_id: roomCreateEvent.roomId,
state_key: targetUserId,
auth_events: [],
depth: 0,
prev_events: [],
origin_server_ts: Date.now(),
sender: creatorUserId,
},
PersistentEventFactory.defaultRoomVersion,
);
await stateService.buildEvent<'m.room.member'>(
{
type: 'm.room.member',
content: {
membership: 'join',
is_direct: true,
displayname: displayname,
},
room_id: roomCreateEvent.roomId,
state_key: targetUserId,
auth_events: [],
depth: 0,
prev_events: [],
origin_server_ts: Date.now(),
sender: targetUserId,
},
PersistentEventFactory.defaultRoomVersion,
);
🤖 Prompt for AI Agents
In packages/federation-sdk/src/services/room.service.ts around lines 1346 to
1363, the generated 'm.room.member' join event incorrectly uses sender:
creatorUserId while state_key is targetUserId; for a direct join the sender must
be the joining user. Fix by changing the event sender to targetUserId when
membership is 'join' (leave the rest of the payload unchanged), or alternatively
convert this to an 'invite' event (membership: 'invite') with sender:
creatorUserId if you intend an invite flow—apply the minimal change to set
sender: targetUserId for the current join path.

Updated message content types in the core and federation SDK to better categorize message types into text, file, and location. Introduced new schemas for message content, including detailed structures for file information and new content for edits. This refactor improves type safety and clarity in message handling across the application.
…ntFactory

Updated the RoomService and PersistentEventFactory to use a new unified method for creating events, enhancing code consistency and readability. This change replaces multiple event creation methods with a single `newEvent` method, streamlining the process of generating various room-related events.
Refactored the event creation process in InviteService, MessageService, ProfilesService, RoomService, and StateService to utilize the new `buildEvent` method. This change enhances code consistency and readability by standardizing how events are constructed and signed across different services.
…ntFactory

Eliminated multiple outdated methods for creating various room events in PersistentEventFactory. This refactor simplifies the codebase by relying on the unified `newEvent` method, enhancing maintainability and consistency in event generation.
Updated ProfilesService, RoomService, and SendJoinService to utilize the new `buildEvent` method for creating room events. This refactor enhances code consistency and readability by standardizing the event construction process across multiple services, while also removing deprecated methods for adding authentication and previous events.
Updated message content types in the core and federation SDK to better categorize message types into text, file, and location. Introduced new schemas for message content, including detailed structures for file information and new content for edits. This refactor improves type safety and clarity in message handling across the application.
@ggazzo ggazzo force-pushed the chore/simplfy-factory branch from a562524 to f7848ef Compare September 14, 2025 23:50
@ggazzo ggazzo changed the base branch from main to chore/message-type September 14, 2025 23:50
@ggazzo ggazzo marked this pull request as ready for review September 14, 2025 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants