Skip to content

feat(call-recorder): support Meeting BaaS provider - #4

Open
Lazare-42 wants to merge 1 commit into
call-recorder-upstream-basefrom
meeting-baas-call-recorder
Open

feat(call-recorder): support Meeting BaaS provider#4
Lazare-42 wants to merge 1 commit into
call-recorder-upstream-basefrom
meeting-baas-call-recorder

Conversation

@Lazare-42

Copy link
Copy Markdown
Contributor

Summary

  • add CALL_RECORDER_PROVIDER with Recall as the default and Meeting BaaS as an alternate provider
  • add Meeting BaaS scheduling, rescheduling, cancellation, bot detail polling, webhook handling, and transcript normalization
  • keep Recall webhook/API behavior intact while routing shared workflows through provider wrappers
  • document both provider configurations and Meeting BaaS API docs

Verification

  • git diff --check
  • Not run: yarn/typecheck/tests locally because this shell has no node, yarn, corepack, npm, tsgo, or tsc on PATH

Notes

  • Meeting BaaS uses a separate server webhook logic function because its workspace resolver is data.extra.twentyWorkspaceId, while Recall keeps data.bot.metadata.twentyWorkspaceId.

@Lazare-42

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Lazare-42
Lazare-42 changed the base branch from main to call-recorder-upstream-base June 25, 2026 09:05
@Lazare-42

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Summary by CodeRabbit

  • New Features

    • Added support for a second call recording provider alongside the existing one.
    • Introduced webhook handling, scheduling, rescheduling, and cancellation for the new provider.
    • Added support for ingesting media and transcripts from provider callbacks.
  • Bug Fixes

    • Improved status handling to avoid downgrading newer recording updates.
    • Updated orphan cleanup so it only runs for the applicable provider.
  • Documentation

    • Expanded setup instructions with provider-specific environment variables and configuration examples.

Walkthrough

Adds Meeting BaaS as a call-recorder provider, including new server variables, API helpers, webhook handling, provider-routing wrappers, and updated scheduling, cancellation, and convergence flows.

Changes

Meeting BaaS call recorder integration

