agentleFS
MicrosoftKnown publishermicrosoft/omnichannel-sdk/CLAUDE.md

omnichannel-sdk

CLAUDE.md24 starsChanged 32 days agoMITView on GitHub

This workspace may contain up to 6 related repositories. Not all teams have all repos. Always be aware of which repository you're in when making changes. What is omnichannel-sdk (@microsoft/ocsdk)? This is the lowest-level HTTP client in the Omnichannel frontend stack. It provides typed wrappers around the Omnichannel livechatconnector REST APIs, handling request construction, retry logic, timeout management, authentication headers, and telemetry logging. It does not manage WebSocket connections, message rendering, or conversation adapters — those are handled by higher-level…

  • Deletes or force-pushes
  • Installs packages

The file

Show its rules and text

We split this CLAUDE.md into the rules it gives an agent

19 rules. About 0 are common, 12 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈12

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    This workspace may contain up to 6 related repositories: Not all teams have all repos.

    line 5
  2. Distinctive:

    No WebSocket/real-time messaging (ACS handles this)

    line 44
  3. Distinctive:

    No message rendering or UI (chat-widget handles this)

    line 45
  4. Distinctive:

    No conversation adapter management (chat-sdk handles this)

    line 46
  5. Distinctive:

    No file uploads (amsclient handles this)

    line 47
  6. Distinctive:

    Every method follows the same structure:

    line 149
  7. Very specific:

    Update CHANGELOG.md under [Unreleased] with all changes

    line 351
  8. Distinctive:

    Use semantic versioning: major version for breaking changes

    line 352
  9. Very specific:

    Use async/await patterns (not mixing done callbacks with promises)

    line 372
  10. Distinctive:

    Test both success and error paths for every API method

    line 373
  11. Very specific:

    Test timeout handling (verify ClientHTTPTimeoutError is thrown)

    line 374
  12. Distinctive:

    Test auth vs anonymous endpoint selection

    line 375
  13. Very specific:

    Test mocks must include headers property on response objects

    line 389
  14. Very specific:

    Code standards: Follow TypeScript strict mode, avoid any types

    line 411
  15. Distinctive:

    Testing: All Karma tests must pass, add tests for new API methods

    line 412
  16. Very specific:

    Telemetry: Every API method must log start/succeed/fail events with timers

    line 413
  17. Very specific:

    CHANGELOG: Update CHANGELOG.md under [Unreleased] section

    line 415
  18. Distinctive:

    Auth parity: If adding a new endpoint, provide both authenticated and anonymous paths

    line 416
  19. Distinctive:

    Retry configuration: Add per-endpoint timeout and wait-time-between-retries configs

    line 417

≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

omnichannel-sdk - Claude Code Instructions

Repository Ecosystem

This workspace may contain up to 6 related repositories. Not all teams have all repos. Always be aware of which repository you're in when making changes.

RepositoryTypePurposeTypical Location
CRM.OmnichannelMonorepo (Backend)20+ microservices for Omnichannel platform<workspace-root>/CRM.Omnichannel/
ConversationControlFrontend (Agent UI)Agent experience and conversation management UI<workspace-root>/CRM.OmniChannel.ConversationControl/
LiveChatWidgetFrontend (Customer)Customer-facing chat widget<workspace-root>/CRM.OmniChannel.LiveChatWidget/
omnichannel-chat-sdkPublic SDKTypeScript SDK for chat integration<workspace-root>/omnichannel-chat-sdk/
omnichannel-chat-widgetPublic ComponentsReact component library<workspace-root>/omnichannel-chat-widget/
omnichannel-amsclientShared LibraryFile upload/download client<workspace-root>/omnichannel-amsclient/

