npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@koi-design/callkit

v2.3.0-beta.8

Published

callkit

Readme

@koi-design/callkit

SIP-based Web Phone Call Toolkit

Installation

NPM Installation

pnpm add @koi-design/callkit

Dependencies

This package requires the following peer dependencies:

{
  "dependencies": {
    "axios": "~0.26.1",
    "blueimp-md5": "^2.12.0",
    "sip.js": "^0.21.2"
  }
}

Quick Start

Method 1: IIFE (Browser Global)

<script src="koi-design/callkit/dist/index.global.js"></script>
<script>
  const callKit = new WebCall.CallKit({
    host: 'https://example.com',
    log: 'debug',
    audioRef: () => document.querySelector('#audioRef'),
    socket: 'wss://example.com/ws/in-call'
  });
</script>

Method 2: ESM Import

import { CallKit } from '@koi-design/callkit';

const callKit = new CallKit({
  host: 'https://example.com',
  log: 'debug',
  audioRef: () => document.querySelector('#audioRef'),
  socket: 'wss://example.com/ws/in-call'
});

Method 3: CommonJS Import

const { CallKit } = require('@koi-design/callkit');

const callKit = new CallKit({
  host: 'https://example.com',
  log: 'debug',
  audioRef: () => document.querySelector('#audioRef'),
  socket: 'wss://example.com/ws/in-call'
});

API Documentation

Configuration Options

interface CallKitConfig {
  // Request host address
  host: string;

  // Audio element object
  audioRef: HTMLAudioElement | (() => HTMLAudioElement);

  // WebSocket address
  socket: string;

  // WebRTC constraint configuration
  constrains?: WebrtcConstranis;

  // Log level
  log?: 'info' | 'success' | 'warn' | 'error' | 'silent';

  // Reconnection configuration
  reconnect?: {
    // SIP reconnection configuration
    sip: {
      enabled: boolean; // Enable SIP reconnection (default: true)
      maxAttempts: number; // Maximum reconnection attempts (default: 5)
      delay: number; // Reconnection delay in ms (default: 3000)
    // In-call socket reconnection configuration
    incall: {
      enabled: boolean; // Enable in-call reconnection (default: true)
      maxAttempts: number; // Maximum reconnection attempts (default: 5)
      delay: number; // Reconnection delay in ms (default: 3000)
      pingInterval: number; // Heartbeat interval in ms (default: 30000)
      pingTimeout: number; // Heartbeat timeout in ms (default: 10000)
    };
  };

  // Track logs configuration
  trackLogs?: {
    enabled: boolean; // Enable log tracking (default: false)
    interval: number; // Log upload interval in ms (default: 10000)
    maxSize: number; // Maximum log buffer size (default: 100)
  };
}

interface WebrtcConstranis {
  audio: {
    autoGainControl?: boolean;
    noiseSuppression?: boolean;
    echoCancellation?: boolean;
  };
  video: false;
}

Instance Methods

interface CallKit {
  // User login
  login(
    username: string,
    password: string,
    extra?: {
      encryptionMethod?: 'INTERNAL' | 'NONE';
      [key: string]: any;
    }
  ): Promise<void>;

  // User logout
  logout(options?: { isReset?: boolean }): Promise<void>;

  // Initiate call
  call(
    extno: string | number,
    options?: {
      sourceType?: number;
      workOrderId?: string;
    }
  ): Promise<void>;

  // Transfer call
  refer(uri: string, options?: any): Promise<void>;

  // SIP registration
  register(): Promise<void>;

  // SIP unregistration
  unregister(): Promise<void>;

  // Hang up call
  hangup(): Promise<void>;

  // Call hold
  hold(): void;

  // Release hold
  unhold(): void;

  // Mute microphone
  mute(): void;

  // Unmute microphone
  unmute(): void;

  // Set user status (manually)
  setUserStatus(status: number): Promise<void>;

  // Reset all states
  reset(config?: { force?: boolean }): Promise<void>;

  // Event listener
  on(event: string, callback: Function): void;

  // Remove event listener
  off(event: string, callback?: Function): void;

