feat: send push notifications for voice calls#39386
feat: send push notifications for voice calls#39386pierre-lehnen-rc wants to merge 19 commits intodevelopfrom
Conversation
|
Looks like this PR is not ready to merge, because of the following issues:
Please fix the issues and try again If you have any trouble, please check the PR guidelines |
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds VoIP push support and wiring: voipToken and pushTokenTypes added to typings/models, push sending updated to support VoIP tokens and retry caps, token removal switched to string-based APIs, and media-call components emit and handle VoIP push notifications. Changes
Sequence DiagramsequenceDiagram
participant Caller
participant MediaCallServer
participant PushService
participant PushTokenDB
participant Gateway
Caller->>MediaCallServer: create/accept/end call (callId)
MediaCallServer->>MediaCallServer: emit pushNotificationRequest(callId, event)
MediaCallServer->>PushService: sendPushNotification(callId, event)
PushService->>PushTokenDB: findAllTokensByUserId / findTokensByUserIdExceptId(userId, skipTokenId)
PushTokenDB-->>PushService: tokens (may include voipToken)
PushService->>PushService: set retryOptions (tries/maxRetries = useVoipToken ? 1 : MAX)
alt useVoipToken & voipToken present
PushService->>Gateway: send APN VoIP (expiry 60s, pushType='voip')
else standard token
PushService->>Gateway: send APN/FCM with retries/backoff
end
Gateway-->>PushService: delivery result / error
PushService->>PushTokenDB: removeOrUnsetByTokenString(token) on invalid token
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #39386 +/- ##
===========================================
- Coverage 70.92% 70.87% -0.05%
===========================================
Files 3196 3200 +4
Lines 113332 113411 +79
Branches 20532 20583 +51
===========================================
+ Hits 80376 80380 +4
- Misses 30912 30976 +64
- Partials 2044 2055 +11
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
04c0d47 to
1a94148
Compare
1a94148 to
0eaeee8
Compare
7a63dfd to
d990aca
Compare
There was a problem hiding this comment.
6 issues found across 20 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/meteor/app/push/server/definition.ts">
<violation number="1" location="apps/meteor/app/push/server/definition.ts:45">
P1: Strip `useVoipToken` before building the gateway payload, otherwise VoIP notifications can start sending an unexpected field to the push gateway.</violation>
</file>
<file name="ee/packages/media-calls/src/definition/IMediaCallServer.ts">
<violation number="1" location="ee/packages/media-calls/src/definition/IMediaCallServer.ts:7">
P3: Remove this unused duplicate type alias; the same `VoipPushNotificationType` union already exists in `getPushNotificationType.ts`.
(Based on your team's feedback about removing unused types and configuration entries.) [FEEDBACK_USED]</violation>
</file>
<file name="apps/meteor/app/push/server/apn.ts">
<violation number="1" location="apps/meteor/app/push/server/apn.ts:98">
P1: Avoid removing the whole push-token record when a VoIP token fails. Here `userToken` can be `app.voipToken`, and `removeAllByTokenString()` will delete the document that also stores the regular APN token.
(Based on your team's feedback about keeping VoIP tokens distinct from the paired regular token lifecycle.) [FEEDBACK_USED]</violation>
</file>
<file name="apps/meteor/server/services/media-call/service.ts">
<violation number="1" location="apps/meteor/server/services/media-call/service.ts:30">
P2: Handle rejections from `sendVoipPushNotification` here; this async emitter callback currently leaves push-send failures as unhandled promise rejections.</violation>
</file>
<file name="apps/meteor/server/services/push/tokenManagement/registerPushToken.ts">
<violation number="1" location="apps/meteor/server/services/push/tokenManagement/registerPushToken.ts:63">
P1: Regular token refreshes should update an existing paired push-token record and clear `voipToken`; this branch inserts a replacement record instead, and duplicate cleanup deletes the original device `_id`, breaking later VoIP updates.
(Based on your team's feedback about regular push refreshes needing to unset stale VoIP tokens instead of replacing the device record.) [FEEDBACK_USED]</violation>
</file>
<file name="apps/meteor/app/push/server/push.ts">
<violation number="1" location="apps/meteor/app/push/server/push.ts:189">
P2: Only increment `countApn` after confirming there is a token to send to; otherwise VoIP notifications with no `voipToken` are reported as delivered even though nothing was sent.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
ee/packages/media-calls/src/server/CallDirector.ts (1)
218-219: Remove the inline rationale comment.Line 218 adds an implementation comment. Please keep the rationale in the PR/ADR and leave the assignment self-explanatory in code.
As per coding guidelines, "Avoid code comments in the implementation".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ee/packages/media-calls/src/server/CallDirector.ts` around lines 218 - 219, Remove the inline rationale comment preceding the _id assignment in CallDirector (the line with "_id: randomUUID()"); simply leave the assignment self-explanatory by deleting the comment text so the code reads only the property assignment. Ensure you only remove the comment and do not alter the _id: randomUUID() expression or surrounding logic.apps/meteor/server/services/media-call/push/getPushNotificationType.ts (1)
10-12: Consider edge case:hangupReason === 'rejected'withoutendedBy.The check at line 10 uses
ORlogic:call.endedBy?.id === call.callee.id || call.hangupReason === 'rejected'. IfhangupReasonis'rejected'butendedByis not the callee (e.g., server-initiated rejection), this would still return'declinedElsewhere'. Verify this matches the intended behavior.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/server/services/media-call/push/getPushNotificationType.ts` around lines 10 - 12, The current condition in getPushNotificationType uses OR for call.endedBy?.id === call.callee.id || call.hangupReason === 'rejected', which will classify server-initiated 'rejected' hangups as 'declinedElsewhere'; change the logic so 'rejected' only counts when the callee actually ended the call. Update the condition around call.endedBy, call.callee.id and call.hangupReason so that you require endedBy?.id === call.callee.id (or require call.hangupReason === 'rejected' AND endedBy?.id === call.callee.id) instead of the current OR expression.apps/meteor/server/services/push/tokenManagement/registerPushToken.ts (1)
26-41: VoIP token silently dropped when_idis missing.On line 34,
voipTokenis only included in the insert ifdata._idis present:...(data.voipToken && data._id && { voipToken: data.voipToken }). While the API layer validates this (requiringidwhenvoipTokenis provided), ifregisterPushTokenis called from another code path without this validation, thevoipTokenwould be silently ignored.Consider adding a debug log or defensive check here to make the behavior more explicit.
Optional: Add defensive logging
async function insertToken(data: PushTokenData): Promise<IPushToken['_id']> { + if (data.voipToken && !data._id) { + logger.warn({ msg: 'voipToken provided without _id, voipToken will not be stored' }); + } + const insertResult = await PushToken.insertToken({ ...(data._id && { _id: data._id }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/server/services/push/tokenManagement/registerPushToken.ts` around lines 26 - 41, The insertToken function is currently dropping voipToken when data._id is missing because of the conditional ...(data.voipToken && data._id && { voipToken: data.voipToken }); modify insertToken (and the call to PushToken.insertToken) to explicitly handle the case where data.voipToken is present but data._id is missing: either add a defensive logger warning via logger.warn or throw an Error when data.voipToken && !data._id, so callers are alerted, and then keep the existing insert behavior (include voipToken only when _id exists); reference insertToken, PushToken.insertToken, data.voipToken and data._id when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/meteor/app/api/server/v1/push.ts`:
- Around line 149-151: The response schema's voipToken property must allow
null/absent values: update the response schema where voipToken is declared (the
voipToken property in the push token response schema) to include nullable: true
(or mark it optional/null depending on your schema library) so validation
accepts undefined/null values returned from storage; keep the key name voipToken
and ensure any TypeScript type/interfaces that mirror this schema also allow
string | null | undefined.
In `@apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts`:
- Around line 13-24: The projection in getActorUser does not include
freeSwitchExtension but the generic T and later code expect it; update the
options projection object used by Users.findOneById and
Users.findOneByFreeSwitchExtension in getActorUser to include
freeSwitchExtension (e.g. add freeSwitchExtension: 1) so the returned user
satisfies T and user.freeSwitchExtension is available.
In `@apps/meteor/server/services/push/tokenManagement/findDocumentToUpdate.ts`:
- Around line 12-15: The early return in findDocumentToUpdate when
data.voipToken is present forces VoIP payloads into the insert path; change the
guard so it only short-circuits for VoIP-only updates. Concretely, in
findDocumentToUpdate update the condition from "if (data.voipToken) return null"
to only return null when the incoming payload contains voipToken but does NOT
contain any identifying main-token fields (e.g., no data.token, no data.appName,
and no data._id), so that mixed APN+VoIP payloads (token+appName+voipToken) will
fall through and match/update the existing document used by registerPushToken
instead of inserting a new one.
---
Nitpick comments:
In `@apps/meteor/server/services/media-call/push/getPushNotificationType.ts`:
- Around line 10-12: The current condition in getPushNotificationType uses OR
for call.endedBy?.id === call.callee.id || call.hangupReason === 'rejected',
which will classify server-initiated 'rejected' hangups as 'declinedElsewhere';
change the logic so 'rejected' only counts when the callee actually ended the
call. Update the condition around call.endedBy, call.callee.id and
call.hangupReason so that you require endedBy?.id === call.callee.id (or require
call.hangupReason === 'rejected' AND endedBy?.id === call.callee.id) instead of
the current OR expression.
In `@apps/meteor/server/services/push/tokenManagement/registerPushToken.ts`:
- Around line 26-41: The insertToken function is currently dropping voipToken
when data._id is missing because of the conditional ...(data.voipToken &&
data._id && { voipToken: data.voipToken }); modify insertToken (and the call to
PushToken.insertToken) to explicitly handle the case where data.voipToken is
present but data._id is missing: either add a defensive logger warning via
logger.warn or throw an Error when data.voipToken && !data._id, so callers are
alerted, and then keep the existing insert behavior (include voipToken only when
_id exists); reference insertToken, PushToken.insertToken, data.voipToken and
data._id when making the change.
In `@ee/packages/media-calls/src/server/CallDirector.ts`:
- Around line 218-219: Remove the inline rationale comment preceding the _id
assignment in CallDirector (the line with "_id: randomUUID()"); simply leave the
assignment self-explanatory by deleting the comment text so the code reads only
the property assignment. Ensure you only remove the comment and do not alter the
_id: randomUUID() expression or surrounding logic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c94fd886-f6f9-491d-9cd5-b6049d59b307
📒 Files selected for processing (20)
apps/meteor/app/api/server/v1/push.tsapps/meteor/app/push/server/apn.tsapps/meteor/app/push/server/definition.tsapps/meteor/app/push/server/fcm.tsapps/meteor/app/push/server/push.tsapps/meteor/server/services/media-call/logger.tsapps/meteor/server/services/media-call/push/getPushNotificationType.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tsapps/meteor/server/services/media-call/service.tsapps/meteor/server/services/push/service.tsapps/meteor/server/services/push/tokenManagement/findDocumentToUpdate.tsapps/meteor/server/services/push/tokenManagement/registerPushToken.tsee/packages/media-calls/src/definition/IMediaCallServer.tsee/packages/media-calls/src/internal/agents/UserActorAgent.tsee/packages/media-calls/src/server/CallDirector.tsee/packages/media-calls/src/server/MediaCallServer.tspackages/core-typings/src/IPushNotificationConfig.tspackages/core-typings/src/IPushToken.tspackages/model-typings/src/models/IPushTokenModel.tspackages/models/src/models/PushToken.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
apps/meteor/server/services/media-call/push/getPushNotificationType.tspackages/core-typings/src/IPushNotificationConfig.tsee/packages/media-calls/src/definition/IMediaCallServer.tsapps/meteor/server/services/push/tokenManagement/findDocumentToUpdate.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tspackages/core-typings/src/IPushToken.tsapps/meteor/server/services/media-call/logger.tsee/packages/media-calls/src/server/CallDirector.tsee/packages/media-calls/src/internal/agents/UserActorAgent.tsapps/meteor/app/push/server/apn.tsapps/meteor/server/services/push/service.tsapps/meteor/app/push/server/fcm.tsapps/meteor/app/push/server/definition.tsapps/meteor/server/services/push/tokenManagement/registerPushToken.tsapps/meteor/server/services/media-call/service.tspackages/model-typings/src/models/IPushTokenModel.tspackages/models/src/models/PushToken.tsee/packages/media-calls/src/server/MediaCallServer.tsapps/meteor/app/api/server/v1/push.tsapps/meteor/app/push/server/push.ts
🧠 Learnings (16)
📓 Common learnings
Learnt from: pierre-lehnen-rc
Repo: RocketChat/Rocket.Chat PR: 39174
File: apps/meteor/server/services/push/tokenManagement/registerPushToken.ts:47-49
Timestamp: 2026-03-02T16:21:44.002Z
Learning: In the Rocket.Chat push token system (apps/meteor/server/services/push/tokenManagement/registerPushToken.ts), the main (non-VoIP) token is responsible for keeping authToken, appName, and userId updated. VoIP tokens are supplementary—when a device already has a non-VoIP token registered, VoIP token updates only modify the voipToken field, delegating metadata management to the main token registration flow.
📚 Learning: 2026-03-02T16:21:44.002Z
Learnt from: pierre-lehnen-rc
Repo: RocketChat/Rocket.Chat PR: 39174
File: apps/meteor/server/services/push/tokenManagement/registerPushToken.ts:47-49
Timestamp: 2026-03-02T16:21:44.002Z
Learning: In the Rocket.Chat push token system (apps/meteor/server/services/push/tokenManagement/registerPushToken.ts), the main (non-VoIP) token is responsible for keeping authToken, appName, and userId updated. VoIP tokens are supplementary—when a device already has a non-VoIP token registered, VoIP token updates only modify the voipToken field, delegating metadata management to the main token registration flow.
Applied to files:
apps/meteor/server/services/media-call/push/getPushNotificationType.tspackages/core-typings/src/IPushNotificationConfig.tsapps/meteor/server/services/push/tokenManagement/findDocumentToUpdate.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tspackages/core-typings/src/IPushToken.tsapps/meteor/app/push/server/apn.tsapps/meteor/server/services/push/service.tsapps/meteor/app/push/server/fcm.tsapps/meteor/app/push/server/definition.tsapps/meteor/server/services/push/tokenManagement/registerPushToken.tspackages/model-typings/src/models/IPushTokenModel.tspackages/models/src/models/PushToken.tsapps/meteor/app/api/server/v1/push.tsapps/meteor/app/push/server/push.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.
Applied to files:
apps/meteor/server/services/media-call/push/getPushNotificationType.tspackages/core-typings/src/IPushNotificationConfig.tsee/packages/media-calls/src/definition/IMediaCallServer.tsapps/meteor/server/services/push/tokenManagement/findDocumentToUpdate.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tspackages/core-typings/src/IPushToken.tsapps/meteor/server/services/media-call/logger.tsee/packages/media-calls/src/server/CallDirector.tsee/packages/media-calls/src/internal/agents/UserActorAgent.tsapps/meteor/app/push/server/apn.tsapps/meteor/server/services/push/service.tsapps/meteor/app/push/server/fcm.tsapps/meteor/app/push/server/definition.tsapps/meteor/server/services/push/tokenManagement/registerPushToken.tsapps/meteor/server/services/media-call/service.tspackages/model-typings/src/models/IPushTokenModel.tspackages/models/src/models/PushToken.tsee/packages/media-calls/src/server/MediaCallServer.tsapps/meteor/app/api/server/v1/push.tsapps/meteor/app/push/server/push.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.
Applied to files:
apps/meteor/server/services/media-call/push/getPushNotificationType.tspackages/core-typings/src/IPushNotificationConfig.tsee/packages/media-calls/src/definition/IMediaCallServer.tsapps/meteor/server/services/push/tokenManagement/findDocumentToUpdate.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tspackages/core-typings/src/IPushToken.tsapps/meteor/server/services/media-call/logger.tsee/packages/media-calls/src/server/CallDirector.tsee/packages/media-calls/src/internal/agents/UserActorAgent.tsapps/meteor/app/push/server/apn.tsapps/meteor/server/services/push/service.tsapps/meteor/app/push/server/fcm.tsapps/meteor/app/push/server/definition.tsapps/meteor/server/services/push/tokenManagement/registerPushToken.tsapps/meteor/server/services/media-call/service.tspackages/model-typings/src/models/IPushTokenModel.tspackages/models/src/models/PushToken.tsee/packages/media-calls/src/server/MediaCallServer.tsapps/meteor/app/api/server/v1/push.tsapps/meteor/app/push/server/push.ts
📚 Learning: 2025-11-17T14:30:36.271Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 37491
File: packages/desktop-api/src/index.ts:17-27
Timestamp: 2025-11-17T14:30:36.271Z
Learning: In the Rocket.Chat desktop API (`packages/desktop-api/src/index.ts`), the `CustomNotificationOptions` type has an optional `id` field by design. Custom notifications dispatched without an ID cannot be closed programmatically using `closeCustomNotification`, and this is intentional.
Applied to files:
packages/core-typings/src/IPushNotificationConfig.tsapps/meteor/app/push/server/push.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.tsapps/meteor/server/services/media-call/logger.tsee/packages/media-calls/src/server/CallDirector.tsee/packages/media-calls/src/internal/agents/UserActorAgent.tsapps/meteor/server/services/media-call/service.ts
📚 Learning: 2026-02-20T09:04:55.725Z
Learnt from: Shreyas2004wagh
Repo: RocketChat/Rocket.Chat PR: 38681
File: apps/meteor/server/modules/streamer/streamer.module.ts:307-313
Timestamp: 2026-02-20T09:04:55.725Z
Learning: In apps/meteor/server/modules/streamer/streamer.module.ts, the catch block in sendToManySubscriptions intentionally uses SystemLogger.debug (not error or warn) for per-subscription delivery failures to keep logs less noisy, as this was a deliberate design choice reviewed and approved by KevLehman.
Applied to files:
apps/meteor/server/services/media-call/logger.tsapps/meteor/server/services/media-call/service.ts
📚 Learning: 2025-12-18T15:18:31.688Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37773
File: apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx:24-34
Timestamp: 2025-12-18T15:18:31.688Z
Learning: In apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx, for internal call history items, the item.contactId is guaranteed to always match either the caller.id or callee.id in the call data, so the contact resolution in getContact will never result in undefined.
Applied to files:
ee/packages/media-calls/src/server/CallDirector.tsapps/meteor/server/services/media-call/service.tsee/packages/media-calls/src/server/MediaCallServer.ts
📚 Learning: 2026-02-26T19:22:36.646Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.tsx:40-40
Timestamp: 2026-02-26T19:22:36.646Z
Learning: In packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.tsx, when the media session state is 'unavailable', the voiceCall action is not included in the actions object passed to CallHistoryActions, so it won't appear in the menu at all. The action filtering happens upstream before getItems is called, preventing any tooltip confusion for the unavailable state.
Applied to files:
ee/packages/media-calls/src/internal/agents/UserActorAgent.tsapps/meteor/server/services/media-call/service.tsee/packages/media-calls/src/server/MediaCallServer.ts
📚 Learning: 2026-02-24T19:09:09.561Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
Applied to files:
apps/meteor/app/push/server/apn.tsapps/meteor/server/services/push/service.ts
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.
Applied to files:
apps/meteor/server/services/push/service.tsapps/meteor/app/push/server/fcm.tsapps/meteor/app/push/server/definition.ts
📚 Learning: 2025-09-30T13:00:05.465Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 36990
File: apps/meteor/ee/server/apps/storage/AppRealStorage.ts:55-58
Timestamp: 2025-09-30T13:00:05.465Z
Learning: In AppRealStorage (apps/meteor/ee/server/apps/storage/AppRealStorage.ts), the `remove` method is designed to be idempotent and returns `{ success: true }` unconditionally because the goal is to ensure the app is removed, not to distinguish whether this specific call performed the deletion. Database errors will throw exceptions.
Applied to files:
apps/meteor/server/services/push/service.tspackages/models/src/models/PushToken.ts
📚 Learning: 2026-02-25T20:10:16.987Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38913
File: packages/ddp-client/src/legacy/types/SDKLegacy.ts:34-34
Timestamp: 2026-02-25T20:10:16.987Z
Learning: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor (e.g., declare module 'rocket.chat/rest-typings') are not visible when compiling packages/ddp-client in isolation, which is why legacy SDK methods that depend on OperationResult types for OpenAPI-migrated endpoints must remain commented out.
Applied to files:
packages/model-typings/src/models/IPushTokenModel.tspackages/models/src/models/PushToken.tsapps/meteor/app/api/server/v1/push.ts
📚 Learning: 2026-03-09T18:39:14.020Z
Learnt from: Harxhit
Repo: RocketChat/Rocket.Chat PR: 39476
File: apps/meteor/server/methods/addAllUserToRoom.ts:0-0
Timestamp: 2026-03-09T18:39:14.020Z
Learning: In apps/meteor/server/methods/addAllUserToRoom.ts, the implementation uses a single cursor pass (Users.find(userFilter).batchSize(100)) that collects both the full user objects (collectedUsers: IUser[]) and their usernames (usernames: string[]) in one iteration. `beforeAddUserToRoom` is then called once with the full usernames batch (preserving batch-validation semantics), and the subsequent subscription/message processing loop iterates over the same stable `collectedUsers` array — no second DB query is made. This avoids any race condition between validation and processing while preserving the original batch-validation behavior.
Applied to files:
packages/models/src/models/PushToken.ts
📚 Learning: 2026-02-23T17:53:06.802Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:06.802Z
Learning: During PR reviews that touch endpoint files under apps/meteor/app/api/server/v1, enforce strict scope: if a PR targets a specific endpoint (e.g., rooms.favorite), do not propose changes to unrelated endpoints (e.g., rooms.invite) unless maintainers explicitly request them. Focus feedback on the touched endpoint's behavior, API surface, and related tests; avoid broad cross-endpoint changes in the same PR unless requested.
Applied to files:
apps/meteor/app/api/server/v1/push.ts
📚 Learning: 2026-02-24T19:09:01.522Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:01.522Z
Learning: In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior; style-only cleanups (e.g., removing inline comments) may be deferred to follow-ups to keep the migration PR focused.
Applied to files:
apps/meteor/app/api/server/v1/push.ts
🔇 Additional comments (27)
apps/meteor/app/push/server/fcm.ts (3)
11-15: LGTM! Optional notification fields support VoIP use cases.Making
titleandbodyoptional inFCMNotificationFieldcorrectly aligns with the broader push notification changes where VoIP notifications may not include visible notification content.
142-154: LGTM! Conditional notification field construction is correct.The conditional spread pattern at lines 143-144 ensures
titleandbodyare only included when present, and line 149 correctly omits thenotificationfield entirely when empty. This allows data-only FCM messages for VoIP.
186-189: LGTM! Token removal simplified to use string directly.The change to pass
tokendirectly to_removeTokenaligns with the updatedPushToken.removeAllByTokenStringAPI that accepts a raw token string instead of an object structure.apps/meteor/server/services/media-call/service.ts (2)
16-17: LGTM! Clean import structure for VoIP push integration.The imports correctly bring in the module-scoped logger and the new
sendVoipPushNotificationhandler.
30-30: LGTM! Event wiring for VoIP push notifications follows established patterns.The
pushNotificationRequestevent listener correctly delegates tosendVoipPushNotification, following the same pattern as the existingsignalRequest,callUpdated, andhistoryUpdatehandlers.apps/meteor/server/services/push/service.ts (1)
39-44: LGTM! Duplicate token removal parameters align with updated token management API.The
removeDuplicateTokenscall correctly passes the required fields (_id,token,appName,authToken) for identifying and removing duplicate tokens while preserving the newly registered token.ee/packages/media-calls/src/internal/agents/UserActorAgent.ts (3)
54-64: LGTM! End notification correctly gated for callee role.The
'end'push notification is appropriately sent only for the callee role before sending the hangup signal, allowing the callee's device to handle call termination.
74-85: LGTM! New call notification correctly follows signal dispatch.The
'new'push notification is sent aftersendSignal(buildNewCallSignal(...)), which is the correct order—the signal goes first to online clients, then the push notification serves as a backup to wake offline devices.
24-52: Push notification timing is intentional and correctly designed.The
onCallAcceptedmethod is explicitly documented inIMediaCallAgent.tsas being "called when the call was accepted, even if the webrtc negotiation is pending." The early return when the offer is unavailable (lines 38-42) is by design—it allows the 'answer' push event to signal call acceptance independently of WebRTC negotiation readiness, which is handled separately viaonRemoteDescriptionChangedwhen the SDP becomes available. No changes needed.> Likely an incorrect or invalid review comment.apps/meteor/app/push/server/definition.ts (1)
20-46: LGTM! Type changes enable VoIP-specific push notification flows.Making
from,title, andtextoptional correctly supports VoIP push notifications that may be data-only. The newuseVoipTokenfield enables routing to the dedicated VoIP push token. The context snippets confirm thatpush.ts,apn.ts, andfcm.tsall handle these optional fields with appropriate conditional checks.ee/packages/media-calls/src/server/MediaCallServer.ts (2)
9-14: LGTM! Import correctly expanded for VoIP push notification types.The import now includes
VoipPushNotificationEventTypewhich is used in the newsendPushNotificationmethod signature.
78-82: LGTM! Push notification method follows established patterns.The
sendPushNotificationmethod correctly follows the same pattern assendSignal,reportCallUpdate, andupdateCallHistory—logging debug information and emitting an event for the service layer to handle.apps/meteor/app/push/server/apn.ts (3)
37-42: LGTM! VoIP-specific APN configuration is correct.The 60-second expiry for VoIP notifications is appropriate for time-sensitive call alerts, and
pushType: 'voip'is the correct setting for iOS VoIP push notifications via PushKit.
59-79: LGTM! Conditional field assignments handle optional values correctly.Each field (
category,body,title,from) is now guarded with an existence check before assignment, preventing undefined values from being set on the APN notification object.
27-27: LGTM! Token removal callback simplified to accept string directly.The
_removeTokensignature change to accept a plain string aligns with the updatedPushToken.removeAllByTokenStringAPI used by the caller inpush.ts.Also applies to: 98-98
apps/meteor/server/services/media-call/push/getPushNotificationType.ts (1)
5-23: No actionable changes needed. The function correctly handles the'answeredElsewhere'notification type through an early return guard in the consuming function (sendVoipPushNotification.ts, line 69): whencall.acceptedAtis set, notifications are only sent for the'answer'event, not for subsequent'end'events. The'answeredElsewhere'type is therefore only returned when appropriate—to notify other devices that a call was answered—and the concern about notifying the device that completed the call is prevented by the guard condition upstream.apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts (2)
85-103: LGTM!The notification payload structure is well-designed with appropriate fields for VoIP call notifications. The conditional
skipTokenIdusingcontractIdcorrectly prevents sending state-change notifications to the device that already handled the call.
56-80: LGTM!The early return logic correctly handles edge cases: skipping notifications for already-accepted calls (except 'answer' events), and ensuring state consistency between event types and notification types.
apps/meteor/server/services/push/tokenManagement/registerPushToken.ts (2)
12-24: LGTM!The
canModifyTokenDocumentlogic correctly ensures VoIP tokens can only be modified via explicit_idmatch, preventing accidental overwrites. This aligns with the design where VoIP tokens are supplementary to the main token. Based on learnings: "VoIP tokens are supplementary—when a device already has a non-VoIP token registered, VoIP token updates only modify the voipToken field, delegating metadata management to the main token registration flow."
60-68: LGTM!The refactored
registerPushTokenfunction cleanly orchestrates the token registration flow with proper separation of concerns between finding, inserting, and updating tokens.apps/meteor/app/api/server/v1/push.ts (2)
166-170: LGTM!Good defensive validation ensuring
voipTokencannot be registered without a deviceid. This prevents the silent token drop issue in the downstream registration logic.
24-30: LGTM!Good refactoring to use shared
IPushTokenTypesandpushTokenTypesfrom core-typings, ensuring consistency across the codebase. ThecleanTokenResultfunction properly sanitizes the response.Also applies to: 80-97
apps/meteor/app/push/server/push.ts (5)
331-346: LGTM!The VoIP-specific retry limit (
maxTries: 1for VoIP vsPUSH_GATEWAY_MAX_ATTEMPTSfor regular notifications) is a sensible design choice. VoIP notifications are time-sensitive, so avoiding extended retries prevents stale call notifications. The token existence check on line 343 properly handles cases where a VoIP token may not be registered.
356-384: LGTM!The
skipTokenIdoption is well-implemented, allowing VoIP notifications to exclude the device that already handled the call action. The conditional betweenfindTokensByUserIdExceptIdandfindAllTokensByUserIdcleanly handles both cases.
429-454: LGTM!The validation schema changes correctly accommodate VoIP notifications which may not have
from,title, ortextfields. The addition ofuseVoipTokenvalidation ensures type safety.
188-196: LGTM!The APN notification path correctly handles VoIP tokens: selecting the appropriate token based on
useVoipToken, setting the topic suffix to.voipfor VoIP notifications, and properly guarding against missing tokens before sending.
170-174: LGTM!The
removeTokenmethod signature change to accept a token string directly simplifies the interface and aligns with how it's called from APN/FCM error handlers. The error handling with logging prevents unhandled promise rejections.
apps/meteor/server/services/push/tokenManagement/findDocumentToUpdate.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts (1)
13-22:⚠️ Potential issue | 🟡 MinorInclude
freeSwitchExtensionin the actor projection.Line 45 falls back to
user.freeSwitchExtension, but the projection on Line 16 only fetchesnameandusername. For SIP actors that makes the last user-based fallback alwaysundefined.🩹 Proposed fix
- const options = { projection: { name: 1, username: 1 } }; + const options = { projection: { name: 1, username: 1, freeSwitchExtension: 1 } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts` around lines 13 - 22, The projection for getActorUser currently only requests name and username, but later code expects freeSwitchExtension (causing SIP actors to get undefined); update the projection object in getActorUser (used by Users.findOneById and Users.findOneByFreeSwitchExtension) to include freeSwitchExtension so the returned user documents contain that field for the SIP fallback logic to work correctly.
🧹 Nitpick comments (3)
apps/meteor/app/push/server/push.ts (1)
310-317: Make the gateway payload mapping explicit.This subtractive spread forwards every future
PendingPushNotificationfield unless someone remembers to keep the omit list in sync. That's brittle at an external API boundary. Prefer an explicit mapper orpick()list and the new inline comment goes away too.As per coding guidelines, "Avoid code comments in the implementation".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/app/push/server/push.ts` around lines 310 - 317, The current getGatewayNotificationData function uses a subtractive spread on PendingPushNotification (via destructuring priority/useVoipToken) which will silently forward any future fields to the gateway; replace this brittle approach with an explicit mapping: enumerate and copy only the allowed properties into the returned GatewayNotification payload (i.e., explicitly pick fields such as title, body, data, badge, sound, etc.) inside getGatewayNotificationData and remove the subtractive spread and the comment so the mapping is explicit and self-documenting for GatewayNotification.apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts (2)
68-75: Extract these state guards instead of documenting them inline.The new comments are explaining branching that would read better as small predicates like
shouldSkipAcceptedCallEvent()andshouldSkipStaleIncomingCall(). That keeps the flow readable without carrying implementation comments.As per coding guidelines, "Avoid code comments in the implementation".
Also applies to: 101-102
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts` around lines 68 - 75, Extract the inline state guards into named predicate helpers to remove the explanatory comments: create shouldSkipAcceptedCallEvent(call, event) that returns true when call.acceptedAt is set and event !== 'answer', and create shouldSkipStaleIncomingCall(call, event) which uses getPushNotificationType(call) and returns true when event === 'new' and type !== 'incoming_call'; then replace the two inline if-checks in sendVoipPushNotification with these predicates (and remove the comments), and update any related checks around the other similar branch (the other occurrence around the existing checks) to call the new helpers for clarity.
85-87: Don't count this as sent yet.Line 85 increments
metrics.notificationsSentbefore any token lookup or dispatch, andPush.send()catches its own failures inapps/meteor/app/push/server/push.tsLines 500-508. Right now this metric reports attempts as successful sends, which will make VoIP rollout telemetry hard to trust.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts` around lines 85 - 87, metrics.notificationsSent is being incremented before the push is actually dispatched and Push.send internally catches failures; move the metrics.notificationsSent.inc call so it runs only after a successful send. Specifically, in sendVoipPushNotification (around where metrics.notificationsSent.inc and Push.send are called), await Push.send(...) and only call metrics.notificationsSent.inc({ notification_type: 'mobile' }) when Push.send resolves without error (or when the send result indicates success); do not increment on start or on caught failures from apps/meteor/app/push/server/push.ts send handler.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/meteor/app/push/server/push.ts`:
- Around line 300-306: The retry branch in sendGatewayPush currently schedules
exponential backoff retries even for VoIP pushes (notification.useVoipToken),
allowing stale incoming_call re-delivery; change the logic in sendGatewayPush to
skip scheduling delayed retries when notification.useVoipToken is true (do not
call setTimeout with sendGatewayPush for VoIP pushes) and instead avoid retrying
(or handle VoIP retries synchronously if a different behavior is required).
Update both retry sites (the setTimeout call using tries/maxTries around the
exponential backoff and the similar block at lines ~331-334) to check
notification.useVoipToken and return without queuing a delayed retry when it's
true. Ensure you reference the notification.useVoipToken flag and the
sendGatewayPush(...) retry invocation so the fix is applied to both locations.
---
Duplicate comments:
In `@apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts`:
- Around line 13-22: The projection for getActorUser currently only requests
name and username, but later code expects freeSwitchExtension (causing SIP
actors to get undefined); update the projection object in getActorUser (used by
Users.findOneById and Users.findOneByFreeSwitchExtension) to include
freeSwitchExtension so the returned user documents contain that field for the
SIP fallback logic to work correctly.
---
Nitpick comments:
In `@apps/meteor/app/push/server/push.ts`:
- Around line 310-317: The current getGatewayNotificationData function uses a
subtractive spread on PendingPushNotification (via destructuring
priority/useVoipToken) which will silently forward any future fields to the
gateway; replace this brittle approach with an explicit mapping: enumerate and
copy only the allowed properties into the returned GatewayNotification payload
(i.e., explicitly pick fields such as title, body, data, badge, sound, etc.)
inside getGatewayNotificationData and remove the subtractive spread and the
comment so the mapping is explicit and self-documenting for GatewayNotification.
In `@apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts`:
- Around line 68-75: Extract the inline state guards into named predicate
helpers to remove the explanatory comments: create
shouldSkipAcceptedCallEvent(call, event) that returns true when call.acceptedAt
is set and event !== 'answer', and create shouldSkipStaleIncomingCall(call,
event) which uses getPushNotificationType(call) and returns true when event ===
'new' and type !== 'incoming_call'; then replace the two inline if-checks in
sendVoipPushNotification with these predicates (and remove the comments), and
update any related checks around the other similar branch (the other occurrence
around the existing checks) to call the new helpers for clarity.
- Around line 85-87: metrics.notificationsSent is being incremented before the
push is actually dispatched and Push.send internally catches failures; move the
metrics.notificationsSent.inc call so it runs only after a successful send.
Specifically, in sendVoipPushNotification (around where
metrics.notificationsSent.inc and Push.send are called), await Push.send(...)
and only call metrics.notificationsSent.inc({ notification_type: 'mobile' })
when Push.send resolves without error (or when the send result indicates
success); do not increment on start or on caught failures from
apps/meteor/app/push/server/push.ts send handler.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1c0d8831-8f61-4124-9a18-d7e1d582d852
📒 Files selected for processing (6)
apps/meteor/app/push/server/push.tsapps/meteor/server/services/media-call/push/getPushNotificationType.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tspackages/core-typings/src/index.tspackages/model-typings/src/models/IPushTokenModel.tspackages/models/src/models/PushToken.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/models/src/models/PushToken.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: 📦 Build Packages
- GitHub Check: cubic · AI code reviewer
- GitHub Check: CodeQL-Build
- GitHub Check: CodeQL-Build
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
packages/core-typings/src/index.tsapps/meteor/server/services/media-call/push/getPushNotificationType.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tspackages/model-typings/src/models/IPushTokenModel.tsapps/meteor/app/push/server/push.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: pierre-lehnen-rc
Repo: RocketChat/Rocket.Chat PR: 39174
File: apps/meteor/server/services/push/tokenManagement/registerPushToken.ts:47-49
Timestamp: 2026-03-02T16:21:44.002Z
Learning: In the Rocket.Chat push token system (apps/meteor/server/services/push/tokenManagement/registerPushToken.ts), the main (non-VoIP) token is responsible for keeping authToken, appName, and userId updated. VoIP tokens are supplementary—when a device already has a non-VoIP token registered, VoIP token updates only modify the voipToken field, delegating metadata management to the main token registration flow.
📚 Learning: 2026-03-02T16:21:44.002Z
Learnt from: pierre-lehnen-rc
Repo: RocketChat/Rocket.Chat PR: 39174
File: apps/meteor/server/services/push/tokenManagement/registerPushToken.ts:47-49
Timestamp: 2026-03-02T16:21:44.002Z
Learning: In the Rocket.Chat push token system (apps/meteor/server/services/push/tokenManagement/registerPushToken.ts), the main (non-VoIP) token is responsible for keeping authToken, appName, and userId updated. VoIP tokens are supplementary—when a device already has a non-VoIP token registered, VoIP token updates only modify the voipToken field, delegating metadata management to the main token registration flow.
Applied to files:
packages/core-typings/src/index.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tspackages/model-typings/src/models/IPushTokenModel.tsapps/meteor/app/push/server/push.ts
📚 Learning: 2026-02-25T20:10:16.987Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38913
File: packages/ddp-client/src/legacy/types/SDKLegacy.ts:34-34
Timestamp: 2026-02-25T20:10:16.987Z
Learning: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor (e.g., declare module 'rocket.chat/rest-typings') are not visible when compiling packages/ddp-client in isolation, which is why legacy SDK methods that depend on OperationResult types for OpenAPI-migrated endpoints must remain commented out.
Applied to files:
packages/core-typings/src/index.tspackages/model-typings/src/models/IPushTokenModel.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.
Applied to files:
packages/core-typings/src/index.tsapps/meteor/server/services/media-call/push/getPushNotificationType.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tspackages/model-typings/src/models/IPushTokenModel.tsapps/meteor/app/push/server/push.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.
Applied to files:
packages/core-typings/src/index.tsapps/meteor/server/services/media-call/push/getPushNotificationType.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.tspackages/model-typings/src/models/IPushTokenModel.tsapps/meteor/app/push/server/push.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2025-12-18T15:18:31.688Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37773
File: apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx:24-34
Timestamp: 2025-12-18T15:18:31.688Z
Learning: In apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx, for internal call history items, the item.contactId is guaranteed to always match either the caller.id or callee.id in the call data, so the contact resolution in getContact will never result in undefined.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2025-09-30T13:00:05.465Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 36990
File: apps/meteor/ee/server/apps/storage/AppRealStorage.ts:55-58
Timestamp: 2025-09-30T13:00:05.465Z
Learning: In AppRealStorage (apps/meteor/ee/server/apps/storage/AppRealStorage.ts), the `remove` method is designed to be idempotent and returns `{ success: true }` unconditionally because the goal is to ensure the app is removed, not to distinguish whether this specific call performed the deletion. Database errors will throw exceptions.
Applied to files:
packages/model-typings/src/models/IPushTokenModel.ts
📚 Learning: 2025-11-17T14:30:36.271Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 37491
File: packages/desktop-api/src/index.ts:17-27
Timestamp: 2025-11-17T14:30:36.271Z
Learning: In the Rocket.Chat desktop API (`packages/desktop-api/src/index.ts`), the `CustomNotificationOptions` type has an optional `id` field by design. Custom notifications dispatched without an ID cannot be closed programmatically using `closeCustomNotification`, and this is intentional.
Applied to files:
apps/meteor/app/push/server/push.ts
🔇 Additional comments (2)
packages/core-typings/src/index.ts (1)
30-30: LGTM!The change from
export type *toexport *correctly exposes the runtimepushTokenTypesconst array fromIPushToken.ts, which is needed for the VoIP push notification feature. This follows the established pattern used for other modules that export runtime values (e.g.,UserStatuson line 13 andIServerEventon line 28).apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts (1)
101-102: I need the review comment to be provided in order to rewrite it. Please share the original review comment that needs to be verified and rewritten.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts (1)
18-24: Add exhaustive handling for actor types.The switch statement lacks a
defaultcase, causing the function to implicitly returnundefinedwhenactor.typeis neither'user'nor'sip'. This contradicts the declared return typePromise<T | null>.Proposed fix
switch (actor.type) { case 'user': return Users.findOneById<T>(actor.id, options); case 'sip': return Users.findOneByFreeSwitchExtension<T>(actor.id, options); + default: + return null; } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts` around lines 18 - 24, The switch over actor.type in sendVoipPushNotification.ts only handles 'user' and 'sip' and can implicitly return undefined; update the switch in the function so it is exhaustive: add a default branch that returns null (or explicitly Promise.resolve(null) to match Promise<T | null>), or replace the default with an assertUnreachable check/cast if you prefer stricter typing. Make the change near the existing branches for Users.findOneById<T> and Users.findOneByFreeSwitchExtension<T> so unknown actor.type values reliably produce null (or an explicit runtime error if you choose assertUnreachable).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts`:
- Around line 106-110: The statement in sendVoipPushNotification that calls
sendVoipPushNotificationAsync(...).catch(...) is missing a trailing semicolon;
update the end of the void sendVoipPushNotificationAsync(callId,
event).catch((err) => { logger.error({ msg: 'Failed to send VoIP push
notification', err, callId, event }); }) line to include a semicolon so the
sendVoipPushNotification function ends with a proper statement terminator.
- Line 90: The file uses Meteor.absoluteUrl() but does not import Meteor; add
the missing import "import { Meteor } from 'meteor/meteor';" at the top of the
module (matching other files' import style) so Meteor.absoluteUrl() resolves
correctly and avoids a ReferenceError.
---
Nitpick comments:
In `@apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts`:
- Around line 18-24: The switch over actor.type in sendVoipPushNotification.ts
only handles 'user' and 'sip' and can implicitly return undefined; update the
switch in the function so it is exhaustive: add a default branch that returns
null (or explicitly Promise.resolve(null) to match Promise<T | null>), or
replace the default with an assertUnreachable check/cast if you prefer stricter
typing. Make the change near the existing branches for Users.findOneById<T> and
Users.findOneByFreeSwitchExtension<T> so unknown actor.type values reliably
produce null (or an explicit runtime error if you choose assertUnreachable).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3fda886b-c087-4e7f-bcac-abd95d1bcf92
📒 Files selected for processing (2)
apps/meteor/app/api/server/v1/push.tsapps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/meteor/app/api/server/v1/push.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: 🔨 Test Unit / Unit Tests
- GitHub Check: 🔎 Code Check / TypeScript
- GitHub Check: 🔎 Code Check / Code Lint
- GitHub Check: 📦 Meteor Build (coverage)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: pierre-lehnen-rc
Repo: RocketChat/Rocket.Chat PR: 39174
File: apps/meteor/server/services/push/tokenManagement/registerPushToken.ts:47-49
Timestamp: 2026-03-02T16:21:44.002Z
Learning: In the Rocket.Chat push token system (apps/meteor/server/services/push/tokenManagement/registerPushToken.ts), the main (non-VoIP) token is responsible for keeping authToken, appName, and userId updated. VoIP tokens are supplementary—when a device already has a non-VoIP token registered, VoIP token updates only modify the voipToken field, delegating metadata management to the main token registration flow.
📚 Learning: 2026-03-02T16:21:44.002Z
Learnt from: pierre-lehnen-rc
Repo: RocketChat/Rocket.Chat PR: 39174
File: apps/meteor/server/services/push/tokenManagement/registerPushToken.ts:47-49
Timestamp: 2026-03-02T16:21:44.002Z
Learning: In the Rocket.Chat push token system (apps/meteor/server/services/push/tokenManagement/registerPushToken.ts), the main (non-VoIP) token is responsible for keeping authToken, appName, and userId updated. VoIP tokens are supplementary—when a device already has a non-VoIP token registered, VoIP token updates only modify the voipToken field, delegating metadata management to the main token registration flow.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2025-12-18T15:18:31.688Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37773
File: apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx:24-34
Timestamp: 2025-12-18T15:18:31.688Z
Learning: In apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx, for internal call history items, the item.contactId is guaranteed to always match either the caller.id or callee.id in the call data, so the contact resolution in getContact will never result in undefined.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.
Applied to files:
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
🔇 Additional comments (1)
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts (1)
26-54: LGTM!The fallback chain for actor name resolution and conditional avatar URL generation are well-structured.
apps/meteor/server/services/media-call/push/sendVoipPushNotification.ts
Outdated
Show resolved
Hide resolved
Co-authored-by: Kevin Aleman <kaleman960@gmail.com>
| authRequired: true, | ||
| }, | ||
| async function action() { | ||
| const { token } = this.bodyParams; |
There was a problem hiding this comment.
I think we need to remove voip token as well, right?
Proposed changes (including videos or screenshots)
Issue(s)
VMUX-47
Steps to test or reproduce
Further comments
Summary by CodeRabbit
New Features
Improvements