Layer / File(s) Summary
Provider configuration and docs
packages/twenty-apps/public/call-recorder/README.md, packages/twenty-apps/public/call-recorder/src/application-config.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/constants/*, packages/twenty-apps/public/call-recorder/src/logic-functions/providers/call-recorder-provider.type.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/providers/get-call-recorder-provider.util.ts
Server-variable docs, application config, provider typing, and provider selection are updated for call recorder provider choice.
Meeting BaaS API helpers
packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/get-meeting-baas-api-config.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/meeting-baas-api-request.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/get-meeting-baas-bot.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/schedule-meeting-baas-bot.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/reschedule-meeting-baas-bot.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/cancel-meeting-baas-bot.util.ts
Meeting BaaS API config, request handling, bot lookup, and scheduled-bot create/reschedule/cancel helpers are added.
Webhook payload and handler
packages/twenty-apps/public/call-recorder/src/constants/meeting-baas-webhook-logic-function-universal-identifier.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-webhook.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/flows/handle-meeting-baas-webhook.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/parse-meeting-baas-webhook-event.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/domain/map-meeting-baas-status-to-call-recording-status.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/normalize-meeting-baas-transcript.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/flows/ingest-call-recording-media.util.ts
The Meeting BaaS webhook entrypoint, event parser, transcript normalizer, media ingestion helper, and status mapping are added, and webhook payloads update call recordings.
Provider routing wrappers
packages/twenty-apps/public/call-recorder/src/logic-functions/providers/schedule-call-recorder-bot.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/providers/reschedule-call-recorder-bot.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/providers/cancel-call-recorder-bot.util.ts
Provider-routing wrappers dispatch scheduling, rescheduling, and cancellation to Meeting BaaS or Recall implementations.
Existing flow wiring
packages/twenty-apps/public/call-recorder/src/logic-functions/flows/ensure-call-recorder.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/flows/cancel-call-recording-request.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/flows/reschedule-call-recording-bot.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/flows/reap-orphaned-call-recorders.util.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/flows/__tests__/heal-call-recordings-missing-bot.test.ts, packages/twenty-apps/public/call-recorder/src/logic-functions/flows/__tests__/reconcile-call-recorder.test.ts
Ensure, cancel, reschedule, and orphan reaping flows are switched to the provider wrappers, and their tests mock the new module paths.
Diverged recording convergence
packages/twenty-apps/public/call-recorder/src/logic-functions/flows/converge-diverged-call-recordings.util.ts
The diverged-recording convergence flow branches to Meeting BaaS, fetches provider bot state, ingests media, resolves transcripts, and applies provider-specific failure updates.

Sequence Diagram(s)

sequenceDiagram
  participant meetingBaasWebhookRouteHandler
  participant handleMeetingBaasWebhook
  participant parseMeetingBaasWebhookEvent
  participant ingestCallRecordingMediaFromUrls
  participant normalizeMeetingBaasTranscript
  participant updateCallRecording

  meetingBaasWebhookRouteHandler->>handleMeetingBaasWebhook: forward validated webhook body
  handleMeetingBaasWebhook->>parseMeetingBaasWebhookEvent: parse Meeting BaaS event
  alt COMPLETED event
    handleMeetingBaasWebhook->>ingestCallRecordingMediaFromUrls: ingest audio/video URLs
    handleMeetingBaasWebhook->>normalizeMeetingBaasTranscript: normalize transcript payload
  end
  handleMeetingBaasWebhook->>updateCallRecording: persist status, ids, and transcript
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Poem

🐰 I hopped through callbacks, wee and bright,
With provider paws set just right.
Meeting BaaS sang, Recall replied,
Through webhook winds and transcript tide,
And every bot found its moonlit flight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding Meeting BaaS provider support to call-recorder.
Description check ✅ Passed The description matches the changeset and covers the new provider routing, Meeting BaaS flows, and docs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch meeting-baas-call-recorder

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/flows/converge-diverged-call-recordings.util.ts`:
- Around line 685-700: The transcript fetch in
converge-diverged-call-recordings.util.ts should be hardened before parsing the
body. In the transcript retrieval logic around fetch/transcriptRecord, validate
that the response has an expected JSON Content-Type and reject unexpected or
empty bodies before calling response.json(). Also add a bounded body-size check
or use a safer read path so large malformed responses cannot stall the
per-candidate convergence loop, and consider reducing the AbortSignal.timeout
used in this flow to a more appropriate per-recording limit.
- Around line 573-581: The failure gate in convergeDivergedCallRecordings logic
is short-circuiting too early for Meeting BaaS because
extractMeetingBaasConvergence populates externalRecordingId from bot.bot_id even
when no media artifact exists. Update the terminal-artifact check in
converge-diverged-call-recordings.util.ts so it keys off actual artifact
availability for Meeting BaaS (for example, audioUrl/videoUrl presence from the
Meeting BaaS convergence data) rather than !isUndefined(externalRecordingId),
and keep the existing candidate.status, updateData.status,
convergence.isRecordingDone, and hasRecordingArtifactPath conditions intact.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/flows/handle-meeting-baas-webhook.util.ts`:
- Around line 79-89: The `handleMeetingBaasWebhook` completion path is
hardcoding `hasAudio` and `hasVideo` to false, which causes
`ingestCallRecordingMediaFromUrls` to reprocess media on repeated
`bot.completed` events. Update this flow so the flags come from a richer
`callRecording` fetch that includes existing media presence, or move the
dedup/skip check into `ingestCallRecordingMediaFromUrls` itself; use the `status
=== CallRecordingStatus.COMPLETED` block and `ingestCallRecordingMediaFromUrls`
call as the main fix points.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/get-meeting-baas-api-config.util.ts`:
- Around line 60-70: The config builder in get-meeting-baas-api-config.util.ts
returns apiKey and callbackSecret without trimming, unlike botName and
callbackUrl. Update the returned config object to normalize these two values
with trim() before use so the x-meeting-baas-api-key header and x-mb-secret
comparison do not include accidental whitespace; keep the change localized to
the getMeetingBaasApiConfig logic and preserve the existing fallback behavior
for botName.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/get-meeting-baas-bot.util.ts`:
- Line 32: The getMeetingBaasBot result handling currently treats a missing
payload as success by returning an empty bot object, which can mask malformed
responses. Update the get-meeting-baas-bot.util.ts logic around
getMeetingBaasBot so that only a real bot payload from result.data?.data returns
ok: true, and any absent/invalid payload is returned as a failure instead of
defaulting to {}. Keep the response shape aligned with the existing bot/result
types used by this utility.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/meeting-baas-api-request.util.ts`:
- Around line 28-35: The Meeting BaaS fetch in meeting-baas-api-request.util.ts
currently has no timeout, so slow upstream calls can hang the logic-function.
Update the request in the request helper that builds the fetch options to attach
an AbortSignal created with AbortSignal.timeout(...), and pass it as the signal
alongside method, headers, and optional body. Keep the change localized to the
request utility so all Meeting BaaS calls fail fast consistently.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/schedule-meeting-baas-bot.util.ts`:
- Around line 77-85: In schedule-meeting-baas-bot.util.ts, the external bot ID
check only rejects undefined, so `result.data?.data?.bot_id` can still be null
or an empty string and later break downstream API calls. Update the validation
around `externalBotId` to require a non-empty string before returning success,
and keep the existing error return path when the value is missing or invalid.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-webhook.ts`:
- Line 52: The webhook handler in meeting-baas-webhook is using a function
timeout that is shorter than the internal COMPLETED ingestion work, so adjust
the budget to match the downstream media and transcript timeouts or reduce those
internal timeouts accordingly. Update the logic around the webhook entrypoint
and the COMPLETED path that calls the media download and transcript fetch
helpers so the total execution window safely covers both sequential steps before
updateCallRecording runs.
- Line 33: The x-mb-secret check in meeting-baas-webhook should use a
constant-time comparison instead of a direct string inequality. Update the
secret validation logic in the webhook handler to convert both values to
equal-length buffers and compare them with crypto.timingSafeEqual, keeping the
existing webhookSecret and routePayload.headers['x-mb-secret'] flow intact.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/providers/get-call-recorder-provider.util.ts`:
- Line 10: Normalize the provider input inside getCallRecorderProvider by
trimming whitespace and converting to lowercase before the comparison, so values
like stray-spaced or differently cased meeting-baas still resolve correctly.
Update the matching logic around the rawProvider return path to compare against
the normalized value rather than the original string, and keep the fallback to
recall only for truly unknown providers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 87d67f73-aba4-49eb-981c-0815be8e5023

📥 Commits

Reviewing files that changed from the base of the PR and between 811fecc and 8a8ddd2.

📒 Files selected for processing (32)
  • packages/twenty-apps/public/call-recorder/README.md
  • packages/twenty-apps/public/call-recorder/src/application-config.ts
  • packages/twenty-apps/public/call-recorder/src/constants/meeting-baas-webhook-logic-function-universal-identifier.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/constants/call-recorder-provider-env-var-name.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/constants/meeting-baas-api-base-url-env-var-name.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/constants/meeting-baas-api-key-env-var-name.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/constants/meeting-baas-callback-secret-env-var-name.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/constants/meeting-baas-callback-url-env-var-name.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/domain/map-meeting-baas-status-to-call-recording-status.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/flows/__tests__/heal-call-recordings-missing-bot.test.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/flows/__tests__/reconcile-call-recorder.test.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/flows/cancel-call-recording-request.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/flows/converge-diverged-call-recordings.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/flows/ensure-call-recorder.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/flows/handle-meeting-baas-webhook.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/flows/ingest-call-recording-media.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/flows/reap-orphaned-call-recorders.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/flows/reschedule-call-recording-bot.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/cancel-meeting-baas-bot.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/get-meeting-baas-api-config.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/get-meeting-baas-bot.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/meeting-baas-api-request.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/normalize-meeting-baas-transcript.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/parse-meeting-baas-webhook-event.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/reschedule-meeting-baas-bot.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/schedule-meeting-baas-bot.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-webhook.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/providers/call-recorder-provider.type.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/providers/cancel-call-recorder-bot.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/providers/get-call-recorder-provider.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/providers/reschedule-call-recorder-bot.util.ts
  • packages/twenty-apps/public/call-recorder/src/logic-functions/providers/schedule-call-recorder-bot.util.ts

Comment on lines +573 to +581
if (
candidate.status === CallRecordingStatus.COMPLETED ||
updateData.status === CallRecordingStatus.FAILED ||
!convergence.isRecordingDone ||
!isUndefined(externalRecordingId) ||
hasRecordingArtifactPath({ candidate, updateData })
) {
return undefined;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd 'get-meeting-baas-bot.util.ts' --exec cat -n {}
fd 'has-recording-artifact-path' -e ts --exec cat -n {}

Repository: Meeting-BaaS/twenty

Length of output: 1336


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant implementation and helper.
fd 'converge-diverged-call-recordings.util.ts' packages -x sed -n '1,260p' {}
printf '\n--- SPLIT ---\n'
fd 'converge-diverged-call-recordings.util.ts' packages -x sed -n '260,430p' {}
printf '\n--- SPLIT ---\n'
fd 'converge-diverged-call-recordings.util.ts' packages -x sed -n '430,660p' {}
printf '\n--- SPLIT ---\n'
fd 'converge-diverged-call-recordings.util.ts' packages -x sed -n '660,760p' {}
printf '\n--- SPLIT ---\n'
fd 'has-recording-artifact-path' packages -e ts -x sed -n '1,220p' {}
printf '\n--- SPLIT ---\n'
fd 'extract-meeting-baas-convergence' packages -e ts -x sed -n '1,260p' {}
printf '\n--- SPLIT ---\n'
fd 'get-meeting-baas-bot.util.ts' packages -x sed -n '1,220p' {}

Repository: Meeting-BaaS/twenty

Length of output: 22636


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Narrow down the exact files if the initial names differ.
git ls-files 'packages/**/converge-diverged-call-recordings.util.ts' \
  'packages/**/has-recording-artifact-path*.ts' \
  'packages/**/extract-meeting-baas-convergence*.ts' \
  'packages/**/get-meeting-baas-bot.util.ts'

