feat: add BigBlueButton video conferencing integration#27469
feat: add BigBlueButton video conferencing integration#27469njg7194 wants to merge 1 commit intocalcom:mainfrom
Conversation
This adds BigBlueButton as a video conferencing option for Cal.com bookings. BigBlueButton is an open source web conferencing system designed for online learning, supporting real-time audio, video, slides, chat, and screen sharing. Features: - Dynamic meeting creation via BigBlueButton API - Configurable BBB server URL and secret - Automatic checksum-based API authentication - Support for concurrent meetings Closes calcom#1985
|
|
Graphite Automations"Send notification to Community team when bounty PR opened" took an action on this PR • (02/01/26)2 teammates were notified to this PR based on Keith Williams's automation. |
There was a problem hiding this comment.
4 issues found across 11 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/app-store/bigbluebutton/package.json">
<violation number="1" location="packages/app-store/bigbluebutton/package.json:8">
P2: @calcom/bigbluebutton imports `zod` directly but the package.json for this new package does not declare `zod` in dependencies, which can cause module resolution failures in workspace installs or isolated builds.</violation>
</file>
<file name="packages/app-store/bigbluebutton/DESCRIPTION.md">
<violation number="1" location="packages/app-store/bigbluebutton/DESCRIPTION.md:3">
P2: Referenced carousel asset `bigbluebutton1.webp` is missing from the repository, so the App Store page will render a broken image unless the file is added or the reference updated.</violation>
</file>
<file name="packages/app-store/bigbluebutton/lib/VideoApiAdapter.ts">
<violation number="1" location="packages/app-store/bigbluebutton/lib/VideoApiAdapter.ts:93">
P1: The returned meeting URL is built with the moderator password and organizer name, so any recipient of this link will join as a moderator under the organizer identity. This exposes moderator controls to attendees and causes identity confusion. Generate attendee join links (or per-user signed URLs) instead of returning the moderator join URL as the general meeting link.</violation>
<violation number="2" location="packages/app-store/bigbluebutton/lib/VideoApiAdapter.ts:128">
P2: `deleteMeeting` calls BigBlueButton `end` with an empty password. The API requires the moderator password to end a meeting, but the moderator password generated in `createMeeting` isn’t persisted or returned, so the `end` call will fail and meetings may remain active until timeout.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| // Generate join URL for moderator (organizer) | ||
| const joinParams: Record<string, string> = { | ||
| meetingID: meetingID, | ||
| password: moderatorPassword, |
There was a problem hiding this comment.
P1: The returned meeting URL is built with the moderator password and organizer name, so any recipient of this link will join as a moderator under the organizer identity. This exposes moderator controls to attendees and causes identity confusion. Generate attendee join links (or per-user signed URLs) instead of returning the moderator join URL as the general meeting link.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/bigbluebutton/lib/VideoApiAdapter.ts, line 93:
<comment>The returned meeting URL is built with the moderator password and organizer name, so any recipient of this link will join as a moderator under the organizer identity. This exposes moderator controls to attendees and causes identity confusion. Generate attendee join links (or per-user signed URLs) instead of returning the moderator join URL as the general meeting link.</comment>
<file context>
@@ -0,0 +1,155 @@
+ // Generate join URL for moderator (organizer)
+ const joinParams: Record<string, string> = {
+ meetingID: meetingID,
+ password: moderatorPassword,
+ fullName: eventData.organizer.name || "Organizer",
+ redirect: "true",
</file context>
| "main": "./index.ts", | ||
| "description": "BigBlueButton is an open source web conferencing system for online learning. It supports real-time sharing of audio, video, slides, chat, and screen.", | ||
| "dependencies": { | ||
| "@calcom/lib": "workspace:*" |
There was a problem hiding this comment.
P2: @calcom/bigbluebutton imports zod directly but the package.json for this new package does not declare zod in dependencies, which can cause module resolution failures in workspace installs or isolated builds.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/bigbluebutton/package.json, line 8:
<comment>@calcom/bigbluebutton imports `zod` directly but the package.json for this new package does not declare `zod` in dependencies, which can cause module resolution failures in workspace installs or isolated builds.</comment>
<file context>
@@ -0,0 +1,13 @@
+ "main": "./index.ts",
+ "description": "BigBlueButton is an open source web conferencing system for online learning. It supports real-time sharing of audio, video, slides, chat, and screen.",
+ "dependencies": {
+ "@calcom/lib": "workspace:*"
+ },
+ "devDependencies": {
</file context>
| @@ -0,0 +1,6 @@ | |||
| --- | |||
| items: | |||
| - bigbluebutton1.webp | |||
There was a problem hiding this comment.
P2: Referenced carousel asset bigbluebutton1.webp is missing from the repository, so the App Store page will render a broken image unless the file is added or the reference updated.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/bigbluebutton/DESCRIPTION.md, line 3:
<comment>Referenced carousel asset `bigbluebutton1.webp` is missing from the repository, so the App Store page will render a broken image unless the file is added or the reference updated.</comment>
<file context>
@@ -0,0 +1,6 @@
+---
+items:
+ - bigbluebutton1.webp
+---
+
</file context>
|
|
||
| const endParams: Record<string, string> = { | ||
| meetingID: uid, | ||
| password: "", // We don't store moderator password, but end might still work |
There was a problem hiding this comment.
P2: deleteMeeting calls BigBlueButton end with an empty password. The API requires the moderator password to end a meeting, but the moderator password generated in createMeeting isn’t persisted or returned, so the end call will fail and meetings may remain active until timeout.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/bigbluebutton/lib/VideoApiAdapter.ts, line 128:
<comment>`deleteMeeting` calls BigBlueButton `end` with an empty password. The API requires the moderator password to end a meeting, but the moderator password generated in `createMeeting` isn’t persisted or returned, so the `end` call will fail and meetings may remain active until timeout.</comment>
<file context>
@@ -0,0 +1,155 @@
+
+ const endParams: Record<string, string> = {
+ meetingID: uid,
+ password: "", // We don't store moderator password, but end might still work
+ };
+
</file context>
|
This PR has been marked as stale due to inactivity. If you're still working on it or need any help, please let us know or update the PR to keep it active. |
| const apiBase = bbbUrl.endsWith("/") | ||
| ? `${bbbUrl}api/` | ||
| : bbbUrl.endsWith("/api/") | ||
| ? bbbUrl | ||
| : `${bbbUrl}/api/`; |
There was a problem hiding this comment.
🔴 Condition ordering in URL construction causes double /api/api/ path when BBB URL already ends with /api/
When a user configures a BigBlueButton URL that already ends with /api/ (e.g., https://bbb.example.com/bigbluebutton/api/), the API base URL is constructed incorrectly, resulting in all BBB API calls failing.
Root Cause
The ternary checks bbbUrl.endsWith("/") before checking bbbUrl.endsWith("/api/"). Since any string ending with /api/ also ends with /, the first condition always matches first, and "api/" is appended again:
const apiBase = bbbUrl.endsWith("/") // <-- matches first for '/api/' URLs
? `${bbbUrl}api/` // => 'https://…/api/api/'
: bbbUrl.endsWith("/api/") // <-- never reached for '/api/' URLs
? bbbUrl
: `${bbbUrl}/api/`;For input https://bbb.example.com/bigbluebutton/api/:
- Actual:
https://bbb.example.com/bigbluebutton/api/api/(broken) - Expected:
https://bbb.example.com/bigbluebutton/api/(correct)
The more specific /api/ check must come before the generic / check. The same bug exists in deleteMeeting at packages/app-store/bigbluebutton/lib/VideoApiAdapter.ts:120-124.
Impact: Meeting creation and deletion fail for any admin who configures the BBB URL with a trailing /api/ path, which is a common format shown in the BBB documentation.
| const apiBase = bbbUrl.endsWith("/") | |
| ? `${bbbUrl}api/` | |
| : bbbUrl.endsWith("/api/") | |
| ? bbbUrl | |
| : `${bbbUrl}/api/`; | |
| const apiBase = bbbUrl.endsWith("/api/") | |
| ? bbbUrl | |
| : bbbUrl.endsWith("/") | |
| ? `${bbbUrl}api/` | |
| : `${bbbUrl}/api/`; |
Was this helpful? React with 👍 or 👎 to provide feedback.
| const apiBase = bbbUrl.endsWith("/") | ||
| ? `${bbbUrl}api/` | ||
| : bbbUrl.endsWith("/api/") | ||
| ? bbbUrl | ||
| : `${bbbUrl}/api/`; |
There was a problem hiding this comment.
🔴 Same condition ordering bug in deleteMeeting URL construction causes double /api/api/ path
The deleteMeeting method has the same URL construction bug as createMeeting — it checks endsWith("/") before endsWith("/api/"), causing the BBB end API call to target a wrong URL.
Root Cause
This is the same logic error as in createMeeting (packages/app-store/bigbluebutton/lib/VideoApiAdapter.ts:46-50), duplicated in deleteMeeting. The more specific check for /api/ must come first:
// Current (broken):
const apiBase = bbbUrl.endsWith("/")
? `${bbbUrl}api/`
: bbbUrl.endsWith("/api/")
? bbbUrl
: `${bbbUrl}/api/`;Impact: When a meeting is cancelled or rescheduled, the end API call to BigBlueButton will target the wrong URL and fail to terminate the meeting on the BBB server.
| const apiBase = bbbUrl.endsWith("/") | |
| ? `${bbbUrl}api/` | |
| : bbbUrl.endsWith("/api/") | |
| ? bbbUrl | |
| : `${bbbUrl}/api/`; | |
| const apiBase = bbbUrl.endsWith("/api/") | |
| ? bbbUrl | |
| : bbbUrl.endsWith("/") | |
| ? `${bbbUrl}api/` | |
| : `${bbbUrl}/api/`; |
Was this helpful? React with 👍 or 👎 to provide feedback.
What does this PR do?
This PR adds BigBlueButton as a video conferencing integration for Cal.com.
Fixes #1985
BigBlueButton Overview
BigBlueButton is an open source web conferencing system designed for online learning. It supports:
Implementation Details
This integration follows the same pattern as other video conferencing apps (Jitsi, Daily, Zoom):
_metadata.ts- App metadata and configurationlib/VideoApiAdapter.ts- Core API integration with BBB serverapi/add.ts- App installation handlerzod.ts- Schema for app keys (BBB URL and secret)Configuration
Users need to configure:
https://bbb.example.com/bigbluebutton/)API Integration
The implementation uses the BigBlueButton API:
create- Creates a new meeting roomjoin- Generates join URLs for participantsend- Ends a meeting (on deletion)Checksum-based authentication is implemented as per BBB API requirements.
Type of change
How should this be tested?
Mandatory Tasks