Skip to content

Conversation

Shreyas281299
Copy link
Contributor

COMPLETES #< INSERT LINK TO ISSUE >

This pull request addresses

< DESCRIBE THE CONTEXT OF THE ISSUE >

by making the following changes

< DESCRIBE YOUR CHANGES >

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.

@Shreyas281299 Shreyas281299 requested a review from a team as a code owner August 12, 2025 17:54
Copy link
Contributor

coderabbitai bot commented Aug 12, 2025

📝 Walkthrough

Walkthrough

Adds a new “Calling Labs” entry to docs/index.html and introduces a complete Webex Calling WebRTC SDK lab under docs/labs/calling/. The lab includes an index.html UI, index.js controller, supporting modules for auth, registration, and call controls, and styles.css. It implements OAuth and PAT initialization, registration/deregistration, line registration, microphone/media wiring, outgoing/incoming calls, mute/hold, transfer (blind/consult), and DTMF (per-key and batch). A README documents lab goals, flow, OAuth setup, scopes, and usage details. No existing exported/public APIs in the main codebase are changed.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

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

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Shreyas281299 Shreyas281299 marked this pull request as draft August 12, 2025 17:54
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (13)
docs/labs/calling/styles.css (1)

24-30: Consider extracting magic numbers to CSS custom properties.

The padding, border radius, and color values are repeated throughout the stylesheet. Consider defining CSS custom properties for consistency and maintainability.