Quick Context

  • Purpose: Low-level HTTP client for Omnichannel REST APIs (session lifecycle, chat config, tokens, transcripts)
  • npm Name: @microsoft/ocsdk
  • Version: 0.5.21
  • Type: TypeScript Library
  • Tech Stack: TypeScript 4.9, Axios + axios-retry, crypto-js, Webpack 5, Karma + Jasmine
  • Distribution: npm registry (@microsoft/ocsdk), UMD bundle (dist/SDK.min.js), CJS (lib/)
  • Consumers: @microsoft/omnichannel-chat-sdk (primary consumer), CRM.OmniChannel.LiveChatWidget

Architecture Overview

What is omnichannel-sdk (@microsoft/ocsdk)?

This is the lowest-level HTTP client in the Omnichannel frontend stack. It provides typed wrappers around the Omnichannel livechatconnector REST APIs, handling request construction, retry logic, timeout management, authentication headers, and telemetry logging. It does not manage WebSocket connections, message rendering, or conversation adapters — those are handled by higher-level packages (chat-sdk, chat-widget).

Key Responsibilities:

  • REST API calls to Omnichannel backend (livechatconnector/* endpoints)
  • Automatic retry with exponential backoff via axios-retry (retries on 5xx, network errors, optionally 429)
  • Per-endpoint configurable request timeouts
  • Authentication header management (AuthenticatedUserToken, AuthCodeNonce rotation)
  • Browser/device/OS detection for session context
  • Data masking and PII sanitization in telemetry logs
  • Cache key generation via SHA-256 hashing (crypto-js)
  • UMD bundle for script-tag usage (window.Microsoft.CRM.Omnichannel.SDK)

What This Package Does NOT Do:

  • No WebSocket/real-time messaging (ACS handles this)
  • No message rendering or UI (chat-widget handles this)
  • No conversation adapter management (chat-sdk handles this)
  • No file uploads (amsclient handles this)

Source Code Structure

omnichannel-sdk/
├── src/
│   ├── index.ts                    # Entry point, UMD global setup
│   ├── SDK.ts                      # Main SDK class (implements ISDK) — all API methods
│   ├── SDKProvider.ts              # Factory: SDKProvider.getSDK() creates SDK instances
│   ├── Common/
│   │   ├── Constants.ts            # Default headers, status codes, config params
│   │   ├── Enums.ts                # ChannelId, LiveChatVersion, OCSDKTelemetryEvent, SDKError
│   │   ├── EventNames.ts           # Custom DOM event names
│   │   ├── Locales.ts              # Supported locale list
│   │   ├── Mappings.ts             # StringMap type alias
│   │   ├── OCSDKLogger.ts          # Logger wrapper
│   │   ├── OmnichannelEndpoints.ts # All REST endpoint path constants
│   │   ├── OmnichannelHTTPHeaders.ts # HTTP header name constants
│   │   └── RequestTimeoutConfig.ts # Per-endpoint timeout type
│   ├── Interfaces/
│   │   ├── ISDK.ts                 # SDK public interface (all API method signatures)
│   │   ├── IOmnichannelConfiguration.ts # { orgUrl, orgId, widgetId, channelId }
│   │   ├── ISDKConfiguration.ts    # Retry counts, timeouts, nonce, ocUserAgent
│   │   ├── IAxiosRetryOptions.ts   # Retry handler config
│   │   └── I*OptionalParams.ts     # Per-method optional parameter interfaces
│   ├── Model/
│   │   ├── FetchChatTokenResponse.ts
│   │   ├── InitContext.ts          # Session init payload shape
│   │   ├── ILogger.ts / LogLevel.ts
│   │   ├── QueueAvailability.ts / ReconnectAvailability.ts / ReconnectMappingRecord.ts
│   │   └── Location.ts
│   └── Utils/
│       ├── axiosRetryHandler.ts    # Core retry logic (exponential backoff, 429 handling, header overwrites)
│       ├── BrowserInfo.ts / DeviceInfo.ts / OSInfo.ts  # User agent detection
│       ├── endpointsCreators.ts    # Dynamic endpoint path builders (version-aware)
│       ├── EventManager.ts         # Custom DOM event dispatch
│       ├── httpHeadersUtils.ts     # OC-User-Agent header builder
│       ├── LoggingSanitizer.ts     # PII stripping for telemetry
│       ├── SessionInitRetryHandler.ts
│       ├── uuid.ts                 # UUID v4 generator
│       └── Timer.ts / sleep.ts / ...
├── test/
│   ├── index.ts                    # Test entry point
│   ├── SDK.spec.ts                 # Main SDK tests
│   ├── SDKProvider.spec.ts
│   ├── Common/OCSDKLogger.spec.ts
│   └── Utils/*.spec.ts             # Utility tests
├── lib/                            # TSC + Babel output (CJS, published to npm)
├── dist/                           # Webpack output (UMD bundle)
├── karma.conf.js                   # Test runner config (Karma + Jasmine + ChromeHeadless)
├── webpack.config.js               # Webpack entry (merges common + dev/prod)
├── webpack.common.js               # Shared webpack config (entry, resolve, output)
├── webpack.prod.js                 # Production webpack config (minified SDK.min.js)
└── webpack.dev.js                  # Development webpack config

Key Files

FilePurpose
src/SDK.tsCore file — all 18+ API methods (getChatConfig, getChatToken, sessionInit, sessionClose, etc.)
src/SDKProvider.tsFactory pattern — SDKProvider.getSDK(config, sdkConfig, logger)
src/Interfaces/ISDK.tsPublic contract — all method signatures
src/Interfaces/IOmnichannelConfiguration.tsRequired config: { orgUrl, orgId, widgetId, channelId }
src/Interfaces/ISDKConfiguration.tsOptional config: retry counts, timeouts, nonce, ocUserAgent
src/Common/OmnichannelEndpoints.tsAll REST API path constants (39 endpoints)
src/Common/Enums.tsChannelId, LiveChatVersion (V1=IC3, V2=ACS, V3), OCSDKTelemetryEvent
src/Utils/axiosRetryHandler.tsRetry logic: exponential backoff, 429 handling, retry-after header

SDK API Methods

The SDK class (src/SDK.ts) implements ISDK with these methods:

MethodHTTPPurpose
getLcwFcsDetails()GETFetch LCW FCS details for the org
getChatConfig(requestId, bypassCache?)GETFetch widget configuration (sets liveChatVersion)
getLWIDetails(requestId, opts?)GETGet live work item details (anon or auth)
getChatToken(requestId, opts?, retryCount?)GETGet chat token to join ACS thread (with retry)
getReconnectableChats(params)GETFetch reconnectable chats for authenticated user
getReconnectAvailability(reconnectId, opts?)GETCheck reconnect availability
getAgentAvailability(requestId, opts?)POSTCheck agent/queue availability
sessionInit(requestId, opts?)POSTStart a chat session (sends browser/device context)
createConversation(requestId, opts?)POSTCreate conversation via connector path
sessionClose(requestId, opts?)POSTClose a chat session
validateAuthChatRecord(requestId, opts)GETValidate authenticated chat record exists
submitPostChatResponse(requestId, response, opts?)POSTSubmit post-chat survey response
getSurveyInviteLink(ownerId, body, opts?)POSTGet survey invite link
getChatTranscripts(requestId, chatId, token, opts?)GETGet chat transcripts (V1 and V2 paths)
getPersistentChatHistory(requestId, opts?)GETGet persistent chat history (auth required)
emailTranscript(requestId, token, body, opts?)POSTEmail transcript to customer
fetchDataMaskingInfo(requestId)GETFetch org data masking rules
makeSecondaryChannelEventRequest(requestId, body, opts?)POSTSend secondary channel event
sendTypingIndicator(requestId, version, opts?)POSTSend typing indicator (V2 only)

Method Pattern

Every method follows the same structure:

public async methodName(requestId: string, optionalParams: IMethodOptionalParams = {}): Promise<ReturnType> {
    // 1. Start timer + log telemetry start event
    const timer = Timer.TIMER();
    this.logWithLogger(LogLevel.INFO, OCSDKTelemetryEvent.METHOD_STARTED, "...", requestId);

    // 2. Build request path (auth vs anon endpoint, version-aware)
    let requestPath = authenticatedUserToken
        ? `/${OmnichannelEndpoints.AuthPath}/...`
        : `/${OmnichannelEndpoints.AnonPath}/...`;

    // 3. Create axios instance with retry handler
    const axiosInstance = axios.create();
    axiosRetryHandler(axiosInstance, { retries: ..., waitTimeInMsBetweenRetries: ... });

    // 4. Build headers (Content-Type, auth token, nonce, session ID, user agent, correlation ID)
    const requestHeaders: StringMap = { ...Constants.defaultHeaders };
    if (authenticatedUserToken) {
        requestHeaders[OmnichannelHTTPHeaders.authenticatedUserToken] = authenticatedUserToken;
        requestHeaders[OmnichannelHTTPHeaders.authCodeNonce] = this.configuration.authCodeNonce;
    }
    this.addDefaultHeaders(requestId, requestHeaders);

    // 5. Execute request with configurable timeout
    try {
        const response = await axiosInstance(options);
        this.setAuthCodeNonce(response.headers); // Rotate nonce from response
        this.logWithLogger(LogLevel.INFO, OCSDKTelemetryEvent.METHOD_SUCCEEDED, ...);
        return response.data;
    } catch (error) {
        this.logWithLogger(LogLevel.ERROR, OCSDKTelemetryEvent.METHOD_FAILED, ...);
        if (isExpectedAxiosError(error, Constants.axiosTimeoutErrorCode)) {
            throw new Error(this.HTTPTimeOutErrorMessage);
        }
        throw error;
    }
}

Build & Test Workflow

Prerequisites

  • Node.js (v12+ per README, but modern versions work)
  • npm package manager
  • NODE_OPTIONS=--openssl-legacy-provider is required for the production build

Setup

cd omnichannel-sdk
npm install

Common Commands

Build (3-stage pipeline: TSC -> Babel -> Webpack):

  • Full production build: npm run build:prod — runs all 3 stages, outputs lib/ (CJS) and dist/SDK.min.js (UMD)
  • TypeScript only: npm run build:tsc — outputs to lib/ with declarations
  • Babel only: npm run build:babel — transpiles src/ to lib/ (ES5)
  • Webpack dev: npm run build:dev — outputs dist/SDK.js (unminified UMD)
  • Watch mode: npm run watch — Webpack in watch mode

Test:

  • Unit tests: npm test — Karma + Jasmine in headless Chrome
  • Lint: npm run lint — ESLint
  • Format: npm run format — Prettier

Build Pipeline Detail

Source (src/*.ts)
    │
    ├─ TSC ──────────→ lib/*.js + lib/*.d.ts   (CJS + declarations, published to npm)
    │                    target: ES5, strict: true
    │
    ├─ Babel ────────→ lib/*.js                 (overwritten, ES5 with polyfills)
    │                    presets: @babel/env, @babel/typescript
    │
    └─ Webpack ──────→ dist/SDK.min.js          (UMD bundle, libraryTarget: window)
                         entry: lib/index.js (prod) or src/index.ts (dev)

Why 3 stages? TSC generates type declarations. Babel handles the actual transpilation to ES5 with runtime polyfills. Webpack bundles everything into a single UMD file for <script> tag usage.

Test Infrastructure

  • Runner: Karma
  • Framework: Jasmine
  • Browser: ChromeHeadless (ChromeHeadlessCI with --no-sandbox in CI)
  • Coverage: Istanbul via @jsdevtools/coverage-istanbul-loader
  • Mocking: axios-mock-adapter for HTTP mocking
  • CI Reporter: @dhigroup/karma-vsts-reporter for Azure DevOps

Coding Standards

TypeScript Best Practices

  • Strict mode enabled in tsconfig.json
  • Avoid any type — use proper interfaces (existing any casts are marked with eslint-disable comments)
  • Explicit return types — all public methods have return types
  • Async/await — preferred over .then() chains
  • Use const unless the pointer will mutate, then let

SDK-Specific Patterns

Always use the timer + telemetry pattern:

const timer = Timer.TIMER();
this.logWithLogger(LogLevel.INFO, OCSDKTelemetryEvent.STARTED, "Description", requestId);
try {
    // ... operation
    const elapsedTimeInMilliseconds = timer.milliSecondsElapsed;
    this.logWithLogger(LogLevel.INFO, OCSDKTelemetryEvent.SUCCEEDED, "Description", requestId, response, elapsedTimeInMilliseconds, ...);
} catch (error) {
    const elapsedTimeInMilliseconds = timer.milliSecondsElapsed;
    this.logWithLogger(LogLevel.ERROR, OCSDKTelemetryEvent.FAILED, "Description", requestId, undefined, elapsedTimeInMilliseconds, ...);
}

Always check for timeout errors and wrap them:

if (isExpectedAxiosError(error, Constants.axiosTimeoutErrorCode)) {
    reject(new Error(this.HTTPTimeOutErrorMessage));
}

Always rotate AuthCodeNonce from response headers:

const { headers } = response;
this.setAuthCodeNonce(headers); // Updates this.configuration.authCodeNonce

Always add default headers:

this.addDefaultHeaders(requestId, requestHeaders);
// Adds: Oc-Sessionid, Ms-Oc-User-Agent, correlation ID

Auth vs Anonymous endpoints: Most methods have two endpoint paths — anonymous and authenticated. Switch based on the presence of authenticatedUserToken:

const basePath = authenticatedUserToken
    ? OmnichannelEndpoints.LiveChatAuthSessionInitPath
    : OmnichannelEndpoints.LiveChatSessionInitPath;

Reconnect ID handling: There are two modes for passing reconnect IDs — as a URL path segment or as a sig query parameter, controlled by useUnauthReconnectIdSigQueryParam:

const shouldUseSigQueryParam = !authenticatedUserToken && this.configuration.useUnauthReconnectIdSigQueryParam;
if (reconnectId) {
    if (shouldUseSigQueryParam) {
        params.sig = reconnectId;
    } else {
        requestPath += `/${reconnectId}`;
    }
}

Retry & Timeout Configuration

Default Retry Config

  • Max retries on failure: 5 (maxRequestRetriesOnFailure)
  • getChatToken retry count: 10 (getChatTokenRetryCount)
  • getChatToken retry interval: 10,000ms (getChatTokenTimeBetweenRetriesOnFailure)
  • Retry on 429: true for getChatToken (getChatTokenRetryOn429), getChatConfig (getChatConfigRetryOn429), sessionInit, and createConversation; false by default for others
  • Retry strategy: Exponential backoff (2^retryCount * waitTime), respects retry-after header (seconds or HTTP-date), 5s fallback on 429; all delays add up to 1s of positive jitter
  • Retryable conditions: 5xx status, network errors, no response, optionally 429

Default Timeouts (per endpoint)

EndpointTimeout
getChatConfig120,000ms
getChatTranscripts30,000ms
getChatToken, sessionInit, sessionClose, getLWIDetails, getReconnectableChats, getReconnectAvailability, submitPostChatResponse, getSurveyInviteLink, getAgentAvailability, validateAuthChatRecord, getPersistentChatHistory15,000ms
emailTranscript, fetchDataMaskingInfo, sendTypingIndicator5,000ms

Integration with Other Repos

This SDK integrates with:

  • CRM.Omnichannel (Backend): All livechatconnector/* REST APIs in the Omnichannel gateway

Consumed by:

  • omnichannel-chat-sdk (@microsoft/omnichannel-chat-sdk) — Primary consumer. Wraps ocsdk methods and adds conversation lifecycle management, adapter handling, and WebSocket coordination.
  • CRM.OmniChannel.LiveChatWidget — Indirect consumer via chat-sdk

Dependency direction:

LiveChatWidget → chat-widget → chat-sdk → ocsdk (this package)
                                         → amsclient

When changing public APIs:

  • This is consumed by omnichannel-chat-sdk — breaking changes require coordinated releases
  • The ISDK interface (src/Interfaces/ISDK.ts) is the public contract
  • Update CHANGELOG.md under [Unreleased] with all changes
  • Use semantic versioning: major version for breaking changes

Testing Strategy

Unit Tests (Karma + Jasmine):

  • Location: test/ directory
  • Run: npm test
  • Mocking: axios-mock-adapter for HTTP call mocking

Test files:

  • test/SDK.spec.ts — Tests for all SDK API methods
  • test/SDKProvider.spec.ts — Factory tests
  • test/Common/OCSDKLogger.spec.ts — Logger tests
  • test/Utils/*.spec.ts — Utility function tests

Test Best Practices:

  • Mock axios responses using axios-mock-adapter
  • Include headers in all response mocks (required since Webpack 5 migration)
  • Use async/await patterns (not mixing done callbacks with promises)
  • Test both success and error paths for every API method
  • Test timeout handling (verify ClientHTTPTimeoutError is thrown)
  • Test auth vs anonymous endpoint selection

Common Issues & Troubleshooting

Build Issues:

  • NODE_OPTIONS=--openssl-legacy-provider required for production build — the build script includes cross-env to set this
  • 3-stage build is slow — TSC, then Babel, then Webpack. For development, use npm run build:dev (Webpack only from source)
  • Clear node_modules: rm -rf node_modules && npm install

Test Issues:

  • Tests run in ChromeHeadless via Karma — ensure Chrome/Chromium is installed
  • In CI, use ChromeHeadlessCI launcher (set CI=true env var) for --no-sandbox flags
  • Test mocks must include headers property on response objects

Authentication Issues:

  • vsts-npm-auth -config .npmrc if internal dependency resolution fails

Runtime Issues:

  • process is not defined in browser — Webpack 5 removed Node.js polyfills; webpack.common.js uses ProvidePlugin to polyfill process
  • AuthCodeNonce rotation — if requests fail with auth errors, verify the nonce is being properly rotated from response headers via setAuthCodeNonce()

Documentation

  • README.md — SDK usage examples, initialization, API calls
  • CHANGELOG.md — Release history from v0.1.0 to v0.5.21
  • SECURITY.md — Security policies
  • CODE_OF_CONDUCT.md — Microsoft Open Source Code of Conduct

Pull Request Guidelines

  1. Code standards: Follow TypeScript strict mode, avoid any types
  2. Testing: All Karma tests must pass, add tests for new API methods
  3. Telemetry: Every API method must log start/succeed/fail events with timers
  4. Error handling: Wrap timeout errors as ClientHTTPTimeoutError, propagate others
  5. CHANGELOG: Update CHANGELOG.md under [Unreleased] section
  6. Auth parity: If adding a new endpoint, provide both authenticated and anonymous paths
  7. Retry configuration: Add per-endpoint timeout and wait-time-between-retries configs

Summary: This is the lowest-level HTTP client (@microsoft/ocsdk) in the Omnichannel frontend stack. It wraps livechatconnector REST APIs with axios + retry logic, per-endpoint timeouts, auth header management, and telemetry logging. Uses a 3-stage build (TSC -> Babel -> Webpack). Consumed primarily by @microsoft/omnichannel-chat-sdk. Always follow the timer + telemetry + retry pattern for new methods.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.