Repository: Meeting-BaaS/twenty

Length of output: 375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the convergence flow and the artifact-path helper.
files=(
  "$(git ls-files 'packages/**/converge-diverged-call-recordings.util.ts' | head -n 1)"
  "$(git ls-files 'packages/**/has-recording-artifact-path*.ts' | head -n 1)"
  "$(git ls-files 'packages/**/extract-meeting-baas-convergence*.ts' | head -n 1)"
  "$(git ls-files 'packages/**/get-meeting-baas-bot.util.ts' | head -n 1)"
)

for f in "${files[@]}"; do
  [ -n "$f" ] || continue
  echo "--- $f ---"
  wc -l "$f"
  sed -n '1,260p' "$f"
  echo
done

Repository: Meeting-BaaS/twenty

Length of output: 10890


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for Meeting BaaS bot payload assumptions and any docs/examples.
rg -n --hidden --no-ignore-vcs "bot_id|transcriptionUrl|raw_transcription|audioUrl|videoUrl|meeting-baas" packages/twenty-apps/public/call-recorder -g '!**/dist/**' -g '!**/build/**'

Repository: Meeting-BaaS/twenty

Length of output: 19158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for Meeting BaaS payload assumptions and any docs/examples.
rg -n --hidden --no-ignore-vcs "bot_id|transcriptionUrl|raw_transcription|audioUrl|videoUrl|meeting-baas" packages/twenty-apps/public/call-recorder -g '!**/dist/**' -g '!**/build/**'

Repository: Meeting-BaaS/twenty

Length of output: 19158


🌐 Web query:

Meeting BaaS API GET /v2/bots/{bot_id} response bot_id field documentation

💡 Result:

In the Meeting BaaS API v2, the bot_id field is a primary identifier used across multiple endpoints to reference a specific bot instance. When interacting with the bot management endpoints, the bot_id is passed as a path parameter in the URI, typically in the format /v2/bots/{bot_id} [1][2]. This field is a string-type identifier, commonly represented as a UUID [3][4]. Key points regarding the bot_id field: - Purpose: It serves as the unique reference for a deployed bot, allowing you to retrieve details, check status, obtain screenshots, remove the bot from a meeting, or manage its data [1][2]. - Usage in Requests: Methods such as getBotDetails, getBotStatus, leaveBot, and deleteBotData require the bot_id to be provided within the request path [1]. - Source of bot_id: The bot_id is generated and returned by the API upon the successful creation of a bot (e.g., via a POST request to /bots) [5][2][4]. - Webhook Payload: The bot_id is also included within the data object of webhook events sent by Meeting BaaS, allowing you to correlate status updates or completion events with the original bot deployment [3]. For precise implementation details, you can refer to the official Meeting BaaS API v2 documentation or the OpenAPI specification available in their documentation repository [6][7].

Citations:


🌐 Web query:

Meeting BaaS API GET /v2/bots/{bot_id} response bot_id field documentation

💡 Result:

In the Meeting BaaS v2 API, the endpoint GET /v2/bots/{bot_id} is used to retrieve detailed information about a specific bot [1]. In the API response body, the bot_id field is a string that represents the unique identifier (UUID) assigned to the bot [1]. This identifier is consistent across the Meeting BaaS API and is required as a path parameter in subsequent requests related to that specific bot, such as checking its status, retrieving screenshots, leaving a meeting, or deleting its data [1][2]. Example response structure for GET /v2/bots/{bot_id}: { "success": true, "data": { "bot_id": "123e4567-e89b-12d3-a456-426614174000", "status": "completed", "meeting_url": "https://meet.google.com/...",... } } [1] The bot_id serves as the primary reference key for managing the bot's lifecycle and retrieving post-meeting data like recordings, transcripts, and speaker diarization [1].

Citations:


Meeting BaaS can’t reach the terminal-artifact failure gate