+:root {
+  --border-radius: 4px;
+  --border-radius-lg: 8px;
+  --padding-sm: 8px;
+  --padding-md: 12px;
+  --color-border: #ddd;
+  --color-primary: #00a6d6;
+  --color-accent: #1a73e8;
+}
+
 fieldset { border: 1px solid #ddd; border-radius: 6px; margin: 12px 0; padding: 12px; }
-legend { color: #1a73e8; font-weight: 600; }
+legend { color: var(--color-accent); font-weight: 600; }

 .s-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
-button { background:#00a6d6; color:#fff; border:none; border-radius:4px; padding:8px 12px; cursor:pointer; }
+button { background: var(--color-primary); color:#fff; border:none; border-radius: var(--border-radius); padding: var(--padding-sm) var(--padding-md); cursor:pointer; }
docs/labs/calling/modules/registration.js (1)

11-18: Remove debug console.log statements.

Console logging in production code can expose sensitive information and clutters the console output.

 export function getPrimaryLine(callingClient) {
   if (!callingClient) return undefined;
-  console.log('callingClient', callingClient);
   const lines = callingClient.getLines();
   const first = Object.values(lines)[0];
-  console.log('first', first);
   return first;
 }
docs/labs/calling/README.md (3)

14-23: Fix markdownlint MD040: add a language to the fenced code block.

Static analysis flagged MD040. Add a language (e.g., text) to the directory tree block.

Apply this diff:

-```
+```text
 docs/labs/calling/
 ├── index.html          # Lab UI
 ├── index.js            # Orchestration
 ├── styles.css          # Styles
 └── modules/
     ├── auth.js         # Initialization
     ├── registration.js # Register/deregister/line helpers
-    └── call-controls.js# Call control helpers (placeholder)
+    └── call-controls.js # Call control helpers

---

`20-22`: **Update comment: module is no longer a placeholder.**

The comment says “placeholder,” but call-controls.js implements dialpad, mute, and hold. Adjust the comment for accuracy (see diff in previous comment).

---

`50-86`: **Prefer Authorization Code + PKCE over Implicit for production OAuth.**

For production apps, Authorization Code with PKCE is recommended over the Implicit flow. Consider adding a short note here that the Implicit sample is for labs only, and point to the Code+PKCE guidance.

Optionally insert a note right after Line 52:

```diff
 For production, use OAuth instead of a PAT. Create an Integration at the Webex Developer Portal and configure:
+Note: For production SPAs, prefer the Authorization Code + PKCE flow over the Implicit flow for improved security (token handling, refresh, reduced exposure). The Implicit flow shown below is intended for this lab only.
docs/labs/calling/index.html (4)

9-11: Unify highlight.js versions and defer its loading.

CSS is 11.11.1 while JS is 11.7.0. Use the same version to avoid quirks. Also add defer to avoid blocking render.

Apply this diff:

-    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
+    <script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>

Also applies to: 20-20


14-19: Consider pinning Webex UMD to a stable version.

Using webex@next is non-deterministic and may break the lab unexpectedly. Pin to a known-good version and update intentionally.

Example:

-    <script src="https://unpkg.com/webex@next/umd/webex.min.js"></script>
+    <script src="https://unpkg.com/webex@<pinned-version>/umd/webex.min.js"></script>

176-176: Improve keyboard/mobile UX for destination field.

Use a telephone keypad for number/SIP entry and disable auto-features that can alter input.

Apply this diff:

-          <input id="destination" type="text" placeholder="Destination (SIP/phone)" />
+          <input
+            id="destination"
+            type="text"
+            placeholder="Destination (SIP/phone)"
+            inputmode="tel"
+            autocomplete="off"
+            autocapitalize="off"
+            autocorrect="off"
+            spellcheck="false"
+          />

227-227: Dialer UX: use tel input mode and limit allowed characters.

Helps ensure only valid DTMF characters are entered.

Apply this diff:

-          <input id="dtmf-display" type="text" placeholder="Digits" />
+          <input
+            id="dtmf-display"
+            type="text"
+            placeholder="Digits"
+            inputmode="tel"
+            pattern="[0-9*#]*"
+            autocomplete="off"
+            autocapitalize="off"
+            autocorrect="off"
+            spellcheck="false"
+          />
docs/labs/calling/index.js (4)

164-169: Cleanup remote media and incoming UI on disconnect.

Helps prevent stale audio elements and UI text after a call ends.

Apply this diff:

   call.on('disconnect', () => {
     els.callStatus.textContent = 'Call Disconnected';
     setCallUI(false);
     activeCall = undefined;
     resetTransferUI();
+    if (els.remoteAudio) els.remoteAudio.srcObject = null;
+    if (els.incomingInfo) els.incomingInfo.textContent = 'No incoming calls';
   });

72-91: Early validation for empty token on PAT init.

Short-circuit with a helpful status instead of relying on thrown errors.

Apply this diff:

 async function handleInit() {
   els.init.disabled = true;
   els.authStatus.textContent = 'Initializing...';
   const token = els.token.value.trim();
+  if (!token) {
+    els.authStatus.textContent = 'Please paste an access token or use OAuth.';
+    els.init.disabled = false;
+    return;
+  }
   try {
     const { callingInstance, client } = await initCalling({
       token,
       fedramp: !!els.fedramp.checked,
       useIntegration: !!els.intEnv.checked
     });

330-330: Drop stray console log.

Avoids noisy console output in the lab.

Apply this diff:

-  console.log('bindUI');

96-103: Hardcoded OAuth clientId is acceptable for labs; consider environment override.

For a lab, a placeholder is fine (per prior team learning), but optionally read from a query param or env to avoid editing source when testing different integrations.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d798015 and 0b4a684.

📒 Files selected for processing (8)
  • docs/index.html (1 hunks)
  • docs/labs/calling/README.md (1 hunks)
  • docs/labs/calling/index.html (1 hunks)
  • docs/labs/calling/index.js (1 hunks)
  • docs/labs/calling/modules/auth.js (1 hunks)
  • docs/labs/calling/modules/call-controls.js (1 hunks)
  • docs/labs/calling/modules/registration.js (1 hunks)
  • docs/labs/calling/styles.css (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-12-06T12:48:03.643Z
Learnt from: bhabalan
PR: webex/webex-js-sdk#4022
File: docs/samples/contact-center/app.js:116-118
Timestamp: 2024-12-06T12:48:03.643Z
Learning: In `docs/samples/contact-center/app.js`, hardcoding the OAuth client ID and secret is acceptable for testing purposes in an isolated sandbox environment.

Applied to files:

  • docs/labs/calling/README.md
🧬 Code Graph Analysis (4)
docs/labs/calling/modules/call-controls.js (1)
docs/labs/calling/index.js (2)
  • els (12-43)
  • call (220-220)
docs/labs/calling/modules/registration.js (1)
docs/labs/calling/index.js (2)
  • calling (5-5)
  • callingClient (6-6)
docs/labs/calling/modules/auth.js (1)
docs/labs/calling/index.js (3)
  • initCalling (77-81)
  • token (75-75)
  • token (322-322)
docs/labs/calling/index.js (3)
docs/labs/calling/modules/auth.js (3)
  • initCalling (1-41)
  • callingInstance (34-34)
  • initOauth (59-72)
docs/labs/calling/modules/registration.js (3)
  • register (1-4)
  • getPrimaryLine (11-18)
  • deregister (6-9)
docs/labs/calling/modules/call-controls.js (1)
  • setupCallControls (9-63)
🪛 markdownlint-cli2 (0.17.2)
docs/labs/calling/README.md

14-14: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: AWS Amplify Console Web Preview
🔇 Additional comments (17)
docs/index.html (1)

88-88: LGTM! Navigation link properly added.

The new "Calling Labs" navigation item is correctly positioned alongside the existing "Contact Center Labs" entry and follows the established HTML structure and naming conventions.

docs/labs/calling/styles.css (3)

1-8: LGTM! Well-structured base styling.

The typography and layout foundation is solid with proper font stack, line height, and centered container with reasonable max-width.


10-14: LGTM! Consistent branding colors.

The blue color (#0052bf) appears to align with Cisco/Webex branding and the visual styling is appropriate for headers.


32-36: LGTM! Responsive grid layouts are well-implemented.

Both the media grid and dialpad use appropriate CSS Grid with good responsive behavior and consistent spacing.

docs/labs/calling/modules/call-controls.js (5)

1-9: LGTM! Clear function documentation and parameter validation.

The JSDoc is comprehensive and the function signature is well-defined with proper destructuring.


12-20: Review mute behavior - potential UX confusion.

The mute implementation calls call.mute(stream, 'user_mute') but doesn't track or toggle mute state. Users may not have visual feedback about whether they're muted or unmuted.

Consider implementing a toggle pattern or updating UI state to reflect mute status:

 els.mute.addEventListener('click', () => {
   const call = getActiveCall?.();
   const stream = getLocalStream?.();
   if (!call || !stream) return;
+  // Consider tracking mute state and toggling
+  // const isMuted = call.isMuted(stream);
+  // if (isMuted) {
+  //   call.unmute(stream, 'user_unmute');
+  // } else {
   call.mute(stream, 'user_mute');
+  // }
+  // Update button text/state to reflect current mute status
 });

22-29: Hold/Resume implementation looks correct.

The doHoldResume() method name suggests it handles both hold and resume operations internally, which is appropriate for a toggle button.


46-55: LGTM! Batch DTMF sending with proper validation.

The implementation correctly validates both the call existence and input content before sending digits.


57-62: LGTM! Simple and effective clear functionality.

The clear operation is straightforward with appropriate null checking.

docs/labs/calling/modules/auth.js (5)

1-8: LGTM! Proper input validation and configuration structure.

The function correctly validates the required token and builds the webex configuration appropriately.


19-32: Review feature toggles logic for FedRAMP compliance.

The feature flags disable several capabilities (calling, callSettings, contact) when fedramp is true. Ensure this aligns with FedRAMP compliance requirements and doesn't break essential functionality.

The current logic disables these features in FedRAMP mode:

  • calling: !fedramp (disables calling when FedRAMP is true)
  • callSettings: !fedramp
  • contact: !fedramp

Please verify this matches the intended FedRAMP compliance requirements, as disabling core calling functionality in FedRAMP mode seems counterintuitive for a calling lab.


34-41: LGTM! Proper async initialization with event handling.

The initialization correctly waits for the 'ready' event before resolving and returns both the calling instance and client.


43-50: LGTM! Comprehensive calling scopes defined.

The OAuth scopes cover the necessary permissions for WebRTC calling functionality.


10-17: Integration service URLs are reachable (HTTP 401 as expected)

Both endpoints are live and returning the expected “authorization required” response. No updates to these URLs are needed at this time.

docs/labs/calling/modules/registration.js (2)

1-4: LGTM! Proper error handling for required parameter.

The function correctly validates the calling parameter and provides a clear error message.


6-9: LGTM! Graceful handling of missing calling instance.

The early return pattern appropriately handles the case where calling might not be initialized.

docs/labs/calling/index.js (1)

264-269: completeTransfer usage for CONSULT transfer is correct as-is

The Webex Calling WebRTC SDK’s completeTransfer signature is completeTransfer(transferType, transferCallId?, transferTarget?) and the Call object exposes getCallId() to retrieve its ID. Passing consultCall.getCallId() for a CONSULT transfer is exactly what the API expects, so no changes are needed.

</p>
<fieldset>
<legend>Credentials</legend>
<input id="access-token" type="text" placeholder="Paste access token" />
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Hide sensitive PAT input and disable auto-features that can leak it.

PATs are sensitive. Use a password field and disable autocorrect/capitalize/spellcheck and autocomplete.

Apply this diff:

-        <input id="access-token" type="text" placeholder="Paste access token" />
+        <input
+          id="access-token"
+          type="password"
+          placeholder="Paste access token"
+          autocomplete="off"
+          autocapitalize="off"
+          autocorrect="off"
+          spellcheck="false"
+          aria-label="Access token"
+        />
📝 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
<input id="access-token" type="text" placeholder="Paste access token" />
<input
id="access-token"
type="password"
placeholder="Paste access token"
autocomplete="off"
autocapitalize="off"
autocorrect="off"
spellcheck="false"
aria-label="Access token"
/>
🤖 Prompt for AI Agents
In docs/labs/calling/index.html around line 43, the access token input is
currently a plain text field which can expose PATs; change the input to
type="password" and add attributes to prevent browser and OS features from
leaking the token: set autocomplete="off" (or autocomplete="new-password"),
autocorrect="off", autocapitalize="off", and spellcheck="false" so the token is
hidden and auto-features are disabled.

<p><strong>Using OAuth (for production):</strong></p>
<p>
To use OAuth, first create an Integration in the
<a href="https://developer.webex.com/my-apps" target="_blank">Webex Developer Portal</a>.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add rel="noopener noreferrer" to external link with target="_blank".

Prevents reverse tabnabbing and improves security.

Apply this diff:

-        <a href="https://developer.webex.com/my-apps" target="_blank">Webex Developer Portal</a>.
+        <a href="https://developer.webex.com/my-apps" target="_blank" rel="noopener noreferrer">Webex Developer Portal</a>.
📝 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
<a href="https://developer.webex.com/my-apps" target="_blank">Webex Developer Portal</a>.
<a href="https://developer.webex.com/my-apps" target="_blank" rel="noopener noreferrer">Webex Developer Portal</a>.
🤖 Prompt for AI Agents
In docs/labs/calling/index.html around line 78, the external anchor uses
target="_blank" but is missing rel="noopener noreferrer"; update the <a> tag to
include rel="noopener noreferrer" alongside target="_blank" to prevent reverse
tabnabbing and improve security.

Comment on lines +133 to +142
async function handleDeregister() {
try {
await deregister(calling);
setRegistrationUI(false);
setCallUI(false);
activeCall = undefined;
} catch (e) {
console.error('Deregister failed', e);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

End active/consult calls before deregistering and reset media UI.

Avoid dangling calls and stale UI when deregistering.

Apply this diff:

 async function handleDeregister() {
   try {
+    if (consultCall) {
+      try { consultCall.end(); } catch {}
+      consultCall = undefined;
+    }
+    if (activeCall) {
+      try { activeCall.end(); } catch {}
+      activeCall = undefined;
+    }
     await deregister(calling);
     setRegistrationUI(false);
     setCallUI(false);
-    activeCall = undefined;
+    resetTransferUI();
+    if (els.remoteAudio) els.remoteAudio.srcObject = null;
   } catch (e) {
     console.error('Deregister failed', e);
   }
 }
📝 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
async function handleDeregister() {
try {
await deregister(calling);
setRegistrationUI(false);
setCallUI(false);
activeCall = undefined;
} catch (e) {
console.error('Deregister failed', e);
}
}
async function handleDeregister() {
try {
if (consultCall) {
try { consultCall.end(); } catch {}
consultCall = undefined;
}
if (activeCall) {
try { activeCall.end(); } catch {}
activeCall = undefined;
}
await deregister(calling);
setRegistrationUI(false);
setCallUI(false);
resetTransferUI();
if (els.remoteAudio) els.remoteAudio.srcObject = null;
} catch (e) {
console.error('Deregister failed', e);
}
}
🤖 Prompt for AI Agents
In docs/labs/calling/index.js around lines 133 to 142, the deregister handler
currently calls deregister and then hides UI but can leave active or consult
calls and media streams dangling; before calling deregister, if there is an
activeCall or consultCall, await their proper termination (call their
hangup/terminate/end method or send a BYE and await confirmation), stop and
release any local media tracks and clear audio/video element srcObject, then
call deregister, and only after successful deregistration
setRegistrationUI(false), setCallUI(false) and clear activeCall/consultCall
variables.

Comment on lines +312 to +317
function handleAnswer() {
if (!activeCall || !localAudioStream) return;
wireActiveCall(activeCall);
activeCall.answer(localAudioStream);
els.answer.disabled = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Answer incoming calls even if the mic stream hasn’t been acquired yet.

Users may click Answer before Step 4. Make handleAnswer async and fetch the mic if needed.

Apply this diff:

-function handleAnswer() {
-  if (!activeCall || !localAudioStream) return;
-  wireActiveCall(activeCall);
-  activeCall.answer(localAudioStream);
-  els.answer.disabled = true;
-}
+async function handleAnswer() {
+  if (!activeCall) return;
+  if (!localAudioStream) {
+    await handleGetMedia();
+    if (!localAudioStream) {
+      els.callStatus.textContent = 'Microphone unavailable.';
+      return;
+    }
+  }
+  wireActiveCall(activeCall);
+  activeCall.answer(localAudioStream);
+  els.answer.disabled = true;
+}
📝 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
function handleAnswer() {
if (!activeCall || !localAudioStream) return;
wireActiveCall(activeCall);
activeCall.answer(localAudioStream);
els.answer.disabled = true;
}
async function handleAnswer() {
if (!activeCall) return;
if (!localAudioStream) {
await handleGetMedia();
if (!localAudioStream) {
els.callStatus.textContent = 'Microphone unavailable.';
return;
}
}
wireActiveCall(activeCall);
activeCall.answer(localAudioStream);
els.answer.disabled = true;
}
🤖 Prompt for AI Agents
In docs/labs/calling/index.js around lines 312 to 317, handleAnswer currently
returns if localAudioStream is missing, preventing answering when the user
clicks before the mic is acquired; make handleAnswer an async function, check
for localAudioStream and if absent call the existing mic acquisition routine
(await getLocalAudioStream or equivalent) inside a try/catch, assign the result
to localAudioStream, then proceed to wireActiveCall(activeCall), call
activeCall.answer(localAudioStream), and disable els.answer; ensure errors
during mic acquisition are caught and logged and that the function still exits
gracefully if acquisition fails.

Comment on lines +319 to +327
function autoInitFromHash() {
const hash = window.location.hash?.substring(1) || '';
const params = new URLSearchParams(hash);
const token = params.get('access_token');
if (token) {
els.token.value = token;
handleInit();
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Clear the access token from the URL after auto-init.

After extracting the access_token from the fragment, remove it to avoid leaving tokens in browser history or user-shared URLs.

Apply this diff:

 function autoInitFromHash() {
   const hash = window.location.hash?.substring(1) || '';
   const params = new URLSearchParams(hash);
   const token = params.get('access_token');
   if (token) {
-    els.token.value = token;
-    handleInit();
+    els.token.value = token;
+    // Remove the token fragment from the URL
+    window.history.replaceState(null, '', window.location.pathname + window.location.search);
+    handleInit();
   }
 }
📝 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
function autoInitFromHash() {
const hash = window.location.hash?.substring(1) || '';
const params = new URLSearchParams(hash);
const token = params.get('access_token');
if (token) {
els.token.value = token;
handleInit();
}
}
function autoInitFromHash() {
const hash = window.location.hash?.substring(1) || '';
const params = new URLSearchParams(hash);
const token = params.get('access_token');
if (token) {
els.token.value = token;
// Remove the token fragment from the URL
window.history.replaceState(null, '', window.location.pathname + window.location.search);
handleInit();
}
}
🤖 Prompt for AI Agents
In docs/labs/calling/index.js around lines 319 to 327, after extracting
access_token from the URL fragment and calling handleInit(), remove the token
from the URL so it isn't left in browser history or shared links: clear or
replace the location hash and use history.replaceState (or set location.hash =
'' and call history.replaceState with the current URL sans fragment) to avoid
navigating or adding a new history entry while preserving the current page
state.

Comment on lines +59 to +72
export async function initOauth({ clientId, redirectUri, scope } = {}) {
const webex = Webex.init({
config: {
credentials: {
client_id: clientId || 'YOUR_PUBLIC_CLIENT_ID',
redirect_uri: redirectUri || (window.location.origin + window.location.pathname),
scope: scope || callingScopes
}
}
});

await webex.authorization.initiateLogin({ state: {} });
return webex;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve OAuth configuration validation.

The function uses a placeholder client ID that could lead to runtime failures if not properly configured.

 export async function initOauth({ clientId, redirectUri, scope } = {}) {
+  if (!clientId || clientId === 'YOUR_PUBLIC_CLIENT_ID') {
+    throw new Error('Valid clientId is required for OAuth initialization');
+  }
+  
   const webex = Webex.init({
     config: {
       credentials: {
-        client_id: clientId || 'YOUR_PUBLIC_CLIENT_ID',
+        client_id: clientId,
         redirect_uri: redirectUri || (window.location.origin + window.location.pathname),
         scope: scope || callingScopes
       }
     }
   });
📝 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
export async function initOauth({ clientId, redirectUri, scope } = {}) {
const webex = Webex.init({
config: {
credentials: {
client_id: clientId || 'YOUR_PUBLIC_CLIENT_ID',
redirect_uri: redirectUri || (window.location.origin + window.location.pathname),
scope: scope || callingScopes
}
}
});
await webex.authorization.initiateLogin({ state: {} });
return webex;
}
export async function initOauth({ clientId, redirectUri, scope } = {}) {
if (!clientId || clientId === 'YOUR_PUBLIC_CLIENT_ID') {
throw new Error('Valid clientId is required for OAuth initialization');
}
const webex = Webex.init({
config: {
credentials: {
client_id: clientId,
redirect_uri: redirectUri || (window.location.origin + window.location.pathname),
scope: scope || callingScopes
}
}
});
await webex.authorization.initiateLogin({ state: {} });
return webex;
}
🤖 Prompt for AI Agents
In docs/labs/calling/modules/auth.js around lines 59 to 72, the initOauth
function currently falls back to a placeholder client ID which can produce
runtime failures; validate the provided clientId (and optionally
redirectUri/scope) at the start of the function and fail fast: if clientId is
missing or equals the placeholder string, throw a clear Error (or return a
rejected Promise) instructing the caller to provide a valid clientId; also
validate redirectUri and scope and either supply safe defaults or throw with
actionable messages if they are invalid, so the function never initializes Webex
with a known-bad configuration.

Comment on lines +31 to +44
// Dialpad per-key sending
document.querySelectorAll('.dialpad button[data-tone]')
.forEach((btn) => {
btn.addEventListener('click', () => {
const tone = btn.getAttribute('data-tone');
if (els.dtmfDisplay) {
els.dtmfDisplay.value += tone;
}
const call = getActiveCall?.();
if (call) {
try { call.sendDigit(tone); } catch (e) { /* ignore */ }
}
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling for DTMF operations.

The try/catch block silently ignores errors, which could hide important issues like invalid tones or network problems.

 const call = getActiveCall?.();
 if (call) {
-  try { call.sendDigit(tone); } catch (e) { /* ignore */ }
+  try { 
+    call.sendDigit(tone); 
+  } catch (e) { 
+    console.warn(`Failed to send DTMF tone "${tone}":`, e);
+  }
 }
📝 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
// Dialpad per-key sending
document.querySelectorAll('.dialpad button[data-tone]')
.forEach((btn) => {
btn.addEventListener('click', () => {
const tone = btn.getAttribute('data-tone');
if (els.dtmfDisplay) {
els.dtmfDisplay.value += tone;
}
const call = getActiveCall?.();
if (call) {
try { call.sendDigit(tone); } catch (e) { /* ignore */ }
}
});
});
// Dialpad per-key sending
document.querySelectorAll('.dialpad button[data-tone]')
.forEach((btn) => {
btn.addEventListener('click', () => {
const tone = btn.getAttribute('data-tone');
if (els.dtmfDisplay) {
els.dtmfDisplay.value += tone;
}
const call = getActiveCall?.();
if (call) {
try {
call.sendDigit(tone);
} catch (e) {
console.warn(`Failed to send DTMF tone "${tone}":`, e);
}
}
});
});
🤖 Prompt for AI Agents
In docs/labs/calling/modules/call-controls.js around lines 31 to 44, the current
try/catch for call.sendDigit(tone) swallows all errors; validate the tone before
sending and replace the empty catch with proper error handling: check tone
against the allowed DTMF characters (0-9, *, #, A-D) and if invalid skip and
show a user-visible message; wrap call.sendDigit in a try/catch that logs the
error (include tone and call id/context) to console or the app logger and
surface a brief inline error/toast instead of ignoring, or rethrow for
higher-level handling if appropriate.

Comment on lines +14 to +17
const lines = callingClient.getLines();
const first = Object.values(lines)[0];
console.log('first', first);
return first;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation for empty lines collection.

The function assumes getLines() returns an object with values, but it could be empty or null.

 export function getPrimaryLine(callingClient) {
   if (!callingClient) return undefined;
   const lines = callingClient.getLines();
+  if (!lines || typeof lines !== 'object') return undefined;
   const first = Object.values(lines)[0];
+  if (!first) return undefined;
   return first;
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In docs/labs/calling/modules/registration.js around lines 14 to 17, the code
assumes callingClient.getLines() returns a non-empty object and immediately
accesses Object.values(lines)[0]; add a null/empty check before accessing
values: verify lines is truthy and has at least one key (e.g.,
Object.keys(lines).length > 0), handle the empty/null case by returning null (or
throwing a clear error) and optionally logging a warning, otherwise compute and
return the first value; ensure no runtime error occurs when getLines() returns
null or an empty object.

Comment on lines +84 to +86
// After redirect back, the access_token is in the URL hash. The lab auto-detects
// it and initializes Calling using that token.
```
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Document removing the access token from the URL fragment after parsing.

To reduce accidental token exposure (browser history, on-screen sharing), mention clearing the hash after extraction.

You can augment the sample with this line:

 // After redirect back, the access_token is in the URL hash. The lab auto-detects
-// it and initializes Calling using that token.
+// it and initializes Calling using that token, then removes it from the URL:
+window.history.replaceState(null, '', window.location.pathname + window.location.search);
📝 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
// After redirect back, the access_token is in the URL hash. The lab auto-detects
// it and initializes Calling using that token.
```
// After redirect back, the access_token is in the URL hash. The lab auto-detects
// it and initializes Calling using that token, then removes it from the URL:
window.history.replaceState(null, '', window.location.pathname + window.location.search);
🤖 Prompt for AI Agents
In docs/labs/calling/README.md around lines 84–86, after describing extraction
of the access_token from the URL hash, add a step to remove the fragment from
the browser address bar to avoid accidental token exposure: immediately after
parsing the token, call the browser history API to replace the current URL with
the same path+query but without the hash (e.g., use history.replaceState to
clear the fragment) so the token is not stored in history or visible on-screen.

Copy link

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

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

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