  // Remove all event listeners
  removeAllListeners(): void;
}

Event List

Status Change Events

  • loginChange - Login status change (param: boolean)
  • registerChange - Registration status change (param: boolean)
  • callStatusChange - Call status change (param: CallStatus)
  • callIdChange - Call ID change (param: string)
  • holdChange - Hold status change (param: boolean)
  • muteChange - Mute status change (param: boolean)

Call Events

  • invite - Received incoming call invitation
    • Callback params: { accept: Function, reject: Function, getInviteData: Function }
  • outgoingInvite - Received outgoing call invitation
  • connecting - Call connecting (param: timestamp)
  • ringing - Remote party ringing (param: timestamp)
  • pickUp - Remote party answered (param: timestamp)
  • agentPickUp - Agent connected (param: timestamp)
  • hangUp - Remote party hung up (param: timestamp)
  • noAnswer - No answer (param: timestamp)
  • callEnd - Call ended (param: timestamp)
  • callCdr - Call detail record push (param: CDR data)

Connection Events

  • IncallConnectEvent - In-call socket connection event
  • sipConnectEvent - SIP connection event
  • sipRegistererEvent - SIP registerer event
  • sipSessionEvent - SIP session event

System Events

  • log - System log event
  • error - Error occurred (param: { code: number, message: string })
  • socketEvent - Forward all socket events (param: socket message)

Status Codes

Call Status

const CallStatus = {
  init: 0, // Initial state/hung up
  connecting: 2, // Connecting
  ringing: 4, // Ringing
  calling: 5 // In call
};

Note: In version 2.0.0+, registered and holding statuses have been removed. Registration status is now tracked separately via the registerChange event.

User Status

Note: In version 2.0.0+, user status management has been removed from CallKit. You should maintain user status through your own application using the setUserStatus method.

// Example user status codes (define as needed in your application)
const UserStatus = {
  offline: 1, // Offline
  online: 2, // Online & Free
  catNap: 3, // Cat Nap
  busy: 4, // Busy
  training: 5, // Training
  processing: 6 // Processing
};

// Set user status manually
await callKit.setUserStatus(UserStatus.online);

Error Codes

const ErrorCode = {
  // Unknown error
  UNKNOWN_ERROR: -1,

  // API errors (1000xxx)
  API_USER_LOGIN_ERROR: 1000001, // User login failed
  API_USER_STATUS_UPDATE_ERROR: 1000002, // Update user status failed
  API_USER_LOGOUT_ERROR: 1000003, // User logout failed

  // WebRTC errors (2000xxx)
  CONNECT_CALL_STATUS_ERROR: 2000001, // Call status exception
  USER_NOT_LOGIN: 2000002, // User not logged in
  WEBRTC_USER_MEDIA_ERROR: 2000003, // WebRTC not supported
  WEBRTC_HOLE_STATUS_ERROR: 2000004, // Call hold failed
  WEBRTC_AUDIO_PLAYER_ERROR: 2000005, // Audio player does not exist
  WEBRTC_AUDIO_PLAY_ERROR: 2000006, // Audio playback failed
  WEBRTC_USER_AGENT_ERROR: 2000007, // User agent startup failed
  WEBRTC_CALL_INVITE_ERROR: 2000008, // Call request failed
  WEBRTC_REGISTER_ERROR: 2000009, // Register request failed
  WEBRTC_MUTE_STATUS_ERROR: 2000010, // Mute failed
  WEBRTC_CANCEL_REGISTER_ERROR: 2000011, // Unregister failed
  WEBRTC_MUTE_ERROR: 2000012, // Mute operation failed

  // WebSocket errors (3000xxx)
  SOCKET_CONNECT_ERROR: 3000001, // Connection exception
  SOCKET_PING_TIMEOUT: 3000002, // Ping timeout
  SOKET_SERVER_ERROR: 3000003, // Server exception
  SOCKET_CALL_ERROR: 3000004, // Call failed
  SOCKET_RECONNECT_FAILED: 3000005 // Reconnection limit exceeded
};

FAQ

Q1: How to listen for call status changes?

callKit.on('callStatusChange', (status) => {
  const statusMap = {
    0: 'Initial state',
    2: 'Connecting',
    4: 'Ringing',
    5: 'In call'
  };
  console.log('Current status:', statusMap[status]);
});

Q2: How to listen for registration status changes?

callKit.on('registerChange', (isRegistered) => {
  console.log(
    'Registration status:',
    isRegistered ? 'Registered' : 'Unregistered'
  );
});

Q3: How to get call duration?

let startTime;

callKit.on('pickUp', (date) => {
  startTime = date;
});

callKit.on('callEnd', (date) => {
  const duration = date - startTime;
  console.log('Call duration (ms):', duration);
});

Q4: How to handle incoming calls?

callKit.on('invite', ({ accept, reject, getInviteData }) => {
  // Get call data
  const inviteData = getInviteData();
  console.log('Incoming call:', inviteData);

  // Accept the call
  accept();

  // Or reject the call
  // reject();
});

Q5: How to handle errors?

callKit.on('error', (error) => {
  console.error('Error code:', error.code);
  console.error('Error message:', error.message);

  switch (error.code) {
    case 1000001:
      // Handle login failure
      break;
    case 2000002:
      // Handle not logged in error
      break;
    case 3000005:
      // Handle reconnection failure
      break;
    // ...other error handling
  }
});

Q6: How to handle reconnection?

// Listen to reconnection events
callKit.on('IncallConnectEvent', (event) => {
  console.log('In-call connection event:', event);
});

callKit.on('sipConnectEvent', (event) => {
  console.log('SIP connection event:', event);
});

// Configure reconnection options
const callKit = new CallKit({
  host: 'https://example.com',
  socket: 'wss://example.com/ws/in-call',
  audioRef: () => document.querySelector('#audioRef'),
  reconnect: {
    sip: {
      enabled: true,
      maxAttempts: 5,
      delay: 3000
    },
    incall: {
      enabled: true,
      maxAttempts: 5,
      delay: 3000
    }
  }
});

Q7: How to use mute/unmute?

// Mute microphone
callKit.mute();

// Unmute microphone
callKit.unmute();

// Listen to mute status changes
callKit.on('muteChange', (isMuted) => {
  console.log('Mute status:', isMuted ? 'Muted' : 'Unmuted');
});

Q8: How to use hold/unhold?

// Hold call
callKit.hold();

// Unhold call
callKit.unhold();

// Listen to hold status changes
callKit.on('holdChange', (isHeld) => {
  console.log('Hold status:', isHeld ? 'On hold' : 'Active');
});

More Information

For complete TypeScript type definitions, please refer to index.d.ts

Breaking Changes in v2.0.0

Major Changes