packages/twenty-apps/public/call-recorder/src/logic-functions/flows/converge-diverged-call-recordings.util.ts:573-581, 664-671
extractMeetingBaasConvergence() maps bot.bot_id into externalRecordingId, and GET /v2/bots/{bot_id} returns that field. That makes !isUndefined(externalRecordingId) short-circuit this gate for Meeting BaaS, so a completed bot with no audioUrl/videoUrl never transitions to failed. Gate this on actual artifact availability for Meeting BaaS instead of externalRecordingId.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/flows/converge-diverged-call-recordings.util.ts`
around lines 573 - 581, The failure gate in convergeDivergedCallRecordings logic
is short-circuiting too early for Meeting BaaS because
extractMeetingBaasConvergence populates externalRecordingId from bot.bot_id even
when no media artifact exists. Update the terminal-artifact check in
converge-diverged-call-recordings.util.ts so it keys off actual artifact
availability for Meeting BaaS (for example, audioUrl/videoUrl presence from the
Meeting BaaS convergence data) rather than !isUndefined(externalRecordingId),
and keep the existing candidate.status, updateData.status,
convergence.isRecordingDone, and hasRecordingArtifactPath conditions intact.

Comment on lines +685 to +700
try {
const response = await fetch(transcriptUrl, {
signal: AbortSignal.timeout(120_000),
});

if (!response.ok) {
return undefined;
}

const transcript = await response.json();
const transcriptRecord = asRecord(transcript);

return transcriptRecord?.transcript ?? transcript;
} catch {
return undefined;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Harden the provider transcript fetch.

The transcript body is parsed with no Content-Type or size guard, and the 120s AbortSignal.timeout is large for a per-candidate pass that may iterate many recordings. A malformed or very large response could delay/strain the convergence loop. Consider validating the response content type and bounding the body size before response.json().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/flows/converge-diverged-call-recordings.util.ts`
around lines 685 - 700, The transcript fetch in
converge-diverged-call-recordings.util.ts should be hardened before parsing the
body. In the transcript retrieval logic around fetch/transcriptRecord, validate
that the response has an expected JSON Content-Type and reject unexpected or
empty bodies before calling response.json(). Also add a bounded body-size check
or use a safer read path so large malformed responses cannot stall the
per-candidate convergence loop, and consider reducing the AbortSignal.timeout
used in this flow to a more appropriate per-recording limit.

