-
Notifications
You must be signed in to change notification settings - Fork 19
refactor: replace string event IDs with EventID #200
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
Conversation
WalkthroughType-only migration: most event identifier types changed from plain Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Controller as Homeserver Controller
participant Service as Event/Room Service
participant Repo as Repository / Store
Controller->>Service: call API (params cast to EventID / EventID[])
Service->>Repo: query/persist using EventID or EventID[]
Note over Controller,Repo: All event-id parameters are EventID (type-only)
sequenceDiagram
autonumber
participant RoomSvc as RoomService
participant AuthMap as AuthEvents Map
participant Builder as Tombstone Builder
RoomSvc->>AuthMap: collect auth candidate IDs (may be undefined)
AuthMap-->>RoomSvc: map with optional IDs
RoomSvc->>Builder: filter defined IDs -> auth_events: EventID[]
Builder-->>RoomSvc: tombstone event payload (auth_events typed EventID[])
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #200 +/- ##
==========================================
+ Coverage 81.12% 81.14% +0.01%
==========================================
Files 62 63 +1
Lines 4662 4666 +4
==========================================
+ Hits 3782 3786 +4
Misses 880 880 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…ated files for improved type safety
54dc4cb to
385b58a
Compare
613a78c to
b50354c
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
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.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (8)
packages/federation-sdk/src/repositories/room.repository.ts (2)
54-60: Bug: projection path is wrong;getRoomVersionalways returns null.The version lives under
room.version; projectingversionomits theroomobject.- const room = await this.collection.findOne( - { _id: roomId }, - { projection: { version: 1 } }, - ); + const room = await this.collection.findOne( + { _id: roomId }, + { projection: { 'room.version': 1 } }, + );
62-68: Bug: filter usesroom_idinstead of_id; update will never match.- await this.collection.updateOne( - { room_id: roomId }, - { $set: { name: name } }, - { upsert: false }, - ); + await this.collection.updateOne( + { _id: roomId }, + { $set: { 'room.name': name } }, + { upsert: false }, + );packages/room/src/state_resolution/definitions/algorithm/v2.spec.ts (2)
57-67: Branding mismatch: assigning a plain string to EventID._event_id is branded; constructing it with a string breaks the brand in strict mode. Cast or brand via a helper.
Apply:
- _event_id: EventID; + _event_id: EventID; @@ - this._event_id = `${id}:example.com`; + this._event_id = `${id}:example.com` as EventID;
15-19: MockEventStore signature must match updated EventStore (EventID[]).Interface now requires EventID[]. Update the mock to avoid type mismatch.
Apply:
- async getEvents(eventIds: string[]): Promise<PersistentEventBase[]> { + async getEvents(eventIds: EventID[]): Promise<PersistentEventBase[]> { return this.events.filter((e) => eventIds.includes(e.eventId)); }packages/room/src/types/v3-11.ts (1)
134-137: Migrate remainingevent_idstrings toeventIdSchema.Replace the z.string() event_id fields in packages/room/src/types/v3-11.ts at lines 134–136, 387–390, 397–399, 520–522 with the branded schema.
@@ - event_id: z - .string() - .describe('The event ID of the last known event in the old room.'), + event_id: eventIdSchema.describe( + 'The event ID of the last known event in the old room.', + ), @@ - event_id: z - .string() - .optional() - .describe('The ID of the event that is being related to.'), + event_id: eventIdSchema + .optional() + .describe('The ID of the event that is being related to.'), @@ - event_id: z - .string() - .describe('The ID of the latest event in the thread for fallback'), + event_id: eventIdSchema.describe( + 'The ID of the latest event in the thread for fallback', + ), @@ - event_id: z - .string() - .describe('The ID of the event that is being annotated.'), + event_id: eventIdSchema.describe('The ID of the event that is being annotated.'),packages/federation-sdk/src/repositories/event.repository.ts (2)
296-301: Filter by _id (use EventID[]) — query uses non-existent eventIdThis query filters on a non-existent field (eventId) and will return no results; change to _id and use EventID[]; update callers and add a quick test.
File: packages/federation-sdk/src/repositories/event.repository.ts Lines: 296-301
- findFromNonPublicRooms(eventIds: string[]): FindCursor<EventStore> { - return this.collection.find({ - eventId: { $in: eventIds }, + findFromNonPublicRooms(eventIds: EventID[]): FindCursor<EventStore> { + return this.collection.find({ + _id: { $in: eventIds }, 'event.content.join_rule': { $ne: 'public' }, }); }Update callers to pass EventID[] and add a quick test.
365-385: Wrong field and type for exclusion filter — fix to use _id and EventID[]; add testStored events use _id for the event ID; the current query filters on event_id and accepts string[], so exclusions never match. Update the parameter type and filter.
File: packages/federation-sdk/src/repositories/event.repository.ts (findEventsByRoomAndDepth, ~lines 365–385)
- findEventsByRoomAndDepth( + findEventsByRoomAndDepth( roomId: string, minDepth: number, maxDepth: number, - excludeEventIds: string[], + excludeEventIds: EventID[], limit: number, ): FindCursor<EventStore<Pdu>> { return this.collection .find( { 'event.room_id': roomId, 'event.depth': { $gte: minDepth, $lte: maxDepth }, - event_id: { $nin: excludeEventIds }, + _id: { $nin: excludeEventIds }, }, { projection: { event: 1 }, }, ) .sort({ 'event.depth': 1 }) .limit(limit); }Add a unit/integration test asserting excluded IDs are not returned.
packages/federation-sdk/src/services/event.service.ts (1)
472-498: Fix findEventsByRoomAndDepth to accept EventID[] and filter on _id
findEventsByRoomAndDepth currently types excludeEventIds as string[] and queries event_id: { $nin: ... } (packages/federation-sdk/src/repositories/event.repository.ts, ~line 365). The service passes EventID[] and repository events are stored under _id. Change the method signature to excludeEventIds: EventID[] and update the query to _id: { $nin: excludeEventIds }. After applying the change, re-run missing-events tests.
🧹 Nitpick comments (32)
packages/room/src/state_resolution/definitions/algorithm/v2.ts (2)
107-108: EventID[] migration here is good; tighten the wrapper’s method signature for safety.
eventIdsToFindasEventID[]aligns with the store API. Consider typing the wrapper toEventStoreand the param toreadonly EventID[]to prevent accidental string arrays.- const wrappedStore: typeof store = { - async getEvents(eventIds) { + const wrappedStore: EventStore = { + async getEvents(eventIds: readonly EventID[]) {
175-184: Batch fetch conflicted power events instead of N sequential awaits.Current loop does 1 RPC per ID. Collect and fetch in one call to reduce I/O.
- for (const eventid of fullConflictedSet) { - const [event] = await wrappedStore.getEvents([eventid]); - if (!event) { - console.warn('event not found in eventMap', eventid); - continue; - } - if (isPowerEvent(event)) { - powerEvents.set(event.eventId, event); - } - } + { + const ids = Array.from(fullConflictedSet); + const events = await wrappedStore.getEvents(ids); + for (const event of events) { + if (!event) continue; + if (isPowerEvent(event)) { + powerEvents.set(event.eventId, event); + } + } + }packages/federation-sdk/src/repositories/room.repository.ts (1)
15-16: Align types:tombstone_event_idisEventID; acceptEventIDinmarkRoomAsDeleted.Avoid passing plain
stringto a brandedEventIDfield.- async markRoomAsDeleted( - roomId: string, - tombstoneEventId: string, - ): Promise<void> { + async markRoomAsDeleted( + roomId: string, + tombstoneEventId: EventID, + ): Promise<void> { await this.collection.updateOne( { _id: roomId }, { $set: { 'room.deleted': true, 'room.tombstone_event_id': tombstoneEventId, }, }, ); }Also applies to: 73-86
packages/federation-sdk/src/repositories/state.repository.ts (1)
37-41:getLatestStateMappingreturns the oldest due to ascending sort.Use
-1to fetch the latest.- return this.collection.findOne({ roomId }, { sort: { createdAt: 1 } }); + return this.collection.findOne({ roomId }, { sort: { createdAt: -1 } });packages/core/src/events/m.room.guest_access.ts (1)
1-1: Use package alias and type-only import forEventID; param type changes LGTM.Avoid deep path; keep consistency with other files.
-import { EventID } from 'packages/room/dist'; +import type { EventID } from '@hs/room';Also applies to: 28-30
packages/federation-sdk/src/services/missing-event.service.ts (1)
3-3: Use package alias and type-only import; name the logger after the service.Small hygiene tweaks.
-import { EventID } from 'packages/room/dist'; +import type { EventID } from '@hs/room';-private readonly logger = createLogger('EventService'); +private readonly logger = createLogger('MissingEventService');Also applies to: 17-17
packages/homeserver/src/controllers/internal/room.controller.ts (1)
4-8: MarkEventIDas type-only; parseevent_idinstead of casting.This preserves the brand and avoids leaking values imports.
-import { - EventID, - type PduCreateEventContent, - PersistentEventFactory, -} from '@hs/room'; +import { + type EventID, + type PduCreateEventContent, + PersistentEventFactory, +} from '@hs/room';- const room = await stateService.findStateAtEvent(eventId as EventID); + import { eventIdSchema } from '@hs/room'; + const room = await stateService.findStateAtEvent(eventIdSchema.parse(eventId));Also applies to: 192-193
packages/homeserver/src/controllers/internal/message.controller.ts (1)
119-119: LGTM on EventID casts; make the other call sites consistent.
unsetReactionandredactMessagenow passEventID. Do the same forupdateMessageandsendReactionto avoid mixed typing.Suggested updates elsewhere in this file:
// in updateMessage handler params.messageId as EventID // in sendReaction handler params.messageId as EventIDPlease confirm MessageService method signatures now expect
EventID. If not, align them or narrow here.Also applies to: 158-158
packages/core/src/models/event.model.ts (1)
1-1: Great: persisted _id is EventID. Now align adjacent ID fields.To keep branding consistent and prevent accidental mixing with plain strings, consider updating nearby types:
- missing_dependencies?: EventID[]
- EventStore.nextEventId: EventID
- FetchedEvents.events[].eventId: EventID
- FetchedEvents.missingEventIds: EventID[]
Example (outside selected lines):
interface PersistentEventBase<E = Pdu> { _id: EventID; // ... missing_dependencies?: EventID[]; } export interface EventStore<E = Pdu> extends PersistentEventBase<E> { stateId: string; nextEventId: EventID; } export interface FetchedEvents { events: { eventId: EventID; event: CoreEventBase }[]; missingEventIds: EventID[]; }Also applies to: 7-7
packages/federation-sdk/src/services/send-join.service.ts (1)
3-3: Good: public API now takes EventID; tighten local typing and avoid variable shadowing.
- Type
authChainasEventID[]to preserve branding end‑to‑end.- Avoid reusing the identifier
eventinside thefor...ofloop (shadows the method param).Outside the selected lines:
const authChain: EventID[] = []; for (const ev of state.values()) { const authEvents = await getAuthChain(ev, stateService._getStore(roomVersion)); authChain.push(...authEvents); }Also applies to: 24-24
packages/federation-sdk/src/services/staging-area.service.ts (1)
6-6: Remove redundantas EventIDcasts in emitter payloads.
eventIdis alreadyEventID(via EventStagingStore._id). Casting is unnecessary noise.Apply:
- event_id: eventId as EventID, + event_id: eventId,Repeat for the redaction and membership emitters. The type‑only import on Line 6 is correct.
Also applies to: 166-167, 182-183, 195-196
packages/room/src/manager/v3.ts (1)
19-21: Avoid casts by typing raw_event.prev_events as EventID[] at the source.The cast works, but updating the PDU type would remove the need for
as EventID[].packages/federation-sdk/src/services/room.service.ts (2)
1040-1049: Auth event map now uses actual IDs; consider enforcing required keys.Filtering undefined later is good, but tombstone should require create, power_levels, and member. Fail fast if any are missing.
Apply:
const authEventsMap: TombstoneAuthEvents = { 'm.room.create': authEvents.find( (event) => event.event.type === 'm.room.create', )?._id, 'm.room.power_levels': authEvents.find( (event) => event.event.type === 'm.room.power_levels', )?._id, 'm.room.member': authEvents.find( (event) => event.event.type === 'm.room.member', )?._id, }; + const missing = Object.entries(authEventsMap) + .filter(([, id]) => !id) + .map(([t]) => t); + if (missing.length) { + throw new HttpException( + `Missing auth events for tombstone: ${missing.join(', ')}`, + HttpStatus.FORBIDDEN, + ); + }
1052-1055: Minor: tighten filtering with a type guard.Keeps types precise without an assertion.
Apply:
- const authEventsArray = Object.values(authEventsMap).filter( - (event) => event !== undefined, - ) as EventID[]; + const authEventsArray = Object.values(authEventsMap).filter( + (e): e is EventID => Boolean(e), + );packages/core/src/utils/generateId.ts (2)
2-2: Mark EventID import as type‑only.-import { EventID } from 'packages/room/dist'; +import type { EventID } from 'packages/room/dist';
7-15: Return type change to EventID looks good; casting is acceptable.Optional: centralize branding to reduce repeated
as EventIDcasts (e.g., a tinyasEventID(s: string): EventIDhelper).packages/core/src/events/m.room.tombstone.ts (2)
1-1: Type‑only import for EventID.-import { EventID } from 'packages/room/dist'; +import type { EventID } from 'packages/room/dist';
41-45:isTruthyhelper is duplicated across modules.Consider a shared utility (e.g.,
utils/predicates.ts) to DRY.packages/room/src/types/v3-11.ts (1)
556-561: Use eventIdSchema for top‑levelredactsto finish the migration.- redacts: z - .string() - .describe( - 'The ID of the event that this event redacts. This is an optional field.', - ) - .optional(), + redacts: eventIdSchema + .describe('The ID of the event that this event redacts.') + .optional(),packages/core/src/events/m.room.power_levels.ts (2)
1-1: Type‑only import for EventID.-import { EventID } from 'packages/room/dist'; +import type { EventID } from 'packages/room/dist';
57-60: Make'm.room.member'optional (matches TODO/tests) and avoid cast with a typed predicate.- auth_events: { - 'm.room.create': EventID; - 'm.room.power_levels': EventID; - 'm.room.member': EventID; // TODO: Based on the tests, this is optional, based on the code, this is required check this - }; + auth_events: { + 'm.room.create': EventID; + 'm.room.power_levels': EventID; + 'm.room.member'?: EventID; // optional per tests + }; @@ - auth_events: [ + auth_events: [ auth_events['m.room.create'], auth_events['m.room.power_levels'], auth_events['m.room.member'], - ].filter(Boolean) as EventID[], + ].filter((e): e is EventID => Boolean(e)),If any callers relied on
'm.room.member'being required, CI/type‑check will surface them. Please confirm no regressions.packages/federation-sdk/src/services/message.service.ts (4)
75-76: Fix typos: “white” → “while”.Tiny copy edit in error messages.
-`Room version not found for room ${roomId} white trying to send message`, +`Room version not found for room ${roomId} while trying to send message`,Also applies to: 117-120
379-413: Variable name “redactionEvent” is misleading for an edit event.This block creates an m.room.message replacement, not a redaction. Rename for clarity.
-const redactionEvent = await this.stateService.buildEvent<'m.room.message'>( +const replacementEvent = await this.stateService.buildEvent<'m.room.message'>( ... -await this.stateService.persistTimelineEvent(redactionEvent); -void this.federationService.sendEventToAllServersInRoom(redactionEvent); -return redactionEvent.eventId; +await this.stateService.persistTimelineEvent(replacementEvent); +void this.federationService.sendEventToAllServersInRoom(replacementEvent); +return replacementEvent.eventId;
339-353: Good: unsetReaction now brands the target ID. Also update return type.Return should be EventID for consistency with the new branding.
-): Promise<string> { +): Promise<EventID> {
417-453: Good: redactMessage now brands the target ID. Also update return type.Return should be EventID as well.
-): Promise<string> { +): Promise<EventID> {packages/federation-sdk/src/repositories/event-staging.repository.ts (1)
3-3: Prefer type-only import for Pdu.Avoids emitting a runtime import for a type.
-import { type EventID, Pdu } from '@hs/room'; +import { type EventID, type Pdu } from '@hs/room';packages/federation-sdk/src/utils/event-schemas.ts (1)
13-18: Align prev_events/auth_events with EventID branding.These still accept string/tuple. If you intend to enforce EventID, update schemas to brand event IDs too while preserving tuple support.
-prev_events: z - .array(z.string().or(z.tuple([z.string(), z.string()]))) - .optional(), -auth_events: z - .array(z.string().or(z.tuple([z.string(), z.string()]))) - .optional(), +prev_events: z + .array(eventIdSchema.or(z.tuple([eventIdSchema, z.string()]))) + .optional(), +auth_events: z + .array(eventIdSchema.or(z.tuple([eventIdSchema, z.string()]))) + .optional(),If inbound federation must accept legacy strings, keep the union but brand the event_id member as above.
packages/room/src/types/_common.ts (2)
4-8: Branding scaffold is solid; consider not exporting the brand symbol.Exporting Brand/Branded is fine; exporting the unique symbol is usually unnecessary. Optional.
-export declare const __brand: unique symbol; +declare const __brand: unique symbol; +export { __brand as /* internal */ __brand };Or simply keep it non-exported if not needed by consumers of Brand/Branded.
1-1: Minor consistency nit: prefer named import from zod.Other files import
{ z }. Standardize if you like.-import z from 'zod'; +import { z } from 'zod';packages/core/src/events/m.room.redaction.ts (1)
1-1: Unify import path and make it type-only.Use the public barrel and avoid value import.
-import { EventID } from 'packages/room/dist'; +import type { EventID } from '@hs/room';packages/federation-sdk/src/services/state.service.ts (1)
778-779: Drop redundant cast to EventID[].Pdu.auth_events should already be EventID[]. Remove the cast to keep types honest.
- const authEventsReferencedInMessage = await store.getEvents( - event.event.auth_events as EventID[], - ); + const authEventsReferencedInMessage = await store.getEvents( + event.event.auth_events, + );If this fails TS, there’s a lingering string[] somewhere in Pdu; I can help locate and fix.
packages/federation-sdk/src/repositories/event.repository.ts (1)
205-210: Minor: redundant _id != '' filter.new events are always non-empty ids; this predicate adds noise and no safety.
- .find({ - nextEventId: '', - 'event.room_id': roomId, - _id: { $ne: '' as EventID }, - }) + .find({ + nextEventId: '', + 'event.room_id': roomId, + })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (42)
packages/core/src/events/eventBase.ts(4 hunks)packages/core/src/events/m.reaction.ts(5 hunks)packages/core/src/events/m.room.guest_access.ts(2 hunks)packages/core/src/events/m.room.history_visibility.ts(2 hunks)packages/core/src/events/m.room.join_rules.ts(2 hunks)packages/core/src/events/m.room.member.ts(3 hunks)packages/core/src/events/m.room.message.ts(4 hunks)packages/core/src/events/m.room.name.ts(3 hunks)packages/core/src/events/m.room.power_levels.ts(3 hunks)packages/core/src/events/m.room.redaction.ts(4 hunks)packages/core/src/events/m.room.tombstone.ts(3 hunks)packages/core/src/models/event.model.ts(1 hunks)packages/core/src/types.ts(1 hunks)packages/core/src/utils/generateId.ts(1 hunks)packages/federation-sdk/src/index.ts(5 hunks)packages/federation-sdk/src/repositories/event-staging.repository.ts(3 hunks)packages/federation-sdk/src/repositories/event.repository.ts(8 hunks)packages/federation-sdk/src/repositories/room.repository.ts(2 hunks)packages/federation-sdk/src/repositories/state.repository.ts(1 hunks)packages/federation-sdk/src/services/event-fetcher.service.ts(2 hunks)packages/federation-sdk/src/services/event.service.ts(9 hunks)packages/federation-sdk/src/services/message.service.ts(3 hunks)packages/federation-sdk/src/services/missing-event.service.ts(1 hunks)packages/federation-sdk/src/services/profiles.service.ts(2 hunks)packages/federation-sdk/src/services/room.service.ts(3 hunks)packages/federation-sdk/src/services/send-join.service.ts(2 hunks)packages/federation-sdk/src/services/staging-area.service.ts(5 hunks)packages/federation-sdk/src/services/state.service.ts(7 hunks)packages/federation-sdk/src/utils/event-schemas.ts(4 hunks)packages/homeserver/src/controllers/federation/profiles.controller.ts(2 hunks)packages/homeserver/src/controllers/federation/send-join.controller.ts(2 hunks)packages/homeserver/src/controllers/federation/state.controller.ts(3 hunks)packages/homeserver/src/controllers/federation/transactions.controller.ts(2 hunks)packages/homeserver/src/controllers/internal/message.controller.ts(3 hunks)packages/homeserver/src/controllers/internal/room.controller.ts(2 hunks)packages/room/src/manager/event-wrapper.ts(3 hunks)packages/room/src/manager/v3.ts(3 hunks)packages/room/src/state_resolution/definitions/algorithm/v2.spec.ts(2 hunks)packages/room/src/state_resolution/definitions/algorithm/v2.ts(1 hunks)packages/room/src/state_resolution/definitions/definitions.ts(1 hunks)packages/room/src/types/_common.ts(1 hunks)packages/room/src/types/v3-11.ts(4 hunks)
🔇 Additional comments (35)
packages/federation-sdk/src/repositories/state.repository.ts (1)
11-19: EventID branding indelta.eventId: LGTM.Type-level change is consistent with upstream types and assignments.
Also applies to: 70-77
packages/core/src/types.ts (1)
2-10:SignedEvent.event_id→EventID: LGTM.Type-only import keeps runtime clean.
packages/homeserver/src/controllers/federation/send-join.controller.ts (1)
2-2: LGTM: type‑only import and EventID cast are consistent with the migration.If SendJoinService later loosens its input (e.g., branded validators), this cast can be removed.
Also applies to: 23-23
packages/homeserver/src/controllers/federation/state.controller.ts (1)
22-22: Incorrect — event_id is required by DTO; cast is safeGetStateQueryDto and GetStateIdsQueryDto declare event_id as a required t.String (packages/homeserver/src/dtos/federation/state.dto.ts and packages/homeserver/src/dtos/federation/state-ids.dto.ts) and eventService.getState / getStateIds expect a non-optional EventID — no change required.
Likely an incorrect or invalid review comment.
packages/room/src/state_resolution/definitions/algorithm/v2.spec.ts (1)
1-1: Type import alignment looks good.Using a type‑only import for EventID/StateMapKey keeps the test runtime‑clean.
packages/room/src/manager/v3.ts (1)
31-33: EventID computation is correct and branded.Escaped
$and urlSafe base64 match Matrix v3 spec; branding is explicit.packages/room/src/manager/event-wrapper.ts (1)
120-120: Public API change: eventId now branded.Good alignment with EventID across the codebase.
packages/federation-sdk/src/services/profiles.service.ts (1)
109-115: Type migration to EventID[] for missing events is consistent.Signature aligns with EventService; pass‑through preserved.
packages/federation-sdk/src/services/room.service.ts (1)
1064-1064: LGTM on using the filtered auth_events array.Prevents empty/undefined IDs leaking into the tombstone.
packages/core/src/events/m.room.name.ts (1)
20-23: EventID migration here is consistent and correct.Also applies to: 56-56
packages/core/src/events/m.room.tombstone.ts (1)
24-27: Auth/prev_events typed to EventID (optionals filtered) — LGTM.Also applies to: 35-35
packages/room/src/types/v3-11.ts (2)
2-2: Schema shifts to eventIdSchema are correct and consistent with the EventID migration.Also applies to: 200-201, 534-535, 552-553
198-201: Spec alignment: clarify or remove content.redacts in redaction schemaTests in the repo reference content.redacts, so removing it will affect consumers. Locations: packages/room/src/types/v3-11.ts — PduRoomRedactionContentSchema (lines 198–201); usages: packages/room/src/manager/event-wrapper.spec.ts (lines 267, 282, 287). Action: either add an inline comment in the schema documenting that content.redacts is intentionally present for compatibility, or remove content.redacts from the schema and update the referenced tests/consumers to use top‑level redacts.
packages/core/src/events/m.room.member.ts (2)
21-28: AuthEvents/EventID migration looks correct.Keys and the dynamic member mapping now brand to EventID. Nice.
54-54: prev_events → EventID[] is aligned with the new EventBase typing.LGTM.
packages/federation-sdk/src/repositories/event-staging.repository.ts (2)
16-21: create(eventId: EventID, …): upsert logic remains correct.Branding the _id with EventID is aligned with the migration.
43-45: removeByEventId(eventId: EventID): aligned and clear.LGTM.
packages/federation-sdk/src/utils/event-schemas.ts (4)
1-1: Importing eventIdSchema is the right move.Enables branded validation where needed.
10-11: event_id now uses eventIdSchema.Consistent with EventID branding. Good.
66-67: reaction: relates_to.event_id uses eventIdSchema.Matches the spec and the new typing.
101-104: redaction.redacts uses eventIdSchema.Good consistency.
packages/core/src/events/m.room.message.ts (4)
1-1: Type-only EventID import: good.Consistent with the branding approach.
76-86: Relation event_id fields branded to EventID.This tightens types for both m.annotation and m.replace.
94-98: Auth events now require EventID.Correct and consistent with event base changes.
137-144: prev_events: EventID[] is correct.Matches the updated EventBase expectations.
packages/room/src/types/_common.ts (1)
11-14: eventIdSchema and EventID type look good.Runtime validation + branded type are aligned.
packages/federation-sdk/src/services/message.service.ts (1)
17-21: Migrate all event-id params/returns in message.service.ts to EventID — verification requiredRan the ripgrep check; it returned no output, so I could not confirm whether remaining methods still use string-typed event IDs. Re-run this to verify presence of string-typed event IDs:
rg -n --type=ts -C2 $'\b(eventId|eventIdToRedact|eventIdToReplace|eventToReplyTo|threadRootEventId|latestThreadEventId)\s*:\s*string\b' packages/federation-sdk/src/services/message.service.tsIf matches exist, convert these signatures to EventID/Promise (minimal deltas):
- ): Promise<string> { + ): Promise<EventID> { async sendReaction( roomId: string, - eventId: string, + eventId: EventID, emoji: string, senderUserId: string, -): Promise<string> { +): Promise<EventID> { async sendReplyToMessage( roomId: string, rawMessage: string, formattedMessage: string, - eventToReplyTo: string, + eventToReplyTo: EventID, senderUserId: string, ): Promise<PersistentEventBase> { async sendThreadMessage( roomId: string, rawMessage: string, formattedMessage: string, senderUserId: string, - threadRootEventId: string, - latestThreadEventId?: string, + threadRootEventId: EventID, + latestThreadEventId?: EventID, ): Promise<PersistentEventBase> { async sendReplyToInsideThreadMessage( roomId: string, rawMessage: string, formattedMessage: string, senderUserId: string, - threadRootEventId: string, - eventToReplyTo: string, + threadRootEventId: EventID, + eventToReplyTo: EventID, ): Promise<PersistentEventBase> { async updateMessage( roomId: string, rawMessage: string, formattedMessage: string, senderUserId: string, - eventIdToReplace: string, -): Promise<string> { + eventIdToReplace: EventID, +): Promise<EventID> {packages/core/src/events/m.room.redaction.ts (1)
12-15: LGTM: EventID typed redaction fields.Auth event IDs, content.redacts, and prev_events are correctly branded as EventID.
Also applies to: 28-28, 51-51, 54-54
packages/core/src/events/m.reaction.ts (1)
1-1: LGTM: Reaction event surfaces now use EventID.Imports and all event_id fields consistently branded; no logic changes.
Also applies to: 11-11, 23-26, 37-37, 66-66, 71-71
packages/federation-sdk/src/services/state.service.ts (1)
119-121: LGTM: State service API/storage maps migrated to EventID.Signatures and internal maps now carry EventID without behavior changes.
Also applies to: 256-258, 271-273, 348-351, 376-379
packages/federation-sdk/src/index.ts (1)
2-2: LGTM: Public Homeserver event signatures branded with EventID.Consistent, non-breaking type-level changes.
Also applies to: 110-110, 119-119, 121-121, 136-136, 147-147, 154-154, 160-160, 164-164, 170-170
packages/federation-sdk/src/services/event.service.ts (2)
758-759: LGTM: Auth chain tracked as Set.Matches EventID branding all the way to store.getEvents.
69-78: Bug: getEventById passes eventId to findByRoomIdAndType (uses room lookup instead of event ID).Call findById(eventId), return null if not found, then return null if res.event.type !== type; otherwise return res. Add/adjust tests to cover both branches (with and without type). Location: packages/federation-sdk/src/services/event.service.ts lines 69–78
packages/federation-sdk/src/repositories/event.repository.ts (1)
268-274: LGTM: findByIds now typed to EventID[].Consistent with the rest of the repository API.
packages/core/src/events/eventBase.ts (1)
5-6: LGTM: EventID migration on core event base.Types updated correctly for auth_events/prev_events and redacts — confirmed that packages/core/src/events use EventID (e.g., packages/core/src/events/eventBase.ts lines 5–6) and no remaining string-typed auth_events/prev_events/redacts were found. No runtime behavior changes introduced.
| @@ -1,3 +1,4 @@ | |||
| import { EventID } from 'packages/room/dist'; | |||
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.
Wrong import path for EventID; use package alias.
Using 'packages/room/dist' will break outside the monorepo build. Import from '@hs/room' as a type.
Apply:
-import { EventID } from 'packages/room/dist';
+import type { EventID } from '@hs/room';📝 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.
| import { EventID } from 'packages/room/dist'; | |
| import type { EventID } from '@hs/room'; |
🤖 Prompt for AI Agents
In packages/core/src/events/m.room.history_visibility.ts around line 1, the file
currently imports EventID from the local path 'packages/room/dist' which will
break consumers outside the monorepo; change the import to use the package alias
and import EventID as a type from '@hs/room' (e.g. replace the existing import
with a type-only import from '@hs/room') so builds and external consumers
resolve the symbol correctly.
| @@ -1,3 +1,4 @@ | |||
| import { EventID } from 'packages/room/dist'; | |||
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.
🛠️ Refactor suggestion
🧩 Analysis chain
Fix EventID import path; prefer type‑only import.
Use the same source as the rest of the repo and avoid pulling runtime code for a type.
Apply:
-import { EventID } from 'packages/room/dist';
+import type { EventID } from '@hs/room';The EventID[] parameter changes on Lines 37–38 look correct and align with the project‑wide migration.
Also applies to: 37-38
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== show target file (first 200 lines) ==="
if [ -f packages/core/src/events/m.room.join_rules.ts ]; then
sed -n '1,240p' packages/core/src/events/m.room.join_rules.ts || true
else
echo "MISSING: packages/core/src/events/m.room.join_rules.ts"
fi
echo
echo "=== show lines 1-120 with numbers for quick reference ==="
if [ -f packages/core/src/events/m.room.join_rules.ts ]; then
nl -ba -w3 -s': ' packages/core/src/events/m.room.join_rules.ts | sed -n '1,120p' || true
fi
echo
echo "=== search repo for EventID symbol usages (context) ==="
if command -v rg >/dev/null 2>&1; then
rg -n --hidden -S '\bEventID\b' || true
else
grep -RIn --line-number '\bEventID\b' . || true
fi
echo
echo "=== search for imports that pull from packages/room/dist ==="
if command -v rg >/dev/null 2>&1; then
rg -n --hidden -S "packages/room/dist" || true
else
grep -RIn --line-number "packages/room/dist" . || true
fi
echo
echo "=== search for @hs/room occurrences ==="
if command -v rg >/dev/null 2>&1; then
rg -n --hidden -S "@hs/room" || true
else
grep -RIn --line-number "@hs/room" . || true
fi
echo
echo "=== packages/room package.json (if present) ==="
if [ -f packages/room/package.json ]; then
sed -n '1,240p' packages/room/package.json || true
else
echo "MISSING: packages/room/package.json"
fi
echo
echo "=== list top files under packages/room ==="
if [ -d packages/room ]; then
find packages/room -maxdepth 3 -type f | sed -n '1,200p' || true
else
echo "MISSING: packages/room directory"
fi
echo
echo "=== show root package.json and tsconfig.json (first 200 lines) ==="
if [ -f package.json ]; then
sed -n '1,240p' package.json || true
else
echo "MISSING: package.json"
fi
echo
if [ -f tsconfig.json ]; then
sed -n '1,240p' tsconfig.json || true
else
echo "MISSING: tsconfig.json"
fiLength of output: 29169
Fix EventID import — use a type-only import from @hs/room
Apply:
-import { EventID } from 'packages/room/dist';
+import type { EventID } from '@hs/room';auth_events / prev_events (lines 37–38) are already correctly typed as EventID[].
Also update other occurrences that import from 'packages/room/dist' (e.g. packages/core/src/utils/generateId.ts, packages/core/src/events/*.ts, packages/federation-sdk/src/services/missing-event.service.ts).
📝 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.
| import { EventID } from 'packages/room/dist'; | |
| import type { EventID } from '@hs/room'; |
| @@ -1,3 +1,4 @@ | |||
| import { EventID } from 'packages/room/dist'; | |||
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.
Fix import path and make it type‑only.
Use the package alias consistently and avoid a runtime import.
-import { EventID } from 'packages/room/dist';
+import type { EventID } from '@hs/room';📝 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.
| import { EventID } from 'packages/room/dist'; | |
| import type { EventID } from '@hs/room'; |
🤖 Prompt for AI Agents
In packages/core/src/events/m.room.member.ts around line 1, replace the runtime
import from 'packages/room/dist' with a type‑only import using the package alias
(e.g. import type { EventID } from 'room';) so the value is not imported at
runtime; ensure EventID is used only as a type or add a type-only import where
referenced.
| @@ -1,3 +1,4 @@ | |||
| import { EventID } from 'packages/room/dist'; | |||
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.
🧩 Analysis chain
Use a type‑only import for EventID to avoid runtime dependency on 'packages/room/dist'.
Prevents accidental runtime import under verbatimModuleSyntax/ESM.
-import { EventID } from 'packages/room/dist';
+import type { EventID } from 'packages/room/dist';Please confirm tsconfig has either importsNotUsedAsValues: "remove" or that you’re using type‑only imports repo‑wide to avoid runtime loads of types. Run:
🏁 Script executed:
#!/bin/bash
fd -a 'tsconfig*.json' | xargs -I{} jq -r '.compilerOptions.importsNotUsedAsValues?, .compilerOptions.verbatimModuleSyntax?' {} 2>/dev/nullLength of output: 64
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf "PWD: %s\n\n" "$(pwd)"
echo "=== tsconfig files ==="
fd -HI -a 'tsconfig*.json' 2>/dev/null || true
for f in $(fd -HI -a 'tsconfig*.json' 2>/dev/null || true); do
echo -e "\n--- $f ---"
# print the two properties if present, otherwise indicate MISSING
jq -r 'if .compilerOptions then
"importsNotUsedAsValues: " + (.compilerOptions.importsNotUsedAsValues // "MISSING") + "\nverbatimModuleSyntax: " + ( (.compilerOptions.verbatimModuleSyntax // "MISSING") | tostring )
else
"no compilerOptions"
end' "$f" 2>/dev/null || { echo "jq failed; printing first 200 chars:"; sed -n '1,40p' "$f"; }
done
echo -e "\n=== packages/core/src/events/m.room.name.ts ==="
if [ -f packages/core/src/events/m.room.name.ts ]; then
sed -n '1,200p' packages/core/src/events/m.room.name.ts
else
echo "file not found at that exact path; searching for matching files..."
fd -HI 'm.room.name.ts' || true
fi
echo -e "\n=== Search for EventID import patterns ==="
rg -n --hidden --no-ignore --glob '!node_modules' "import\s+type\s*\{[^}]*\bEventID\b[^}]*\}" -S || true
rg -n --hidden --no-ignore --glob '!node_modules' "import\s*\{[^}]*\bEventID\b[^}]*\}" -S || true
echo -e "\n=== Search for imports from packages/room/dist ==="
rg -n --hidden --no-ignore --glob '!node_modules' "from\s+['\"]packages/room/dist['\"]" -S || true
echo -e "\n=== package.json typescript version (if present) ==="
if [ -f package.json ]; then
jq -r '.devDependencies.typescript // .dependencies.typescript // "missing"' package.json 2>/dev/null || true
else
echo "package.json not found at repo root"
fiLength of output: 7223
Use a type-only import for EventID (avoid runtime dependency on 'packages/room/dist')
packages/core/src/events/m.room.name.ts currently uses a value import and no repo tsconfig sets importsNotUsedAsValues or verbatimModuleSyntax, so this will be emitted at runtime. Replace with a type-only import or set importsNotUsedAsValues: "remove" in the relevant tsconfig.
-import { EventID } from 'packages/room/dist';
+import type { EventID } from 'packages/room/dist';📝 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.
| import { EventID } from 'packages/room/dist'; | |
| import type { EventID } from 'packages/room/dist'; |
🤖 Prompt for AI Agents
In packages/core/src/events/m.room.name.ts around line 1, the current import
"import { EventID } from 'packages/room/dist';" is a value import causing a
runtime dependency; change it to a type-only import by replacing it with "import
type { EventID } from 'packages/room/dist';" so TypeScript emits no runtime
require, or alternatively set the relevant tsconfig to include
"importsNotUsedAsValues": "remove" (or enable "verbatimModuleSyntax") in the
project that compiles this file.
| import { createLogger } from '@hs/core'; | ||
| import { generateId } from '@hs/core'; | ||
| import { Pdu } from '@hs/room'; | ||
| import { EventID, Pdu } from '@hs/room'; |
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.
🛠️ Refactor suggestion
🧩 Analysis chain
Align EventID branding across the fetcher inputs, outputs, and locals.
You accept EventID[] but still use plain string for IDs internally and in the return type. This weakens type safety and can hide bugs in equality checks.
Suggested updates (outside selected lines):
export interface FetchedEvents {
events: { eventId: EventID; event: Pdu }[];
missingEventIds: EventID[];
}
const localEvents: { eventId: EventID; event: Pdu }[] = [];
private async fetchEventsFromFederation(
eventIds: EventID[],
targetServerName: string,
): Promise<Pdu[]> { /* ... */ }Also confirm EventRepository.findByIds(...) and FederationService.getEvent(...) accept EventID:
Also applies to: 28-28
🏁 Script executed:
#!/bin/bash
rg -nP -C2 --type=ts '\bfindByIds\s*\('
rg -nP -C2 --type=ts '\bgetEvent\s*\('Length of output: 3223
Align EventID branding across the fetcher inputs, outputs, and locals.
Fetcher accepts EventID[] but uses plain string for local IDs and the federation call; convert internals and signatures to EventID to restore type safety.
- Change localEvents and fetcher return types in packages/federation-sdk/src/services/event-fetcher.service.ts (around line 39 and call sites at ~106–109) from string to EventID.
- Change federation service signature in packages/federation-sdk/src/services/federation.service.ts (line ~151) to accept eventId: EventID and update call sites.
- Confirm/ensure EventRepository.findByIds(...) accepts EventID (used in event.service.ts / state.service.ts); update if necessary.
Suggested edits:
export interface FetchedEvents {
events: { eventId: EventID; event: Pdu }[];
missingEventIds: EventID[];
}
const localEvents: { eventId: EventID; event: Pdu }[] = [];
private async fetchEventsFromFederation(
eventIds: EventID[],
targetServerName: string,
): Promise<Pdu[]> { /* ... */ }
async getEvent(domain: string, eventId: EventID): Promise<Pdu> { /* ... */ }🤖 Prompt for AI Agents
In packages/federation-sdk/src/services/event-fetcher.service.ts around line 4
and particularly near line 39 and call sites ~106–109, the code uses plain
string for local event IDs and federation calls while the module imports
EventID; change all internal locals and signatures to use EventID (e.g.
localEvents array item type, FetchedEvents.missingEventIds, and fetcher return
types). Also update the federation service signature in
packages/federation-sdk/src/services/federation.service.ts (around line ~151) to
accept eventId: EventID and update every call site to pass an EventID, and
verify EventRepository.findByIds(...) (used in event.service.ts /
state.service.ts) accepts EventID[] and change its signature/usage if necessary
so types line up end-to-end. Ensure imports remain correct and adjust any
downstream typings/returns (e.g. fetchEventsFromFederation return type and
getEvent parameter/return types) to maintain type safety.
| @@ -1,5 +1,5 @@ | |||
| import { ProfilesService } from '@hs/federation-sdk'; | |||
| import { type RoomVersion } from '@hs/room'; | |||
| import { EventID, type RoomVersion } from '@hs/room'; | |||
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.
🛠️ Refactor suggestion
🧩 Analysis chain
Avoid unsafe casts; validate/cast to EventID[] at the boundary.
Prefer schema-based parsing over as to keep branding intact.
-import { EventID, type RoomVersion } from '@hs/room';
+import { type EventID, type RoomVersion, eventIdSchema } from '@hs/room';
...
- body.earliest_events as EventID[],
- body.latest_events as EventID[],
+ eventIdSchema.array().parse(body.earliest_events),
+ eventIdSchema.array().parse(body.latest_events),Also applies to: 106-108
🏁 Script executed:
#!/bin/bash
# Find remaining deep imports and unsafe EventID casts.
rg -nP "from ['\"]/?.*packages/room/dist['\"]"
rg -nP "\bas\s+EventID\[\]" -n
rg -nP "\beventId\s*:\s*string\b" --type=ts -n
rg -nP "tombstone_event_id\s*:\s*string\b" --type=ts -nLength of output: 3108
Replace unsafe as EventID[] casts with schema parsing and remove deep 'packages/room/dist' imports
Use a schema (e.g., eventIdSchema.array().parse(...)) at API boundaries and import the schema from '@hs/room' instead of deep 'packages/room/dist'.
Files to fix (precise pointers):
- Deep imports to replace with public export (
@hs/room):- packages/federation-sdk/src/services/missing-event.service.ts:3
- packages/core/src/utils/generateId.ts:2
- packages/core/src/events/m.room.history_visibility.ts:1
- packages/core/src/events/m.room.redaction.ts:1
- packages/core/src/events/m.room.name.ts:1
- packages/core/src/events/m.room.tombstone.ts:1
- packages/core/src/events/m.room.power_levels.ts:1
- packages/core/src/events/m.room.member.ts:1
- packages/core/src/events/m.room.join_rules.ts:1
- packages/core/src/events/m.room.guest_access.ts:1
- Unsafe
as EventID[]casts to replace with parsing:- packages/federation-sdk/src/services/state.service.ts:778
- packages/federation-sdk/src/services/room.service.ts:1054
- packages/homeserver/src/controllers/federation/profiles.controller.ts:106-107
- packages/room/src/manager/v3.ts:20
- packages/room/src/state_resolution/definitions/algorithm/v2.ts:107
- packages/core/src/events/m.room.power_levels.ts:74
Suggested minimal change (example):
-import { EventID, type RoomVersion } from '@hs/room';
+import { type EventID, type RoomVersion, eventIdSchema } from '@hs/room';
...
- body.earliest_events as EventID[],
- body.latest_events as EventID[],
+ eventIdSchema.array().parse(body.earliest_events),
+ eventIdSchema.array().parse(body.latest_events),📝 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.
| import { EventID, type RoomVersion } from '@hs/room'; | |
| import { type EventID, type RoomVersion, eventIdSchema } from '@hs/room'; | |
| ... | |
| eventIdSchema.array().parse(body.earliest_events), | |
| eventIdSchema.array().parse(body.latest_events), |
🤖 Prompt for AI Agents
In packages/homeserver/src/controllers/federation/profiles.controller.ts (fix
around the import at top and the usage at lines ~106-107), remove any deep
imports from 'packages/room/dist' and import the public schema/export from
'@hs/room' instead; replace unsafe "as EventID[]" casts by validating/parsing
incoming values with eventIdSchema.array().parse(...) (import eventIdSchema from
'@hs/room'), and use the parsed EventID[] result for downstream logic; ensure
types still reference EventID/RoomVersion from '@hs/room' only and propagate
parse errors appropriately (throw/return a 4xx) at the API boundary.
| @@ -1,4 +1,5 @@ | |||
| import { ConfigService, EventService } from '@hs/federation-sdk'; | |||
| import { EventID } from '@hs/room'; | |||
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.
🛠️ Refactor suggestion
Import eventIdSchema (not just EventID) for boundary validation.
Apply:
-import { EventID } from '@hs/room';
+import { EventID, eventIdSchema } from '@hs/room';📝 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.
| import { EventID } from '@hs/room'; | |
| import { EventID, eventIdSchema } from '@hs/room'; |
🤖 Prompt for AI Agents
In packages/homeserver/src/controllers/federation/transactions.controller.ts
around line 2, the current import only pulls EventID from '@hs/room' but the
file needs eventIdSchema for boundary validation; update the import to include
eventIdSchema (e.g., import { EventID, eventIdSchema } from '@hs/room') and then
use eventIdSchema where incoming event IDs are validated so boundary validation
uses the canonical schema.
| const eventData = await eventService.getEventById( | ||
| params.eventId as 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.
Do not cast params.eventId; validate and brand it.
Unsafe cast can pass invalid IDs into the service. Validate with eventIdSchema and return 400 on failure.
Apply:
- const eventData = await eventService.getEventById(
- params.eventId as EventID,
- );
+ const parsed = eventIdSchema.safeParse(params.eventId);
+ if (!parsed.success) {
+ set.status = 400;
+ return { errcode: 'M_INVALID_PARAM', error: 'Invalid event ID' };
+ }
+ const eventData = await eventService.getEventById(parsed.data);📝 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.
| const eventData = await eventService.getEventById( | |
| params.eventId as EventID, | |
| ); | |
| const parsed = eventIdSchema.safeParse(params.eventId); | |
| if (!parsed.success) { | |
| set.status = 400; | |
| return { errcode: 'M_INVALID_PARAM', error: 'Invalid event ID' }; | |
| } | |
| const eventData = await eventService.getEventById(parsed.data); |
🤖 Prompt for AI Agents
In packages/homeserver/src/controllers/federation/transactions.controller.ts
around lines 47 to 49, do not cast params.eventId; instead validate it using
eventIdSchema and, on success, use the branded value as EventID when calling
eventService.getEventById; if validation fails return a 400 response (with an
appropriate error message) and do not call the service. Ensure you replace the
unsafe cast with the validated/branched value and keep error handling consistent
with other controller validations.
| export interface EventStore { | ||
| getEvents(eventIds: string[]): Promise<PersistentEventBase[]>; | ||
| getEvents(eventIds: EventID[]): Promise<PersistentEventBase[]>; | ||
| } |
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.
🛠️ Refactor suggestion
🧩 Analysis chain
API shift acknowledged: EventStore.getEvents now takes EventID[].
This aligns the state resolution APIs with branded IDs.
Run to locate remaining string[] signatures:
🏁 Script executed:
#!/bin/bash
rg -nP --type=ts -C2 '\bgetEvents\s*\(\s*eventIds\s*:\s*string\[\]'Length of output: 1076
Update remaining test mocks: change getEvents(eventIds: string[]) → EventID[]
Two test mocks still declare getEvents with string[] — update their signatures and any related Maps/types to EventID to match the EventStore API.
- packages/room/src/authorizartion-rules/rules.spec.ts — async getEvents(eventIds: string[]): Promise<PersistentEventBase[]> (line ~16)
- packages/room/src/state_resolution/definitions/algorithm/v2.spec.ts — async getEvents(eventIds: string[]): Promise<PersistentEventBase[]> (line ~17)
Example change: async getEvents(eventIds: EventID[]): Promise<PersistentEventBase[]> { ... } (also update Map<string, ...> → Map<EventID, ...> where applicable).
🤖 Prompt for AI Agents
packages/room/src/state_resolution/definitions/definitions.ts lines 83-85:
Update test mocks in the two referenced spec files to match the EventStore
interface by changing getEvents parameter types from string[] to EventID[] and
any related Maps/keys to use EventID instead of string; specifically edit
packages/room/src/authorizartion-rules/rules.spec.ts (around line ~16) and
packages/room/src/state_resolution/definitions/algorithm/v2.spec.ts (around line
~17) to declare async getEvents(eventIds: EventID[]):
Promise<PersistentEventBase[]> { ... } and change Map<string, ...> →
Map<EventID, ...> or other types/looksups that use string keys so all signatures
and usages align with 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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/federation-sdk/src/services/state.service.ts (1)
376-379: Tighten internal cache/key types to EventID.Minor type hygiene: cache and local arrays can use EventID/PersistentEventBase to avoid any[] widening.
- const cache = new Map<string, PersistentEventBase>(); + const cache = new Map<EventID, PersistentEventBase>(); return { - getEvents: async (eventIds: EventID[]): Promise<PersistentEventBase[]> => { - const events = []; - const toFind = []; + getEvents: async (eventIds: EventID[]): Promise<PersistentEventBase[]> => { + const events: PersistentEventBase[] = []; + const toFind: EventID[] = [];
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
packages/federation-sdk/src/services/staging-area.service.ts(3 hunks)packages/federation-sdk/src/services/state.service.ts(7 hunks)packages/room/src/manager/event-wrapper.ts(2 hunks)packages/room/src/manager/v3.ts(4 hunks)packages/room/src/types/_common.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/room/src/manager/event-wrapper.ts
- packages/room/src/manager/v3.ts
- packages/room/src/types/_common.ts
🧰 Additional context used
🧬 Code graph analysis (2)
packages/federation-sdk/src/services/state.service.ts (4)
packages/room/src/manager/v3.ts (1)
eventId(22-34)packages/room/src/types/_common.ts (2)
EventID(8-8)StateMapKey(10-10)packages/room/src/manager/room-state.ts (1)
RoomState(15-154)packages/room/src/manager/event-wrapper.ts (1)
event(102-112)
packages/federation-sdk/src/services/staging-area.service.ts (1)
packages/room/src/types/_common.ts (1)
EventID(8-8)
🔇 Additional comments (9)
packages/federation-sdk/src/services/staging-area.service.ts (3)
6-6: Type-only import is correct.Importing EventID as a type avoids runtime impact and matches the PR goal.
171-175: Reaction 'm.relates_to.event_id' changed to EventID — verify consumers expecting stringFile: packages/federation-sdk/src/services/staging-area.service.ts (lines 171–175)
Repo search returned no matches for consumers typed as string. Absence of matches is not proof — manually verify external/third-party callers, serialization/deserialization paths, and any runtime code casting or treating event_id as string.
151-154: Annotate m.relates_to.event_id as EventID — verify downstream consumers.Location: packages/federation-sdk/src/services/staging-area.service.ts (lines 151–154). Typing event_id as EventID tightens the emitter payload; automated search produced no matches for consumers declaring event_id: string, so manual verification is required. Confirm all downstream consumers/handlers of homeserver.matrix.message and any processors of m.relates_to accept EventID or update their types.
packages/federation-sdk/src/services/state.service.ts (6)
3-3: EventID import at source — aligned with branding.Consistent with room’s branded ID schema.
271-273: Param now Map<StateMapKey, EventID> — consistent with the previous change.
348-351: getFullRoomStateBeforeEvent2(eventId: EventID) — API consistency looks good.
776-779: Passing EventID[] to store.getEvents — correct.Matches the new store signature; no runtime impact.
118-121: findStateAtEvent now takes EventID — verify callers pass an EventID
- Call sites found:
- packages/homeserver/src/controllers/internal/room.controller.ts:192 — passes
eventId as EventID(OK).- packages/federation-sdk/src/services/state.service.ts:349 — internal call with
eventId: EventID(OK).- packages/federation-sdk/src/services/state.service.ts:631 — calls
this.findStateAtEvent(lastEvent._id, 'always')— CONFIRMlastEvent._idis an EventID (not a DB _id); if not, use the event's EventID field or cast.- packages/federation-sdk/src/services/event.service.ts:696 and 755 — pass
eventId— VERIFY the originating variable is typed as EventID.- Action: confirm types at the listed locations and update any caller that passes a DB id or wrong type to an EventID (or add an explicit cast).
254-258: Return type is correct — no caller changes required.
buildFullRoomStateFromEvents is only invoked inside packages/federation-sdk/src/services/state.service.ts and its callers (buildFullRoomStateFromStateMapping, buildFullRoomStateFromStateMappings, buildFullRoomStateStoredEvents) already use Map<StateMapKey, EventID>.
Summary by CodeRabbit