Skip to content

feat(datachannel): add update subchannel subscriptions function#4749

Merged
JudyZhuHz merged 21 commits intowebex:nextfrom
Tianhui-Han:feat/datachannel_update_sub_datachannel_subscriptions
Mar 25, 2026
Merged

feat(datachannel): add update subchannel subscriptions function#4749
JudyZhuHz merged 21 commits intowebex:nextfrom
Tianhui-Han:feat/datachannel_update_sub_datachannel_subscriptions

Conversation

@Tianhui-Han
Copy link
Copy Markdown
Contributor

@Tianhui-Han Tianhui-Han commented Mar 4, 2026

Add update subchannel subscriptions function

IMPORTANT
FAILING TO FILL OUT THIS TEMPLATE WILL RESULT IN REJECTION OF YOUR PULL REQUEST
This is for compliance purposes with FedRAMP program.
-->

COMPLETES #< INSERT LINK TO ISSUE >

This pull request addresses

https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-763776

by making the following changes

  • Added support for JWT‑based datachannel connection (token + URL), enabling proper authorization and subchannel permissions.
  • Added datachannel‑token interceptors to handle reconnection, token refresh, and token‑expiration detection.
  • Added subscribe/unsubscribe APIs for subchannels and implemented the full subscription‑aware design.
  • Ensured subscription state reflects user intent (UI open/close) rather than host state, fixing the issue where captions returned unexpectedly.

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

< ENUMERATE TESTS PERFORMED, WHETHER MANUAL OR AUTOMATED >

The GAI Coding Policy And Copyright Annotation Best Practices

  • GAI was not used (or, no additional notation is required)
  • Code was generated entirely by GAI
  • GAI was used to create a draft that was subsequently customized or modified
  • Coder created a draft manually that was non-substantively modified by GAI (e.g., refactoring was performed by GAI on manually written code)
  • Tool used for AI assistance (GitHub Copilot / Other - specify)
    • Github Copilot
    • Other - Please Specify
  • This PR is related to
    • Feature
    • Defect fix
    • Tech Debt
    • Automation

I certified that

  • I have read and followed contributing guidelines
  • I discussed changes with code owners prior to submitting this pull request
  • I have not skipped any automated checks
  • All existing and new tests passed
  • I have updated the documentation accordingly

Make sure to have followed the contributing guidelines before submitting.

