Skip to content

docs(calling): add sdd patterns for calling package#4776

Merged
rarajes2 merged 6 commits intowebex:nextfrom
rarajes2:calling-spec
Apr 1, 2026
Merged

docs(calling): add sdd patterns for calling package#4776
rarajes2 merged 6 commits intowebex:nextfrom
rarajes2:calling-spec

Conversation

@rarajes2
Copy link
Copy Markdown
Contributor

@rarajes2 rarajes2 commented Mar 15, 2026

COMPLETES #< SPARK-787602 >

This pull request addresses

Adds SDD patterns for the calling package.

by making the following changes

Created: packages/calling/ai-docs/patterns/

File Purpose Why it exists
typescript-patterns.md Naming conventions, interfaces, enums, type maps, imports, exports Direct analog of the reference — adapted for SDK conventions (no I prefix on types, I prefix on interfaces, enum patterns, discriminated unions)
architecture-patterns.md Singleton/factory patterns, client hierarchy, call lifecycle, backend connectors Replaces the React three-layer architecture — this package uses clients, managers, and connectors instead
event-patterns.md Typed event emitter, event type maps, emission/listening, Mercury WebSocket flow Replaces MobX patterns — this package uses a typed Eventing<T> base class instead of observable stores
state-machine-patterns.md XState call/ROAP state machines, state naming, event naming, timeout patterns Unique to this package — documents the XState-driven call and media lifecycle
error-handling-patterns.md Error hierarchy, factory functions, error types/codes, handler utilities, emission flow Unique to this package — documents the ExtendedErrorCallError/LineError/CallingClientError hierarchy
testing-patterns.md Jest setup, mock Webex SDK, fixtures, event testing, async patterns, coverage targets Direct analog of the reference — adapted for Jest + co-located tests (no React Testing Library, no Playwright since this is SDK-only)

Every pattern document was derived from reading the actual source code, not generated generically. The code examples reference real classes, enums, and interfaces from the codebase.

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 - Cursor with calude-4.6-opus-high
  • 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.

@rarajes2 rarajes2 requested a review from a team as a code owner March 15, 2026 12:23
@rarajes2 rarajes2 added the validated If the pull request is validated for automation. label Mar 15, 2026
@rarajes2
Copy link
Copy Markdown
Contributor Author

@codex review

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: 518d0aa0f6

ℹ️ 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 +138 to +142
export const createClient = (
webex: WebexSDK,
config?: CallingClientConfig
): ICallingClient => new CallingClient(webex, config);

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 Document createClient as async and already initialized

This snippet documents createClient as synchronous and encourages a follow-up client.init() call, but the real factory is async and already calls init() internally (packages/calling/src/CallingClient/CallingClient.ts:840-847). Consumers following this pattern will either use the API incorrectly without await or call initialization twice, which can duplicate setup work (line creation/listener registration) and produce hard-to-debug behavior.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This needs to be fixed. Good point codex

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment on lines +223 to +226
CallSettings
├── WxCallBackendConnector (Webex Calling)
├── UcmBackendConnector (UCM)
└── BroadworksBackendConnector (Broadworks)
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 Remove Broadworks connector from CallSettings architecture map