  1. User Status Management Removed

    • CallKit no longer automatically manages user status
    • Use setUserStatus() method to manually maintain user status
  2. Registration Status Separated

    • Registration status is no longer part of call status
    • Use registerChange event to track registration status independently
  3. Call Status Simplified

    • Removed registered (1) status - use registerChange event instead
    • Removed holding (3) status - use holdChange event instead
    • Current statuses: init (0), connecting (2), ringing (4), calling (5)
  4. Enhanced Reconnection Mechanism

    • Completely refactored SIP and socket reconnection logic
    • Added configurable reconnection options for both SIP and in-call connections
    • New error code: SOCKET_RECONNECT_FAILED (3000005)
  5. New Methods

    • mute() / unmute() - Control microphone muting
    • refer(uri, options) - Transfer calls
    • off(event, callback) - Remove specific event listeners
    • removeAllListeners() - Remove all event listeners
    • setUserStatus(status) - Manually set user status
  6. New Events

    • callIdChange - Call ID change event
    • outgoingInvite - Outgoing call invitation event
    • hangUp - Remote party hang up event
    • IncallConnectEvent - In-call socket connection event
    • sipConnectEvent - SIP connection event
    • sipRegistererEvent - SIP registerer event
    • sipSessionEvent - SIP session event

Migration Guide

Please refer to MIGRATION.md for detailed migration instructions from v1.x to v2.0.

License

MIT