Comment on lines +79 to +89
if (status === CallRecordingStatus.COMPLETED) {
Object.assign(
updateData,
await ingestCallRecordingMediaFromUrls({
callRecordingId: callRecording.id,
hasAudio: false,
hasVideo: false,
audioUrl: webhookEvent.audioUrl,
videoUrl: webhookEvent.videoUrl,
}),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -e ts call-recording-record.type.ts packages/twenty-apps/public/call-recorder/src --exec cat -n {}
rg -nP "audio|video" packages/twenty-apps/public/call-recorder/src/logic-functions/types/call-recording-record.type.ts

Repository: Meeting-BaaS/twenty

Length of output: 767


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the webhook handler and the media-ingest helper signatures/usages.
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/flows/handle-meeting-baas-webhook.util.ts

printf '\n--- ingest helper ---\n'
rg -n "function ingestCallRecordingMediaFromUrls|const ingestCallRecordingMediaFromUrls|export .*ingestCallRecordingMediaFromUrls" packages/twenty-apps/public/call-recorder/src -A 40 -B 20

printf '\n--- callRecording media fields / updates ---\n'
rg -n "audioUrl|videoUrl|hasAudio|hasVideo|ingestCallRecordingMediaFromUrls|uploadFile|callRecording" packages/twenty-apps/public/call-recorder/src -A 2 -B 2

Repository: Meeting-BaaS/twenty

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Narrowly inspect the helper implementation and nearby types, without running repo code.
fd -e ts ingest-call-recording-media-from-urls.util.ts packages/twenty-apps/public/call-recorder/src --exec sh -c 'echo "--- {} ---"; sed -n "1,220p" "$1"' sh {}

printf '\n--- record/wire types ---\n'
fd -e ts call-recording-record.type.ts packages/twenty-apps/public/call-recorder/src --exec sh -c 'echo "--- {} ---"; sed -n "1,120p" "$1"' sh {}
fd -e ts call-recording-wire.type.ts packages/twenty-apps/public/call-recorder/src --exec sh -c 'echo "--- {} ---"; sed -n "1,200p" "$1"' sh {}

Repository: Meeting-BaaS/twenty

Length of output: 795


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the webhook handler and the helper implementation.
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/flows/handle-meeting-baas-webhook.util.ts

printf '\n--- helper lookup ---\n'
rg -n "ingestCallRecordingMediaFromUrls" packages/twenty-apps/public/call-recorder/src -A 30 -B 20

printf '\n--- record type ---\n'
sed -n '1,120p' packages/twenty-apps/public/call-recorder/src/logic-functions/types/call-recording-record.type.ts

Repository: Meeting-BaaS/twenty

Length of output: 42318


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the helper and all call sites to determine what the boolean flags mean.
fd -e ts ingest-call-recording-media-from-urls.util.ts packages/twenty-apps/public/call-recorder/src --exec sh -c 'echo "--- {} ---"; sed -n "1,220p" "$1"' sh {}

printf '\n--- call sites ---\n'
rg -n "ingestCallRecordingMediaFromUrls\(" packages/twenty-apps/public/call-recorder/src -A 6 -B 6

Repository: Meeting-BaaS/twenty

Length of output: 3883


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/data/find-call-recordings-by-filter.util.ts

printf '\n--- update-call-recording util ---\n'
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/data/update-call-recording.util.ts

printf '\n--- any record types with audio/video ---\n'
rg -n "type CallRecording.*audio|type CallRecording.*video|audio\?:|video\?:|audio:|video:" packages/twenty-apps/public/call-recorder/src/logic-functions/types packages/twenty-apps/public/call-recorder/src/logic-functions/data -A 2 -B 2

Repository: Meeting-BaaS/twenty

Length of output: 5805


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the record-reading path to see whether media fields are available there.
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/data/find-call-recordings-by-filter.util.ts

printf '\n--- update util ---\n'
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/data/update-call-recording.util.ts

Repository: Meeting-BaaS/twenty

Length of output: 4967


Don’t hardcode both media flags to false here. Every repeated bot.completed will re-download and re-upload any returned audio/video. This query shape doesn’t include existing media presence, so derive the flags from a richer record fetch or move the skip logic into ingestCallRecordingMediaFromUrls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/flows/handle-meeting-baas-webhook.util.ts`
around lines 79 - 89, The `handleMeetingBaasWebhook` completion path is
hardcoding `hasAudio` and `hasVideo` to false, which causes
`ingestCallRecordingMediaFromUrls` to reprocess media on repeated
`bot.completed` events. Update this flow so the flags come from a richer
`callRecording` fetch that includes existing media presence, or move the
dedup/skip check into `ingestCallRecordingMediaFromUrls` itself; use the `status
=== CallRecordingStatus.COMPLETED` block and `ingestCallRecordingMediaFromUrls`
call as the main fix points.

Comment on lines +60 to +70
return {
success: true,
config: {
apiKey,
baseUrl: normalizeBaseUrl(rawBaseUrl),
botName: isNonEmptyString(rawBotName)
? rawBotName.trim()
: DEFAULT_CALL_RECORDER_NAME,
callbackUrl: callbackUrl.trim(),
callbackSecret,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Inconsistent trimming of apiKey and callbackSecret.

callbackUrl and botName are trimmed, but apiKey and callbackSecret are returned as-is. A trailing newline/space (common when copying secrets into env config) would flow into the x-meeting-baas-api-key header and into the x-mb-secret comparison, causing hard-to-diagnose auth failures. Trim them for consistency unless whitespace is intentionally significant.

♻️ Proposed fix
     config: {
-      apiKey,
+      apiKey: apiKey.trim(),
       baseUrl: normalizeBaseUrl(rawBaseUrl),
       botName: isNonEmptyString(rawBotName)
         ? rawBotName.trim()
         : DEFAULT_CALL_RECORDER_NAME,
       callbackUrl: callbackUrl.trim(),
-      callbackSecret,
+      callbackSecret: callbackSecret.trim(),
     },
📝 Committable suggestion

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

Suggested change
return {
success: true,
config: {
apiKey,
baseUrl: normalizeBaseUrl(rawBaseUrl),
botName: isNonEmptyString(rawBotName)
? rawBotName.trim()
: DEFAULT_CALL_RECORDER_NAME,
callbackUrl: callbackUrl.trim(),
callbackSecret,
},
return {
success: true,
config: {
apiKey: apiKey.trim(),
baseUrl: normalizeBaseUrl(rawBaseUrl),
botName: isNonEmptyString(rawBotName)
? rawBotName.trim()
: DEFAULT_CALL_RECORDER_NAME,
callbackUrl: callbackUrl.trim(),
callbackSecret: callbackSecret.trim(),
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/get-meeting-baas-api-config.util.ts`
around lines 60 - 70, The config builder in get-meeting-baas-api-config.util.ts
returns apiKey and callbackSecret without trimming, unlike botName and
callbackUrl. Update the returned config object to normalize these two values
with trim() before use so the x-meeting-baas-api-key header and x-mb-secret
comparison do not include accidental whitespace; keep the change localized to
the getMeetingBaasApiConfig logic and preserve the existing fallback behavior
for botName.

return result;
}

return { ok: true, bot: result.data?.data ?? {} };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not treat missing bot payload as success.

Line 32 currently returns success with {} when result.data?.data is absent. That hides malformed API responses and can derail convergence logic that expects real bot state.

Suggested fix
-  return { ok: true, bot: result.data?.data ?? {} };
+  if (!result.data?.data) {
+    return {
+      ok: false,
+      status: result.status,
+      errorMessage:
+        'Meeting BaaS returned success without data.data for bot details',
+    };
+  }
+
+  return { ok: true, bot: result.data.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.

Suggested change
return { ok: true, bot: result.data?.data ?? {} };
if (!result.data?.data) {
return {
ok: false,
status: result.status,
errorMessage:
'Meeting BaaS returned success without data.data for bot details',
};
}
return { ok: true, bot: result.data.data };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/get-meeting-baas-bot.util.ts`
at line 32, The getMeetingBaasBot result handling currently treats a missing
payload as success by returning an empty bot object, which can mask malformed
responses. Update the get-meeting-baas-bot.util.ts logic around
getMeetingBaasBot so that only a real bot payload from result.data?.data returns
ok: true, and any absent/invalid payload is returned as a failure instead of
defaulting to {}. Keep the response shape aligned with the existing bot/result
types used by this utility.

Comment on lines +28 to +35
const response = await fetch(`${config.baseUrl}${path}`, {
method,
headers: {
'content-type': 'application/json',
'x-meeting-baas-api-key': config.apiKey,
},
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Does AbortSignal.timeout have support in Node.js fetch and what Node version introduced it?

💡 Result:

Yes, AbortSignal.timeout is supported in Node.js and can be used with the native fetch API [1][2][3]. The AbortSignal.timeout(delay) method was introduced in Node.js versions 17.3.0 and 16.14.0 [1][4]. When using this with fetch, the signal will abort the request once the specified delay has passed, causing the fetch promise to reject with a TimeoutError DOMException [2][5][3]. While support exists, users have occasionally reported issues regarding the integration of AbortSignal.timeout with certain fetch implementations or edge-case behaviors in older versions [6]. As of modern Node.js versions, it is a standard way to implement timeouts for network requests [1][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect repository files that may define the runtime and existing timeout patterns.
git ls-files | rg '(^|/)(package\.json|tsconfig\.json|\.nvmrc|\.node-version|README\.md|package-lock\.json|pnpm-lock\.yaml|yarn.lock)$' || true

printf '\n--- package.json candidates ---\n'
for f in $(git ls-files | rg '(^|/)package\.json$'); do
  echo "### $f"
  sed -n '1,220p' "$f" | rg -n '"engines"|"node"|AbortSignal|fetch' || true
  echo
done

printf '\n--- direct timeout usage around meeting-baas request helper ---\n'
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/meeting-baas-api-request.util.ts

Repository: Meeting-BaaS/twenty

Length of output: 24793


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where this logic-function package declares its runtime assumptions.
fd -a -t f 'package.json|.nvmrc|.node-version|README.md' packages/twenty-apps/public/call-recorder . 2>/dev/null || true

printf '\n--- search for Node/runtime references ---\n'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/.git/**' \
  'AbortSignal\.timeout|AbortController|fetch\(|node\s+version|engines|runtime|nodejs|node\.js' \
  packages/twenty-apps/public/call-recorder . 2>/dev/null | sed -n '1,220p'

Repository: Meeting-BaaS/twenty

Length of output: 32391


Add a timeout to the Meeting BaaS request

packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/meeting-baas-api-request.util.ts runs on Node ^24.5.0, so AbortSignal.timeout(...) is available here. Attach a signal so slow or unresponsive upstream calls fail fast instead of hanging the logic-function.

🛠️ Suggested change
     const response = await fetch(`${config.baseUrl}${path}`, {
       method,
       headers: {
         'content-type': 'application/json',
         'x-meeting-baas-api-key': config.apiKey,
       },
+      signal: AbortSignal.timeout(30_000),
       ...(body === undefined ? {} : { body: JSON.stringify(body) }),
     });
📝 Committable suggestion

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

Suggested change
const response = await fetch(`${config.baseUrl}${path}`, {
method,
headers: {
'content-type': 'application/json',
'x-meeting-baas-api-key': config.apiKey,
},
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
const response = await fetch(`${config.baseUrl}${path}`, {
method,
headers: {
'content-type': 'application/json',
'x-meeting-baas-api-key': config.apiKey,
},
signal: AbortSignal.timeout(30_000),
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/meeting-baas-api-request.util.ts`
around lines 28 - 35, The Meeting BaaS fetch in meeting-baas-api-request.util.ts
currently has no timeout, so slow upstream calls can hang the logic-function.
Update the request in the request helper that builds the fetch options to attach
an AbortSignal created with AbortSignal.timeout(...), and pass it as the signal
alongside method, headers, and optional body. Keep the change localized to the
request utility so all Meeting BaaS calls fail fast consistently.

Comment on lines +77 to +85
const externalBotId = result.data?.data?.bot_id;

if (isUndefined(externalBotId)) {
return {
ok: false,
status: null,
errorMessage:
'Meeting BaaS created a scheduled bot but did not return data.bot_id',
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate data.bot_id as a non-empty string.

Line 79 only rejects undefined; invalid runtime values like '' (and null) can be accepted as externalBotId, causing downstream API operations to fail.

Suggested fix
-  const externalBotId = result.data?.data?.bot_id;
-
-  if (isUndefined(externalBotId)) {
+  const externalBotId = result.data?.data?.bot_id;
+  if (!isNonEmptyString(externalBotId)) {
     return {
       ok: false,
       status: null,
       errorMessage:
         'Meeting BaaS created a scheduled bot but did not return data.bot_id',
     };
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-api/schedule-meeting-baas-bot.util.ts`
around lines 77 - 85, In schedule-meeting-baas-bot.util.ts, the external bot ID
check only rejects undefined, so `result.data?.data?.bot_id` can still be null
or an empty string and later break downstream API calls. Update the validation
around `externalBotId` to require a non-empty string before returning success,
and keep the existing error return path when the value is missing or invalid.

);
}

if (routePayload.headers['x-mb-secret'] !== webhookSecret) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP "timingSafeEqual|from ['\"]crypto['\"]|require\(['\"]crypto['\"]\)" packages/twenty-apps/public/call-recorder/src
fd -e ts . packages/twenty-apps/public/call-recorder/src/logic-functions/utils | xargs rg -ln "secret|compare" 2>/dev/null

Repository: Meeting-BaaS/twenty

Length of output: 974


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-webhook.ts
printf '\n---\n'
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/recall-api/verify-recall-webhook-signature.util.ts
printf '\n---\n'
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/__tests__/recall-webhook.test.ts

Repository: Meeting-BaaS/twenty

Length of output: 10789


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-webhook.ts
printf '\n---\n'
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/recall-api/verify-recall-webhook-signature.util.ts
printf '\n---\n'
sed -n '1,220p' packages/twenty-apps/public/call-recorder/src/logic-functions/__tests__/recall-webhook.test.ts

Repository: Meeting-BaaS/twenty

Length of output: 10789


Use a constant-time comparison for x-mb-secret. crypto.timingSafeEqual is already available in this package, so compare equal-length buffers instead of !==.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-webhook.ts`
at line 33, The x-mb-secret check in meeting-baas-webhook should use a
constant-time comparison instead of a direct string inequality. Update the
secret validation logic in the webhook handler to convert both values to
equal-length buffers and compare them with crypto.timingSafeEqual, keeping the
existing webhookSecret and routePayload.headers['x-mb-secret'] flow intact.

name: 'meeting-baas-webhook',
description:
'Receives Meeting BaaS webhook events and updates the matching CallRecording lifecycle status.',
timeoutSeconds: 30,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

timeoutSeconds: 30 is shorter than downstream media/transcript timeouts (120s), so COMPLETED events can be force-aborted.

On COMPLETED, the handler downloads audio/video (MEDIA_DOWNLOAD_TIMEOUT_MS = 120_000) and fetches the transcript (AbortSignal.timeout(120_000) in handle-meeting-baas-webhook.util.ts Line 178), each sequentially. With a 30s function budget, the logic function can be terminated mid-ingestion, leaving the recording partially updated and never reaching updateCallRecording. Align the budget with the internal timeouts (raise timeoutSeconds, or lower the download/fetch timeouts to fit within it).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/meeting-baas-webhook.ts`
at line 52, The webhook handler in meeting-baas-webhook is using a function
timeout that is shorter than the internal COMPLETED ingestion work, so adjust
the budget to match the downstream media and transcript timeouts or reduce those
internal timeouts accordingly. Update the logic around the webhook entrypoint
and the COMPLETED path that calls the media download and transcript fetch
helpers so the total execution window safely covers both sequential steps before
updateCallRecording runs.

CALL_RECORDER_PROVIDER_ENV_VAR_NAME,
);

return rawProvider === 'meeting-baas' ? 'meeting-baas' : 'recall';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Normalize the raw provider before matching to avoid silent fallback.

A value like ' meeting-baas' (stray whitespace) or 'Meeting-BaaS' will not equal 'meeting-baas' and silently resolves to 'recall', sending the operator down the wrong provider path without any signal. Trim and lowercase before comparing.

♻️ Proposed normalization
-  return rawProvider === 'meeting-baas' ? 'meeting-baas' : 'recall';
+  return rawProvider?.trim().toLowerCase() === 'meeting-baas'
+    ? 'meeting-baas'
+    : 'recall';
📝 Committable suggestion

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

Suggested change
return rawProvider === 'meeting-baas' ? 'meeting-baas' : 'recall';
return rawProvider?.trim().toLowerCase() === 'meeting-baas'
? 'meeting-baas'
: 'recall';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/twenty-apps/public/call-recorder/src/logic-functions/providers/get-call-recorder-provider.util.ts`
at line 10, Normalize the provider input inside getCallRecorderProvider by
trimming whitespace and converting to lowercase before the comparison, so values
like stray-spaced or differently cased meeting-baas still resolve correctly.
Update the matching logic around the rawProvider return path to compare against
the normalized value rather than the original string, and keep the fallback to
recall only for truly unknown providers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant