npm package: @knmholdings/phone-sdk
Description: A React-based SIP softphone SDK for web applications.
Author: Hung Luu
Latest version: 0.1.18
Deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

# KNM Phone SDK (React)

A reusable React-based SIP softphone SDK for web applications, built with SIP.js, React, TypeScript, and Tailwind CSS.

[![npm version](https://badge.fury.io/js/%40knmholdings%2Fphone-sdk.svg)](https://badge.fury.io/js/%40knmholdings%2Fphone-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

This SDK provides a floating button and a modal interface for making and receiving SIP calls via WebRTC, designed to be easily embeddable into existing web pages or modern JavaScript applications.

**Features:**

- SIP Registration (Username/Password Authentication)
- Outgoing Calls via Dialpad
- Incoming Call Notifications (In-Modal and OS-level Web Notifications)
- Call Transfer (Blind Transfer)
- Mute/Unhold Call Functionality
- Call History & Recording Playback (requires backend API integration)
- Basic In-Call UI (Caller ID, Timer, Hangup)
- Configurable Server Settings & Customer Info Fetching
- Style isolation using Shadow DOM
- Built with modern web technologies: React, TypeScript, SIP.js, Tailwind CSS.
- Real-time audio stream monitoring via `phone:localAudio` and `phone:remoteAudio` events

## Installation

You can integrate the KNM Phone SDK into your project in two main ways:

**1. Using npm/pnpm/yarn (Recommended for Modern JavaScript/TypeScript Projects)**

This method is best for projects using module bundlers like Vite, Next.js, Create React App, etc. It allows for better tree-shaking and version management.

```bash
# Using npm
npm install @knmholdings/phone-sdk

# Using pnpm
pnpm add @knmholdings/phone-sdk

# Using yarn
yarn add @knmholdings/phone-sdk
```

See the [ES Module (ESM) Integration](#es-module-esm-integration) section below for usage details.

**2. Using UMD Build via CDN (For simple HTML pages)**

This method is suitable for static HTML pages or projects not using a JavaScript module bundler.

See the [UMD / CDN Integration](#umd--cdn-integration) section below for usage details.

---

## ES Module (ESM) Integration (Recommended for Frameworks)

This is the preferred method for integrating with modern JavaScript frameworks like Next.js, React (Vite/CRA), Vue, Angular, etc.

1.  **Install the package** (as shown in the Installation section above).

2.  **Import and Initialize in your application:**
    It's crucial to initialize the SDK in a client-side environment, typically within a `useEffect` hook in a React component. For Next.js, ensure this is done within a Client Component (`"use client";`).

    ```typescript
    // Example: In a React component (e.g., your main App component or a specific layout)
    import React, { useEffect } from 'react';
    import KnmPhoneSDK, {
      type PhoneSDKConfig, // Import types for configuration
      type CustomerInfo    // Import types for data structures
    } from '@knmholdings/phone-sdk';

    function MyAppComponent() {
      useEffect(() => {
        // Ensure this runs only once and on the client side
        if (typeof window !== "undefined") {
          console.log('Initializing KNM Phone SDK (ESM)...');

          const myGetCustomerInfo = async (callerId: string): Promise<CustomerInfo | null> => {
            console.log("Host App: Fetching info for caller:", callerId);
            // Replace with your actual API call or logic
            if (callerId === '1003') {
              return { name: 'ESM Customer', avatarUrl: 'https://via.placeholder.com/100/000/fff?text=EC' };
            }
            return null;
          };

          const sdkConfig: PhoneSDKConfig = {
            // --- REQUIRED ---
            sipHost: 'your-sip-provider.com', // *** REPLACE THIS ***

            // --- OPTIONAL BUT RECOMMENDED FOR SHADOW DOM CSS ---
            // The SDK needs to fetch its CSS for Shadow DOM.
            // Point to the style.css file on a CDN like unpkg.
            // For production, pin to a specific SDK version for stability.
            cssBuildPath: 'https://unpkg.com/@knmholdings/phone-sdk/dist/style.css',

            // --- OTHER OPTIONAL CONFIG ---
            webSocketUrl: 'wss://your-sip-provider.com:8089/ws',
            renderButton: true,
            getCustomerInfo: myGetCustomerInfo,
            onCallStop: () => {
              console.log('Call stopped');
            },
            onCallModalOpenChange: (isOpen) => {
              console.log('Call modal open state changed:', isOpen);
            },
            // containerId: 'my-custom-phone-container'
          };

          KnmPhoneSDK.init(sdkConfig);
        }

        // Cleanup function when the component unmounts
        return () => {
          if (typeof window !== "undefined" && window.KnmPhoneSDK) {
            console.log('Unmounting KNM Phone SDK (ESM)...');
            KnmPhoneSDK.unmount();
          }
        };
      }, []); // Empty dependency array ensures init runs only once on mount

      const openPhone = () => KnmPhoneSDK.open();
      const closePhone = () => KnmPhoneSDK.close();

      // Get call ID
      const callId = KnmPhoneSDK.getCallId();

      return (
        <div>
          <h1>My Application (ESM Integration)</h1>
          <button onClick={openPhone}>Open Phone</button>
          <button onClick={closePhone}>Close Phone</button>
          {/* Optional: <div id="my-custom-phone-container"></div> */}
          {/* Rest of your app */}
        </div>
      );
    }

    export default MyAppComponent;
    ```

    - **Replace placeholders** like `'your-sip-provider.com'`.
    - **CSS Path:** The `cssBuildPath` should point to the `style.css` from the SDK version you installed, typically hosted on unpkg. For production, it's highly recommended to use a specific version in the URL (e.g., `https://unpkg.com/@knmholdings/phone-sdk@0.1.5/dist/style.css`) instead of relying on `@latest`.

---

## UMD / CDN Integration

This method is suitable for static HTML pages or projects not using a JavaScript module bundler.

1.  **Include Scripts in HTML:** Add the following to the `<head>` of your HTML file:

    ```html
    <head>
      <!-- ... other head elements ... -->
      <title>My Page with KNM Phone SDK</title>

      <!-- 1. React & ReactDOM Dependencies (from CDN) -->
      <script crossorigin src="https://unpkg.com/react@18.2.0/umd/react.production.min.js"></script>
      <script
        crossorigin
        src="https://unpkg.com/react-dom@18.2.0/umd/react-dom.production.min.js"
      ></script>

      <!-- 2. SDK's UMD JavaScript Build (from unpkg) -->
      <!-- This will fetch the latest version. Pin to a specific version for production. -->
      <script src="https://unpkg.com/@knmholdings/phone-sdk/dist/knm-phone.umd.js"></script>

      <!-- 3. SDK's CSS is fetched internally by the SDK when using Shadow DOM -->
      <!-- No separate <link> tag is needed here if cssBuildPath is configured correctly during init -->
    </head>
    ```

2.  **Initialize the SDK:** Add a `<script>` block to initialize:

    ```html
    <body>
      <!-- ... your page content ... -->
      <script>
        document.addEventListener('DOMContentLoaded', () => {
          if (window.KnmPhoneSDK) {
            window.KnmPhoneSDK.init({
              sipHost: 'your-sip-provider.com', // *** REPLACE THIS ***
              // For production, pin to a specific SDK version for stability.
              cssBuildPath: 'https://unpkg.com/@knmholdings/phone-sdk/dist/style.css',
              // ... other config ...
            });
          }
        });
      </script>
    </body>
    ```

    - **Replace placeholders** and consider pinning to a specific SDK version in the unpkg URLs for production stability (e.g., `https://unpkg.com/@knmholdings/phone-sdk@0.1.5/dist/...`).

---

## Configuration

The SDK is configured via an options object passed to `KnmPhoneSDK.init()`.

- `sipHost: string` (**Required**): SIP server domain or IP.
- `webSocketUrl?: string`: Full WebSocket URL. Defaults to `wss://{sipHost}:8089/ws`.
- `cssBuildPath?: string`: Absolute URL to the SDK's `style.css` file. **Required if using Shadow DOM** (default for style isolation) to allow the SDK to inject its styles. Example: `'https://unpkg.com/@knmholdings/phone-sdk/dist/style.css'`.
- `renderButton?: boolean`: Show the floating phone button. Defaults to `true`.
- `buttonColor?: string`: Floating button background color (hex code).
- `buttonTextColor?: string`: Floating button icon color (hex code).
- `containerId?: string`: ID of an HTML element to render the SDK into. Defaults to a new div in `body`.
- `getCustomerInfo?: (callerId: string) => Promise<CustomerInfo | null | undefined>`: Callback to fetch info for the incoming caller. See [Typing & API Reference](#typing--api-reference) for `CustomerInfo` type.
- `onCallStop?: (params: CallStopParams) => void`: Callback triggered when a call ends.
- `onCallModalOpenChange?: (isOpen: boolean) => void`: Callback triggered when the call modal opens or closes.

### Events & Callbacks

#### `phone:localAudio` & `phone:remoteAudio`

These events provide access to live audio streams:

```javascript
window.addEventListener('phone:remoteAudio', (event) => {
  const stream = event.detail.stream; // Remote audio MediaStream
  // Visualize or process stream
});

window.addEventListener('phone:localAudio', (event) => {
  const stream = event.detail.stream; // Local microphone MediaStream
  // Monitor input levels
});
```

#### `onCallStop` Callback

Triggered when a call ends:

```typescript
// In config:
{
  onCallStop: () => {
    // Handle call cleanup
    console.log(`Call ended. Clean up the process.`);
  };
}
```

## API

The SDK exposes methods on the imported `KnmPhoneSDK` object (for ESM) or the global `window.KnmPhoneSDK` object (for UMD):

- `init(config: PhoneSDKConfig): void`: Initializes the SDK.
- `open(): void`: Opens the phone modal.
- `close(): void`: Closes the phone modal.
- `unmount(): void`: Unmounts the SDK and cleans up resources.
- `callAgentFirst(customerNumber: string): Promise<boolean>`: Initiates a two-legged call (agent first, then customer). Requires backend API integration.

## Typing & API Reference (for TypeScript Users)

The SDK includes TypeScript declaration files for a better development experience.

1.  **Installation (for Type Support):**
    If using the UMD build, you can still install the package as a dev dependency to get type information in your editor:

    ```bash
    npm install --save-dev @knmholdings/phone-sdk
    ```

    If using ESM, types are automatically available after installation.

2.  **Using Types:**
    Import types in your TypeScript files or use JSDoc for type hinting in JavaScript.

    **TypeScript Example (when SDK is installed):**

    ```typescript
    import KnmPhoneSDK, { type PhoneSDKConfig, type CustomerInfo } from '@knmholdings/phone-sdk';

    const sdkConfig: PhoneSDKConfig = {
      /* ... */
    };
    // KnmPhoneSDK.init(sdkConfig); // If using ESM import
    // For UMD, you might declare window.KnmPhoneSDK type
    ```

3.  **Key Exported Types:**

    - `PhoneSDKConfig`: Interface for the `init()` configuration object.
    - `CustomerInfo`: Interface for the object expected from `getCustomerInfo`.

    Refer to the `dist/types/PhoneSDK.d.ts` file within the installed package for full type details.

## Styling

The SDK uses Tailwind CSS and renders its UI inside a **Shadow DOM** for style isolation. The necessary CSS is loaded from the `style.css` file (via the `cssBuildPath` configuration) and injected into the Shadow DOM.

## Development (Contributing)

1.  **Clone:** `git clone <repository-url>`
2.  **Install:** `pnpm install`
3.  **Configure Dev SIP:** Modify `src/main.tsx` with test SIP details.
4.  **Run Dev Server:** `pnpm dev`
5.  **Build Library:** `pnpm build` (outputs to `dist/`)
    - To publish: Increment version in `package.json`, create a GitHub Release (triggers npm publish workflow).

## License

[MIT](./LICENSE)