The architecture map states that CallSettings has a BroadworksBackendConnector, but the module only contains WxCallBackendConnector and UcmBackendConnector implementations (packages/calling/src/CallSettings/*). Keeping this entry will push readers/LLMs toward imports and abstractions that do not exist in the package, causing dead-end implementation paths and compile errors.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point. Should be removed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

it('should wait for timer', async () => {
jest.useFakeTimers();

call.startKeepalive();
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 Use an existing keepalive API in the test example

This test example calls call.startKeepalive(), but there is no such public method on ICall (the interface exposes postStatus() for keepalive-related behavior in packages/calling/src/CallingClient/calling/types.ts). Copying this snippet into real tests will fail type-checking and mislead contributors about the supported call API surface.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

@rarajes2 rarajes2 changed the base branch from calling-sdk-specs to next March 16, 2026 13:58
- **MUST** use `SDKConnector` for all Webex SDK interactions (requests, Mercury listeners)
- **MUST** separate backend-specific logic into connector classes (WxCall, UCM, Broadworks)
- **MUST** keep types co-located in `types.ts` within each module
- **MUST** export public API through `src/api.ts` only
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is only for the typeDoc documentation generation. See if needs modification

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment on lines +138 to +142
export const createClient = (
webex: WebexSDK,
config?: CallingClientConfig
): ICallingClient => new CallingClient(webex, config);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This needs to be fixed. Good point codex

Comment on lines +223 to +226
CallSettings
├── WxCallBackendConnector (Webex Calling)
├── UcmBackendConnector (UCM)
└── BroadworksBackendConnector (Broadworks)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point. Should be removed.

### Line Errors

```typescript
this.lineEmitter(LINE_EVENTS.ERROR, undefined, lineError);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Mention deviceInfo as optional 2nd param instead of undefined

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Copy Markdown
Contributor

@rsarika rsarika left a comment

Choose a reason for hiding this comment

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


For client and device-level errors (device registration, Mobius discovery, etc.).

```typescript
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.

u can directly point to file/code block instead of copying the whole code again docs? same for all the places we have written whole code in docs. instead small examples

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

- **MUST** mock `@webex/internal-media-core` at the top of call-related test files
- **MUST** maintain ≥85% line/function/statement coverage and ≥80% branch coverage
- **MUST** clean up mocks in `beforeEach`/`afterEach` with `jest.clearAllMocks()`
- **NEVER** test implementation details — test observable behavior and event emissions
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 we add an example for this line ? like what observable reviews to want our focus to be on? so the Agent has better context?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

// webex.internal.services.getMobiusClusters → jest.fn()
// webex.logger → mock logger with all levels
// webex.people.list → jest.fn()
```
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.

Any Info about why we have not mentioned rest of the parameters & methods here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added note: "For the full list of mocked properties, refer to src/common/testUtil.ts". The doc shows the most commonly used properties as a quick reference.

let callManager: ICallManager;

beforeEach(() => {
callManager = getCallManager(webex, defaultServiceIndicator);
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.

import {ServiceIndicator} from '../../common/types';
const defaultServiceIndicator = ServiceIndicator.CALLING;

let's add these lines in the example as well

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

call.on(CALL_EVENT_KEYS.ALERTING, alertingSpy);

// Trigger the action that causes the event
callManager.dequeueWsEvents(incomingCallEvent);
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.

dequeueWsEvents Method is private. so i'm not sure if accessing it by dot is correct.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Replaced the event testing example that used callManager.dequeueWsEvents() with a pattern that triggers events through the public API (call.dial() + flushPromises) and verifies observable behavior.


```typescript
// Single response
webex.request.mockReturnValueOnce({
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.

as webex.request returns an promise, i guess it should be mockResolvedValue,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Changed all mockReturnValueOncemockResolvedValueOnce and mockReturnValuemockResolvedValue in the mock response configuration examples.

});

// Persistent response
webex.request.mockReturnValue({statusCode: 200, body: {}});
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.

Same as line 92

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

it('should wait for timer', async () => {
jest.useFakeTimers();

call.startKeepalive();
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.

it's an private method right? so i guess we should not use directly '.' here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

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.

We don't need this file. Patterns docs would be referred for something that we would be creating repeatedly in the package. State machine is something created once and that too depends on if we have something like call or task to manage it's states. When we create global ai-docs for SDK, that's where the patten for state-machine will be appliacable

### Call Events

```typescript
export type CallEventTypes = {
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.

Critical: Incomplete CallEventTypes — This type map is missing two entries that exist in the source at src/Events/types.ts:213,219:

[LINE_EVENT_KEYS.INCOMING_CALL]: (callObj: ICall) => void;   // line 213
[CALLING_CLIENT_EVENT_KEYS.ALL_CALLS_CLEARED]: () => void;   // line 219

This also hides the fact that CallEventTypes crosses enum boundaries — it uses keys from three different enums (CALL_EVENT_KEYS, LINE_EVENT_KEYS, CALLING_CLIENT_EVENT_KEYS), which is architecturally significant for LLM consumers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

export enum WEBSOCKET_KEYS {
CALL_PROGRESS = 'callprogress',
CALL_CONNECTED = 'callconnected',
CALL_DISCONNECTED = 'callconnected',
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.

Critical: Source code bug reproduced without flaggingCALL_DISCONNECTED = 'callconnected' is a copy-paste bug in the source (src/Events/types.ts:304) where both CALL_CONNECTED and CALL_DISCONNECTED map to the same string 'callconnected'.

The doc should flag this rather than silently propagating it. Suggestion: add an inline comment like:

CALL_DISCONNECTED = 'callconnected', // ⚠️ Bug in source — should likely be 'calldisconnected'

Also consider filing a separate issue to fix the source.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Noted, will create a ticket for this.


emit<E extends keyof T>(event: E, ...args: Parameters<T[E]>): boolean {
const timestamp = new Date().toUTCString();
Logger.info(`${timestamp} ${LOG_PREFIX.EVENT}: ${event.toString()} - event emitted`);
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.

Inaccurate: emit() log message is wrong — The actual source at src/Events/impl/index.ts:23-31 is:

Logger.info(
  `${timestamp} ${LOG_PREFIX.EVENT}: ${event.toString()} - event emitted with parameters -> ${args}`,
  { file: 'Events/impl/index.ts', method: 'emit' }
);

Two differences: (a) missing with parameters -> ${args} suffix, (b) missing {file, method} second argument. An LLM consumer would generate code with the wrong Logger.info signature.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


---

## Event Key Enums
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.

Missing enums in this section:

  1. LINE_EVENT_KEYS (src/Events/types.ts:16-18) — A separate enum from LINE_EVENTS with INCOMING_CALL = 'incoming_call' (vs LINE_EVENTS.INCOMING_CALL = 'line:incoming_call'). This distinction matters because CallEventTypes uses LINE_EVENT_KEYS, not LINE_EVENTS.

  2. COMMON_EVENT_KEYS (src/Events/types.ts:9-14) — Used in CallHistoryEventTypes and VoicemailEventTypes type maps shown in this doc, but the enum definition is never shown.

  3. MEDIA_CONNECTION_EVENT_KEYS (src/Events/types.ts:184-187) — Event-related enum that is completely absent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


```typescript
// Emit with callId
this.emit(CALL_EVENT_KEYS.ALERTING, this.correlationId);
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.

Unverified examplegrep -rn "emit.*ALERTING" packages/calling/src/ returns zero results. CALL_EVENT_KEYS.ALERTING is defined in the type map (types.ts:205) but is never actually emitted anywhere in the codebase. Consider replacing with a verified example like CALL_EVENT_KEYS.PROGRESS or CALL_EVENT_KEYS.CONNECT.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

### Emitting from a Line

```typescript
lineEmitter: (event: LINE_EVENTS, deviceInfo?: IDeviceInfo, lineError?: LineError) => void;
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.

Misleading simplification — The actual lineEmitter at src/CallingClient/line/index.ts:190-215 uses a switch statement with important logic:

  • For REGISTERED: calls this.normalizeLine(deviceInfo) then emits this (the ILine instance), not deviceInfo
  • For ERROR: only emits if lineError is truthy
  • For UNREGISTERED/RECONNECTED/RECONNECTING: emits with no args

The doc's simplified view suggests lineEmitter is a pass-through, which is incorrect.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


```typescript
private listenForWsEvents() {
this.sdkConnector.registerListener<MobiusCallEvent>(
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.

Doc doesn't match actual code — The actual listenForWsEvents at src/CallingClient/calling/callManager.ts:130 uses a raw string, not the enum:

// Actual code:
this.sdkConnector.registerListener('event:mobius', async (event) => {
  this.dequeueWsEvents(event);
});

The doc shows MOBIUS_EVENT_KEYS.SERVER_EVENT_INCLUSIVE and <MobiusCallEvent> type parameter, neither of which exist in the real code. Either document reality or note this is the recommended pattern.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. The actual code should have used the enum but for now keeping it par with code

### Session Listener Pattern in CallingClient

```typescript
private registerSessionsListener() {
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.

Heavily oversimplified — The actual registerSessionsListener at src/CallingClient/CallingClient.ts:665-691 contains critical business logic the doc omits:

// Actual code filters by session type:
const sessionArr = event?.data.userSessions.userSessions;
if (sessionArr.length === 1) {
  if (sessionArr[0].sessionType !== SessionType.WEBEX_CALLING) {
    return; // ← silently drops non-WEBEX_CALLING sessions
  }
}
for (let i = 0; i < sessionArr.length; i += 1) {
  if (sessionArr[i].sessionType !== SessionType.WEBEX_CALLING) {
    sessionArr.splice(i, 1); // ← mutates the array
  }
}

The doc shows a trivial if (event) { this.emit(...) }. At minimum add a comment noting the filtering, since this is a reference for LLMs that will generate code based on it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment on lines +54 to +60
| Client | Factory | Interface | Purpose |
|--------|---------|-----------|---------|
| `CallingClient` | `createClient()` | `ICallingClient` | Line registration, call management |
| `CallHistory` | `createCallHistoryClient()` | `ICallHistory` | Call records |
| `CallSettings` | `createCallSettingsClient()` | `ICallSettings` | DND, forwarding, voicemail settings |
| `ContactsClient` | `createContactsClient()` | `IContacts` | Contact management |
| `Voicemail` | `createVoicemailClient()` | `IVoicemail` | Voicemail operations |
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.

It would be nice to have another column as description, just a small text telling what these are.

Copy link
Copy Markdown
Contributor Author

@rarajes2 rarajes2 Mar 26, 2026

Choose a reason for hiding this comment

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

The client modules table was moved out of the patterns file (per Priya's feedback that it belongs in architecture-level ai-docs, not patterns). The pattern file now focuses on reusable patterns only.

## High-Level Architecture

```
┌──────────────────────────────────────────────────────────────────┐
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.

We should be using memaid diagrams here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

High-Level Architecture and Call Lifecycle were moved out of the patterns file per Priya's feedback. The event-patterns.md now uses a mermaid sequence diagram for the WebSocket event flow. Error-handling-patterns.md uses a mermaid flowchart for the error flow overview.


## Call Lifecycle

```
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.

We should be using memaid diagrams here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not required in this file. Removed.

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.

Callback patterns, is something I feel we can add here as well

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


## Singleton Pattern

### SDKConnector
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.

For each of these can we add more description

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment on lines +28 to +32
```typescript
// PascalCase
CallingClient.ts
CallManager.ts
SDKConnector.ts
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.

Aren't these file names? I understand class names would look similar but seems misleading. Let's may be have a table to say file name and class name accordingly

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment on lines +62 to +65
enum CALL_EVENT_KEYS { ... }
enum ERROR_TYPE { ... }
enum CallDirection { ... }
enum RegistrationStatus { ... }
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.

Why is this of 3 different casings?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added explanation table showing the three casing conventions, what they're used for, and examples. Added guidance for new enums.

export {CallHistory, CallSettings, CallingClient, ContactsClient, Voicemail};

// Types
export {ContactGroup, Contact, CallForwardSetting, VoicemailSetting};
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 it be export type?

Suggested change
export {ContactGroup, Contact, CallForwardSetting, VoicemailSetting};
export type {ContactGroup, Contact, CallForwardSetting, VoicemailSetting};

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Comment thread packages/calling/ai-docs/patterns/typescript-patterns.md
Comment thread packages/calling/ai-docs/patterns/architecture-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/architecture-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/architecture-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/architecture-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/architecture-patterns.md
Comment thread packages/calling/ai-docs/patterns/event-patterns.md
Comment thread packages/calling/ai-docs/patterns/event-patterns.md
Comment thread packages/calling/ai-docs/patterns/event-patterns.md
Comment thread packages/calling/ai-docs/patterns/event-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/event-patterns.md
Comment thread packages/calling/ai-docs/patterns/error-handling-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/error-handling-patterns.md
Comment thread packages/calling/ai-docs/patterns/error-handling-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/error-handling-patterns.md
Comment thread packages/calling/ai-docs/patterns/error-handling-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/error-handling-patterns.md
Comment thread packages/calling/ai-docs/patterns/error-handling-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/error-handling-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/error-handling-patterns.md Outdated
Comment thread packages/calling/ai-docs/patterns/architecture-patterns.md
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: 85d8f7f050

ℹ️ 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 +350 to +354
responsePayload,
ERROR_LAYER.CALL_CONTROL,
this.correlationId,
{file: CALL_FILE, method: 'dial'},
() => this.retryOperation() // optional retry callback
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 Call handleCallErrors with the real parameter order

This example uses the wrong argument order (responsePayload is passed second) and omits the required trailing file argument, while handleCallErrors in packages/calling/src/common/Utils.ts is defined as (emitterCb, errorLayer, retryCb, correlationId, err, caller, file) and returns a Promise<boolean>. If copied into code, this will either fail type-checking or invoke the handler with incorrect semantics, so generated error handling logic will be broken.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Comment on lines +363 to +366
const {abort} = handleCallingClientErrors(responsePayload, {
file: CALLING_CLIENT_FILE,
method: 'getMobiusServers',
});
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 handleCallingClientErrors as async boolean API

The snippet destructures {abort} from handleCallingClientErrors(...), but the actual helper in packages/calling/src/common/Utils.ts returns Promise<boolean> and requires an emitter callback as its second argument. Following this example will produce invalid callsites (wrong arguments and wrong return handling), and callers may skip emitting CallingClientError events because the callback path is missing.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Comment on lines +146 to +149
const callHistory = createCallHistoryClient(webex, config);
const callSettings = createCallSettingsClient(webex, config);
const contacts = createContactsClient(webex, config);
const voicemail = createVoicemailClient(webex, config);
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 logger, not client config, to non-calling factories

These examples pass config into createCallHistoryClient/createCallSettingsClient/createContactsClient/createVoicemailClient, but those factories are typed to take (webex, logger[, ...]) in their respective source files. Copying this pattern from the docs will produce type errors and lead contributors/LLMs to wire the wrong initialization inputs for every non-CallingClient module.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Copy link
Copy Markdown
Contributor

@mkesavan13 mkesavan13 left a comment

Choose a reason for hiding this comment

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

Just one more tiny comment. Rest looks good. Approving the typescript-patterns.md

Comment on lines +375 to +377
| `log.info()` | Normal operations, method entry/exit, state transitions | Starting registration, call connected |
| `log.warn()` | Recoverable issues, degraded behavior, fallbacks | ICE warmup failed (will retry), missing optional config |
| `log.error()` | Unrecoverable failures, critical errors | Device registration failed, unhandled exception |
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.

Aren't there more log types? Can we get them also into the patterns?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Copy Markdown
Contributor

@riteshfyi riteshfyi left a comment

Choose a reason for hiding this comment

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

Everything Looks Good, just a minor suggestion, Approval for testing-patterns.md

describe('Call Tests', () => {
const deviceId = '55dfb53f-bed2-36da-8e85-cee7f02aa68e';
const dest = {type: CallType.URI, address: 'tel:5003'};
let callManager: ICallManager;
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 we mention where to get more info about the call Managar?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think that information is covered in the File Structure section and we also have Related section with other docs reference

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: 5a628f5dff

ℹ️ 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".


export enum ServiceIndicator {
CALLING = 'calling',
CONTACTCENTER = 'contactcenter',
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 real ServiceIndicator enum member names

The enum example documents ServiceIndicator.CONTACTCENTER, but the exported enum in packages/calling/src/common/types.ts uses CONTACT_CENTER (and also includes GUEST_CALLING). If contributors or LLM-generated code copy this snippet for branching or comparisons, they will reference a non-existent member and hit type-check failures.

Useful? React with 👍 / 👎.

```typescript
// SCREAMING_SNAKE_CASE
const MAX_RETRY_COUNT = 3;
const DEFAULT_SESSION_TIMER = 180;
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 Document DEFAULT_SESSION_TIMER with the actual value

This snippet states DEFAULT_SESSION_TIMER = 180, but the real constant is 1000 * 60 * 10 in packages/calling/src/CallingClient/constants.ts. Reusing the documented value in keepalive logic or tests would drastically shorten the interval and produce unrealistic behavior (or excessive status calls).

Useful? React with 👍 / 👎.

Comment on lines +153 to +157
dial(localAudioStream: LocalMicrophoneStream): Promise<void>;
answer(localAudioStream: LocalMicrophoneStream): Promise<void>;
end(): void;
doHoldResume(): void;
sendDigit(tone: string): Promise<void>;
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 Align ICall method returns with the exported API

The interface pattern shows dial, answer, and sendDigit returning Promise<void>, but the public ICall contract in packages/calling/src/CallingClient/calling/types.ts declares these methods as void. This mismatch will mislead consumers into Promise-based call flows that conflict with the package typings and create avoidable type errors.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@Kesari3008 Kesari3008 left a comment

Choose a reason for hiding this comment

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

Approving with few comments that still need to be taken care of

const voicemail = createVoicemailClient(webex, logger);
```

**Important differences from `createClient`**: The non-CallingClient factories (`createCallHistoryClient`, `createCallSettingsClient`, `createContactsClient`, `createVoicemailClient`) are **synchronous** and take a `LoggerInterface` as their second argument — not a `CallingClientConfig`. `LoggerInterface` is defined as `{ level: LOGGER }` (where `LOGGER` is the string enum from `src/Logger/types.ts`). `createCallSettingsClient` additionally accepts an optional `useProdWebexApis?: boolean` third argument.
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.

Refer to other modules as just other client modules, calling them non-callingclient doesn't seem very appropriate

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


This document describes the typed event system used throughout the `@webex/calling` package.

The package implements a fully type-safe event architecture built on Node.js `EventEmitter` (from `events`) augmented with compile-time type enforcement via `typed-emitter`. At its core is the `Eventing<T>` generic base class (`src/Events/impl/index.ts`), which every event-emitting class in the package extends — including `CallingClient`, `Call`, `CallManager`, `Line`, `CallHistory`, and `Voicemail`. Each of these classes is parameterized with a dedicated event type map (e.g., `CallingClientEventTypes`, `CallEventTypes`, `LineEventTypes`, `CallHistoryEventTypes`, `VoicemailEventTypes`) defined in `src/Events/types.ts`, which statically associates string-valued enum keys to their corresponding callback signatures. All event keys are defined as TypeScript `enum` members across `CALL_EVENT_KEYS`, `LINE_EVENTS`, `LINE_EVENT_KEYS`, `CALLING_CLIENT_EVENT_KEYS`, `COMMON_EVENT_KEYS`, `MOBIUS_EVENT_KEYS`, and `MEDIA_CONNECTION_EVENT_KEYS` — raw string keys are never used directly.
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.

Can we put these points in bullet points?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


## Eventing Base Class

All event-emitting classes extend this generic typed emitter (`src/Events/impl/index.ts`).
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.

Add source file locations like this with a title or something. Like Source File:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


### Emitting from a Line

The `lineEmitter` method (`src/CallingClient/line/index.ts`) is **not** a simple pass-through — it contains important business logic via a `switch` statement:
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.

Add an example code for calling lineEMitter as well

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


## Event Emission Pattern

Events are emitted using `this.emit()` with the enum constant as the event name and the typed payload as arguments. Because every emitting class extends `Eventing<T>`, the compiler enforces that the enum key and payload match the class's event type map at every call site. The `Eventing.emit()` override logs every emission with a UTC timestamp before delegating to the underlying `EventEmitter`. Emission happens across five classes — `Call` (the most prolific emitter, covering call lifecycle and error events), `Line` (registration state and incoming calls), `CallManager` (incoming call signaling and all-calls-cleared), `CallingClient` (client-level errors and session info), and `CallHistory` (session, viewed, and deleted events). `Voicemail` defines `VoicemailEventTypes` in its type map but does not currently contain any `this.emit()` call sites in its implementation.
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.

This could be in bullet points

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


---

## Event Key Enums
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.

This comment is missed I believe


---

## Pattern for Adding New Events
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.

Provide references here in this summary for sections above where you have provided details about how each of this step is done

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


### serviceErrorCodeHandler

Utility that maps HTTP status codes to structured response objects (not `ERROR_TYPE` values). Used by voicemail, call settings, contacts, and call history modules — **not** for the call/line/client error hierarchy.
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.

Why are we saying not ERROR_TYPE, directly reference the ERROR code. I believe AI resolved these comments. This section needs manual updating so please check

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

## Error Flow Overview

```mermaid
flowchart TD
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.

ServiceErrorCodeHandler is mentioned but we do not cover how it's related to rest of the error flow so adding a link/relation would be good here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed


---

## Error Handler Utilities
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.

We have handler for registration and keepalive errors as well right, add a reference for those as well

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

@rarajes2 rarajes2 enabled auto-merge (squash) April 1, 2026 09:11
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: 5bbd9a144e

ℹ️ 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".

```typescript
// In types.ts
export interface ICallingClient extends Eventing<CallingClientEventTypes> {
getLine(): ILine | 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.

P2 Badge Replace non-existent getLine() in client contract snippet

The interface example declares getLine(): ILine | undefined, but the actual public contract exposes getLines(): Record<string, ILine> and does not define getLine (packages/calling/src/CallingClient/types.ts). If readers/LLMs copy this snippet, they will generate call sites that fail type-checking against the exported SDK API.

Useful? React with 👍 / 👎.

const line = callingClient.getLines()[0];

line.on(LINE_EVENTS.REGISTERED, (lineInfo: ILine) => {
console.log('Line registered:', lineInfo.deviceId);
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 Use a valid ILine field in the REGISTERED listener example

This listener logs lineInfo.deviceId, but LINE_EVENTS.REGISTERED emits an ILine and ILine does not have a deviceId property (packages/calling/src/CallingClient/line/types.ts); it provides getDeviceId()/mobiusDeviceId instead. Copying this example into strict TypeScript code will produce a property-does-not-exist error.

Useful? React with 👍 / 👎.

ERROR_LAYER.CALL_CONTROL
);
this.emit(CALL_EVENT_KEYS.CALL_ERROR, callError);
uploadLogs(this.webex);
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 metadata to uploadLogs instead of webex

The snippet calls uploadLogs(this.webex), but uploadLogs is typed as uploadLogs(metaData?: LogsMetaData, throwError?: boolean) and obtains the Webex instance internally from SDKConnector (packages/calling/src/common/Utils.ts). Using this example directly leads to incorrect typing and teaches an invalid API contract for log uploads.

Useful? React with 👍 / 👎.

@rarajes2 rarajes2 merged commit 5a46651 into webex:next Apr 1, 2026
11 checks passed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 1, 2026

🎉 Your changes are now available!
Released in: v3.12.0-next.5
📖 View full changelog →
Packages Updated Version
webex 3.12.0-next.5
@webex/contact-center 3.12.0-next.3
@webex/calling 3.12.0-next.2

Thank you for your contribution!
🤖 This is an automated message. For questions, please refer to the documentation.

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.

7 participants