Skip to content

Migrate getExternalRecordingS3Location and getMediaUrl serverless endpoints to lambdas/account-scoped#3991

Merged
stephenhand merged 5 commits intomasterfrom
copilot/migrate-twilio-endpoints
Mar 6, 2026
Merged

Migrate getExternalRecordingS3Location and getMediaUrl serverless endpoints to lambdas/account-scoped#3991
stephenhand merged 5 commits intomasterfrom
copilot/migrate-twilio-endpoints

Conversation

Copy link
Contributor

Copilot AI commented Mar 3, 2026

Migrates two asset download Twilio serverless functions into lambdas/account-scoped/src/conversation/, following the same pattern established by other recent migrations (e.g. getTaskAndReservations). Also adds a feature flag and a new recordingsService module in plugin-hrm-form to support gradual rollout of the migrated endpoints.

Description

lambdas/account-scoped

  • @tech-matters/twilio-configuration: Added getDocsBucketName(accountSid) — retrieves S3 docs bucket name from SSM at /${NODE_ENV}/s3/${accountSid}/docs_bucket_name

  • conversation/getExternalRecordingS3Location: Lists Twilio recordings for a callSid; returns { recordingSid, key, bucket } where key = voice-recordings/${accountSid}/${recordingSid}. Returns 404/409 for missing or ambiguous recordings.

  • conversation/getMediaUrl: Authenticates against the Twilio MCS API using account SID + auth token (Basic Auth) and returns the content_direct_temporary URL for a given serviceSid/mediaSid.

  • router.ts: Both routes registered under conversation/ with validateFlexTokenRequest({ tokenMode: 'agent' }) — matching the TokenValidator wrapper in the original serverless versions.

  • Unit tests added for both handlers.

plugin-hrm-form

  • FeatureFlags.ts: Added use_twilio_lambda_for_recordings_lookup boolean flag.

  • services/recordingsService.ts (new module, consolidates getExternalRecordingInfo.ts + recording API calls): Contains getMediaUrl, internal getExternalRecordingS3Location, and all logic previously in getExternalRecordingInfo.ts. Both API functions route to the migrated lambda endpoints (/conversation/getMediaUrl, /conversation/getExternalRecordingS3Location) when use_twilio_lambda_for_recordings_lookup is enabled, or to the legacy serverless endpoints otherwise.

  • services/ServerlessService.ts: Removed getExternalRecordingS3Location and getMediaUrl (moved to recordingsService).

  • services/getExternalRecordingInfo.ts: Deleted — contents consolidated into recordingsService.ts.

  • Updated all callers (ContactService.ts, InsightsService.ts, formSubmissionHelpers.ts, MessageItem.tsx) to import from recordingsService.ts.

  • Unit tests added for feature-flag routing of both getMediaUrl and getExternalRecordingS3Location (via getExternalRecordingInfo).

  • ContactService.test.ts: Fixed the recordingsService mock so that getExternalRecordingInfo returns a failure result when the task has no conference attribute, restoring the behaviour the test relied on before the refactor.

Checklist

  • Corresponding issue has been opened
  • New tests added
  • Feature flags added
  • Strings are localized
  • Tested for chat contacts
  • Tested for call contacts

Other Related Issues

None

Verification steps

  • Deploy to a dev environment and call POST /lambda/twilio/account-scoped/{accountSid}/conversation/getExternalRecordingS3Location with a valid callSid (and a Flex token) — expect { recordingSid, key, bucket }.
  • Call POST /lambda/twilio/account-scoped/{accountSid}/conversation/getMediaUrl with valid serviceSid + mediaSid — expect a temporary direct media URL string.
  • Enable the use_twilio_lambda_for_recordings_lookup feature flag and verify that voice recording lookups and media URLs in the plugin resolve correctly via the new lambda endpoints.
  • Disable the flag and verify the legacy serverless endpoints are used instead.

AFTER YOU MERGE

  1. Cut a release tag using the Github workflow. Wait for it to complete and notify in the #aselo-deploys Slack channel.
  2. Comment on the ticket with the release tag version AND any additional instructions required to configure an environment to test the changes.
  3. Only then move the ticket into the QA column in JIRA

You are responsible for ensuring the above steps are completed. If you move a ticket into QA without advising what version to test, the QA team will assume the latest tag has the changes. If it does not, the following confusion is on you! :-P

Original prompt

This section details on the original issue you should resolve

<issue_title>Migrate the asset download serverless endpoints into the lambdas/account-scoped</issue_title>
<issue_description>## Description

Migrate the following 2 twilio serverless endpoints into the lambdas/account-scoped

https://github.com/techmatters/serverless/blob/master/functions/getExternalRecordingS3Location.ts
https://github.com/techmatters/serverless/blob/master/functions/getMediaUrl.ts

Place them in the 'conversation' directory

Additional context

Follow the same patterns as for other endpoints that have been migrated

For example, https://github.com/techmatters/serverless/blob/master/functions/getTaskAndReservations.ts was recently migrated to https://github.com/techmatters/flex-plugins/blob/master/lambdas/account-scoped/src/task/getTaskAndReservations.ts

Note how when a TokenValidator wrapper is used in the serverless version, a validateFlexTokenRequest item needs to be added to the request pipeline for the route in account-scoped
</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

…points to lambdas/account-scoped/conversation

Co-authored-by: stephenhand <1694716+stephenhand@users.noreply.github.com>
Copilot AI changed the title [WIP] Migrate Twilio serverless endpoints to account-scoped Lambdas Migrate getExternalRecordingS3Location and getMediaUrl serverless endpoints to lambdas/account-scoped Mar 3, 2026
Copy link
Collaborator

@stephenhand stephenhand left a comment

Choose a reason for hiding this comment

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

Add a feature flag to plugin-hrm-form called use_twilio_lambda_for_recordings_lookup

Use this flag to determine whether the getMediaUrl and getExternalRecordingS3Location methods in ServerlessService.ts should send to the legacy endpoint or the migrated endpoint. It should send to the migrated endpoint if set

Consolidate these two methods and the contents of the getExternalRecordingS3Location.ts files into a new recordingsService module. The getExternalRecordingS3Location migrated from serverless service will no longer need to be exported from the module

…rding logic into recordingsService

Co-authored-by: stephenhand <1694716+stephenhand@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 4, 2026

Add a feature flag to plugin-hrm-form called use_twilio_lambda_for_recordings_lookup

Use this flag to determine whether the getMediaUrl and getExternalRecordingS3Location methods in ServerlessService...

Done in commit 5d24b05:

  • Added use_twilio_lambda_for_recordings_lookup to FeatureFlags.ts
  • Created plugin-hrm-form/src/services/recordingsService.ts consolidating getMediaUrl, internal getExternalRecordingS3Location, and all the logic from getExternalRecordingInfo.ts — both API functions use the feature flag to route to the lambda (/conversation/getMediaUrl, /conversation/getExternalRecordingS3Location) or the legacy serverless endpoint
  • Deleted getExternalRecordingInfo.ts; removed getExternalRecordingS3Location and getMediaUrl from ServerlessService.ts
  • Updated all callers (ContactService.ts, InsightsService.ts, formSubmissionHelpers.ts, MessageItem.tsx) to import from recordingsService.ts
  • Added recordingsService.test.ts covering the feature-flag routing for both getMediaUrl and getExternalRecordingS3Location (via getExternalRecordingInfo)

# Conflicts:
#	lambdas/account-scoped/src/router.ts
#	plugin-hrm-form/src/types/FeatureFlags.ts
Copy link
Collaborator

@stephenhand stephenhand left a comment

Choose a reason for hiding this comment

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

The following unit test is failing :

handleTwilioTask() (externalRecording) should return conversationMedia with correct data if external recording is enabled

…e when no conference

Co-authored-by: stephenhand <1694716+stephenhand@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 6, 2026

The following unit test is failing :

handleTwilioTask() (externalRecording) should return conversationMedia with correct data if external recording is enabled

Fixed in commit 3b5ad6c. The mock for recordingsService in ContactService.test.ts was too simplistic — it always returned success from getExternalRecordingInfo. The second test expects no external recording info when the task has no conference, which the old code handled naturally because only getExternalRecordingS3Location was mocked and the real getExternalRecordingInfo logic ran. Updated the mock to check task?.attributes?.conference and return a failure result when there's no conference, matching the original behavior.

@stephenhand stephenhand marked this pull request as ready for review March 6, 2026 11:47
@stephenhand stephenhand merged commit 245db0f into master Mar 6, 2026
80 checks passed
@stephenhand stephenhand deleted the copilot/migrate-twilio-endpoints branch March 6, 2026 19:23
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.

Migrate the asset download serverless endpoints into the lambdas/account-scoped

2 participants