@Tianhui-Han Tianhui-Han requested review from a team as code owners March 4, 2026 06:47
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c3c22b4ce0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +590 to +593
public updateSubchannelSubscriptions = ({
subscribe = [],
unsubscribe = [],
}: {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle undefined options in updateSubchannelSubscriptions

This destructuring requires an argument object, so calling updateSubchannelSubscriptions() from JavaScript (or any untyped call path) throws a runtime TypeError before the isConnected() guard runs. Because the method already provides defaults for subscribe/unsubscribe, callers reasonably expect the no-arg form to behave like an empty update rather than crash; adding a default for the whole parameter (e.g., {}) avoids this production failure mode.

Useful? React with 👍 / 👎.

@aws-amplify-us-east-2
Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-4749.d3m3l2kee0btzx.amplifyapp.com

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d04435fcf4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +120 to +121
const connectUrl = this.isDataChannelTokenEnabled()
? LLMChannel.buildUrlWithAwareSubchannels(this.webSocketUrl, AWARE_DATA_CHANNEL)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Await token feature gate before selecting connect URL

isDataChannelTokenEnabled() returns a Promise<boolean>, but it is used directly in a ternary, so the condition is always truthy and buildUrlWithAwareSubchannels() runs even when the developer feature flag resolves to false. In environments where the flag is disabled, clients will still connect with subscriptionAwareSubchannels appended, which defeats the intended rollout gate and can change server behavior for all connections on this path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 84acaf49a0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

sessionData.datachannelToken = datachannelToken;
this.connections.set(sessionId, sessionData);

const connectUrl = isDataChannelTokenEnabled
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Resolve feature gate before URL selection

In registerAndConnect, the ternary reads isDataChannelTokenEnabled even though that identifier is not defined in this scope, so calling this method with valid locusUrl/datachannelUrl will throw a runtime ReferenceError before connect() runs. Because no-undef is disabled for TypeScript in this repo, this can slip through linting and break all LLM connection attempts on this path.

Useful? React with 👍 / 👎.

Comment on lines +137 to +139
const connectUrl = isDataChannelTokenEnabled
? LLMChannel.buildUrlWithAwareSubchannels(this.webSocketUrl, AWARE_DATA_CHANNEL)
: this.webSocketUrl;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pass subscription-aware URL into connect

This block computes connectUrl with subscriptionAwareSubchannels, but the method still calls connect(sessionData.webSocketUrl, sessionId), so the new query parameter is never actually used. In environments expecting this flag-controlled URL decoration, clients will continue connecting with the unmodified WebSocket URL and the new feature will not take effect.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9ac617cb11

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@@ -0,0 +1,16 @@
import * as jose from 'jose';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Declare jose in plugin-meetings runtime dependencies

isJwtTokenExpired now imports jose, but @webex/plugin-meetings does not declare jose in its dependencies (it only appears in packages/byods/package.json), so published consumers that install meetings without byods can hit Cannot find module 'jose' as soon as this interceptor module is loaded. Please add jose to packages/@webex/plugin-meetings/package.json so this new runtime import is always resolvable.

Useful? React with 👍 / 👎.

return this.connect(sessionData.webSocketUrl, sessionId);
const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();

const connectUrl = isDataChannelTokenEnabled
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should be isDataChannelTokenEnabled && datachannelToken, not noly the toggle is on but also the token is used when registration

* @param {string[]} options.unsubscribe Sub‑channels to unsubscribe from.
* @returns {void}
*/
public updateSubchannelSubscriptions = ({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When the function is called?

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

return this.internal.llm.isDataChannelTokenEnabled();
},
refreshDataChannelToken: async () => {
// @ts-ignore
const {body} = await this.internal.llm.refreshDataChannelToken();

P1 Badge Read LLM state from webex.internal, not this.internal

static create() captures this.internal.llm, but interceptors are instantiated via Reflect.apply(interceptor, this, []) on each plugin instance, and WebexPlugin exposes the root SDK object as this.webex rather than this.internal. On request paths that carry Data-Channel-Auth-Token, these callbacks can therefore throw when they try to dereference this.internal.llm, which means the new refresh logic never gets a chance to update the token before the request/retry runs.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +644 to +646
const dataChannelToken = this.webex.internal.llm.getDatachannelToken('default');
// @ts-ignore
if (!this.webex.internal.llm.isConnected() || !isDataChannelTokenEnabled || !dataChannelToken)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use the active LLM session for subchannel subscriptions

updateSubchannelSubscriptions() hard-codes the default LLM session (getDatachannelToken('default'), isConnected(), llm.socket, getDatachannelUrl()), but Voicea already routes publish traffic through LLM_PRACTICE_SESSION when that is the active connection. In webinar practice-session flows where only the practice-session data channel is connected, this method now returns early or targets the wrong socket, so requestTurnOnCaptions() never applies the new subchannelSubscriptionRequest and transcription will not be subscribed for that session.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c853f0c83e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines 463 to 464
this.updateSubchannelSubscriptions({subscribe: ['transcription']});
this.announce();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Await subchannel subscription before announcing

When data-channel-with-jwt-token is enabled, updateSubchannelSubscriptions() does not send synchronously: it awaits isDataChannelTokenEnabled() before emitting subchannelSubscriptionRequest. Because it is fire-and-forget here, announce() on the next line always runs first, so Voicea can start publishing transcription before this client has subscribed on a subscription-aware socket. That drops the initial caption events right after turning captions on.

Useful? React with 👍 / 👎.


this.areCaptionsEnabled = true;
this.captionStatus = TURN_ON_CAPTION_STATUS.ENABLED;
this.updateSubchannelSubscriptions({subscribe: ['transcription']});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Re-subscribe after opening a replacement LLM socket

This is the only place the new subchannelSubscriptionRequest is triggered. Later LLM connections created by Mercury reconnects or by Webinar.updatePSDataChannel() bring up a fresh websocket, but they only call voicea.announce() and never re-run updateSubchannelSubscriptions(). Since the subscription request is sent over the websocket, it is scoped to that socket; after a network flap or practice-session handoff, the replacement connection stays unsubscribed to transcription until the user toggles captions again.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5cc969c481

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


const finalToken = currentToken ?? practiceSessionDatachannelToken;

const isCaptionEnabled = this.webex.internal.voicea.getIsCaptionEnabled();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Derive practice-session resubscribe from current meeting state

getIsCaptionEnabled() now drives whether updatePSDataChannel() replays a transcription subscription, but the new VoiceaChannel.isCaptionEnabled flag is only set in updateSubchannelSubscriptionsAndSyncCaptionState() and is never cleared in voicea.deregisterEvents(). Because VoiceaChannel is a singleton internal plugin, once a user enables captions in one meeting/rejoin, later webinar practice-session reconnects will still enter this branch even when captions are off in the current meeting, leaking caption opt-in across sessions and potentially subscribing a fresh meeting to transcription unexpectedly.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 43c801c06b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +224 to +225
if (isCaptionBoxOn) {
this.webex.internal.voicea.updateSubchannelSubscriptions({subscribe: ['transcription']});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Derive practice-session resubscribe from live transcribe state

Fresh evidence after the earlier deregisterEvents() fix: this branch still keys resubscribe off voicea.getIsCaptionBoxOn(), but that flag is only updated when this client turns captions on. In the same meeting, meeting/index.ts's CONTROLS_MEETING_TRANSCRIBE_UPDATED handler only emits MEETING_STOPPED_RECEIVING_TRANSCRIPTION when {transcribing:false} and never clears the Voicea flag, so if captions are later disabled by the host and the practice-session socket reconnects, updatePSDataChannel() will still re-subscribe transcription on the new socket even though the current locus controls say transcription is off.

Useful? React with 👍 / 👎.

Comment on lines +654 to +664
this.webex.internal.llm.socket.send({
id: `${this.seqNum}`,
type: 'subchannelSubscriptionRequest',
data: {
// @ts-ignore
datachannelUri: this.webex.internal.llm.getDatachannelUrl(),
subscribe,
unsubscribe,
},
trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Return the Mercury send promise from subchannel updates

updateSubchannelSubscriptions() is declared async, but it drops the promise from llm.socket.send(...). Mercury's send() resolves asynchronously and rejects with INVALID_STATE_ERROR when the socket is no longer open, so any close/reconnect race after the feature-flag await will surface as an unhandled rejection while callers still observe await updateSubchannelSubscriptions() as success. That makes reconnect resubscribe logic believe the subscription request was sent even when it never left the client.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2a26e82a0e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

this.areCaptionsEnabled = true;
this.captionStatus = TURN_ON_CAPTION_STATUS.ENABLED;
this.announce();
this.updateSubchannelSubscriptionsAndSyncCaptionState({subscribe: ['transcription']}, true);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Send an unsubscribe when transcription is turned off

This new subchannel flow only ever opts the socket into transcription: this call and webinar/index.ts:223-226 both send subscribe:['transcription'], but there is no production path that passes unsubscribe:['transcription'], and meeting/index.ts#stopTranscription() still just removes listeners. On a subscription-aware socket, once a user has enabled captions once, a host stop/start cycle or any local stop path that leaves the websocket open keeps that socket subscribed, so captions will start flowing again on the same connection even though the user has turned them off.

Useful? React with 👍 / 👎.

@Tianhui-Han Tianhui-Han force-pushed the feat/datachannel_update_sub_datachannel_subscriptions branch from 2a26e82 to 43c801c Compare March 23, 2026 06:51
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 43c801c06b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +88 to +90
if (isJwtTokenExpired(token)) {
try {
const newToken = await this._refreshDataChannelToken();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Pass request context into the pre-send token refresh

onRequest() now refreshes any Data-Channel-Auth-Token that is within the 30s buffer, but _refreshDataChannelToken() still has no request/session context: DataChannelAuthTokenInterceptor.create() delegates to the single global LLM refresh handler, and Meeting.refreshDataChannelToken() chooses the token type from current meeting/practice-session state rather than from the request being refreshed. In practice-session webinars (default + practice sockets) or when two meetings are open, this can rewrite a healthy default-session registration request with the practice-session/other-meeting token before the server has even rejected the original header, causing otherwise valid reconnects to fail.

Useful? React with 👍 / 👎.

mickelr

This comment was marked as abuse.

mickelr
mickelr previously approved these changes Mar 23, 2026
mickelr

This comment was marked as abuse.

@mickelr mickelr self-requested a review March 23, 2026 07:23
@mickelr mickelr dismissed their stale review March 23, 2026 07:24

waiting for sdk team reveiw

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8cadca8ca1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +647 to +651
const isDataChannelTokenEnabled = await this.webex.internal.llm.isDataChannelTokenEnabled();
// @ts-ignore
const dataChannelToken = this.webex.internal.llm.isLLMWithDataChannelToken();
// @ts-ignore
if (!this.isLLMConnected() || !isDataChannelTokenEnabled || !dataChannelToken) return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Check the publish session, not any session, for a JWT token

isLLMWithDataChannelToken() only asks whether any LLM session has a stored token, but updateSubchannelSubscriptions() sends on the current publish transport. In webinar handoffs we can still connect the practice-session socket with finalToken === undefined (packages/@webex/plugin-meetings/src/webinar/index.ts), while the default session remains connected with its own token; this branch then sends a subchannelSubscriptionRequest on a practice-session socket that was never opened with subscriptionAwareSubchannels. In that mixed-token state, the call looks successful but captions never get subscribed on the practice-session connection.

Useful? React with 👍 / 👎.

Comment on lines 223 to +225
this.webex.internal.voicea?.announce?.();
if (isCaptionBoxOn) {
this.webex.internal.voicea.updateSubchannelSubscriptions({subscribe: ['transcription']});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Await practice-session subchannel subscribe before announce

When captions are already on and updatePSDataChannel() reconnects the practice-session socket, announce() runs before the new subscription request is even started. updateSubchannelSubscriptions() is asynchronous because it awaits the feature gate in packages/@webex/internal-plugin-voicea/src/voicea.ts:647-651, so on JWT-enabled data channels the fresh socket can begin receiving Voicea traffic before transcription has been subscribed. That drops the first caption events after a practice-session reconnect until a later message arrives.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b1f199ff0d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

'llm#refreshDataChannelToken --> LLM refreshHandler is not set, skipping token refresh'
);

return null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve refreshDataChannelToken rejection semantics

refreshDataChannelToken() now resolves null when no handler is set or the refresh handler fails, but the interceptor still consumes it as const {body} = await this.internal.llm.refreshDataChannelToken() in packages/@webex/plugin-meetings/src/interceptors/dataChannelAuthToken.ts. When an expired token reaches this path (for example after a locus change/leave), the flow now throws a runtime destructuring TypeError instead of following the prior refresh-error path, which breaks caller assumptions and turns token refresh failures into accidental runtime errors; either keep rejecting here or update callers to explicitly handle null.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5b3b5a2c37

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


const finalToken = currentToken ?? practiceSessionDatachannelToken;

const isCaptionBoxOn = this.webex.internal.voicea.getIsCaptionBoxOn();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Guard optional Voicea plugin before reading caption intent

updatePSDataChannel() now calls this.webex.internal.voicea.getIsCaptionBoxOn() unconditionally, but this same block still treats Voicea as optional (this.webex.internal.voicea?.announce?.()). In environments where the Voicea child plugin is not registered (or during version skew where that method is absent), this throws a runtime TypeError before the practice-session data channel reconnect completes, breaking webinar practice-session updates instead of safely no-oping.

Useful? React with 👍 / 👎.

@mickelr mickelr added the validated If the pull request is validated for automation. label Mar 25, 2026
@JudyZhuHz JudyZhuHz merged commit 20103a6 into webex:next Mar 25, 2026
12 checks passed
fnowakow pushed a commit to fnowakow/webex-js-sdk that referenced this pull request Mar 25, 2026
…x#4749)

Co-authored-by: mickelr <121160648+mickelr@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

validated If the pull request is validated for automation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants