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

voxnix

v1.0.19

Published

Universal Voice Widget SDK — SIP-based floating phone widget. Works in React, Vue, Angular, plain HTML, or any stack.

Readme

Voxnix

Universal Voice Widget SDK — SIP-based floating phone widget. Works in React, Vue, Angular, plain HTML, or any stack.

Current version: 1.0.12


What it does

  • Floating phone button (fixed position, configurable placement)
  • Auto-connects to your SIP/PABX server on init
  • Shows dialer numpad immediately after registration
  • Full call UI: incoming call, outgoing dialing, in-call controls (mute, hold, DTMF keypad)
  • Agent status bar — Ready / Not Ready / AUX with optional custom AUX codes
  • Fires callbacks for all call and agent-status events so your app can react
  • Keyboard shortcuts: digits to dial, Enter to call, Backspace to delete, 0–9/*/# for DTMF during a call

Installation

npm install voxnix
# or
yarn add voxnix

Quick start (any framework)

import { OmnixWidget } from 'voxnix';

const widget = OmnixWidget.init({
  auth: {
    username:  '1001',
    pwd_pbx:   'secret',
    pabx_host: 'sip.example.com',
    port:       8089,          // optional, default 8089
  },

  // Required for agent status API (Ready / AUX / Not Ready)
  'X-CPAAS-Key-Fingerprint': 'your-cpaas-key-fingerprint-here',

  placement: 'bottom-left',   // 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'

  // Agent status options (optional)
  autoReady:     true,         // auto-set agent to Ready after SIP register (default: true)
  showAuxButton: false,        // show AUX button in status bar (default: false)
  auxOptions:    [],           // array of { code, label } — custom AUX codes

  // Callbacks
  onRegisterStatus: (status) => {
    // status: 'REGISTERED' | { status: 'FAILED', reason: string }
    console.log('SIP status:', status);
  },
  onAgentStatus:    (status) => console.log('Agent:', status),  // 'READY' | 'NOT_READY' | 'AUX'
  onIncomingCall:   (data)   => console.log('Incoming:', data),
  onCallAnswered:   (data)   => console.log('Answered:', data),
  onCallEnded:      (data)   => console.log('Ended:', data),
  onCallUnanswered: ()       => console.log('Missed call'),
});

// Imperative controls (optional — widget has its own UI)
widget.answer();
widget.hangup();
widget.reject();
widget.mute(true);    // mute
widget.mute(false);   // unmute
widget.hold(true);    // hold
widget.hold(false);   // resume
widget.dial('1002');  // programmatic dial
widget.destroy();     // unmount widget

Config reference

Top-level options

| Option | Type | Default | Description | |-----------------------------|--------------------------------------------------------------------|-----------------|-----------------------------------------------------------------| | auth | object | — | SIP credentials (see auth object) | | pabxConfig | { auth: object } | — | Alternative config shape — use pabxConfig.auth instead of auth | | X-CPAAS-Key-Fingerprint | string | — | Required for agent status API calls. See section below | | fingerprint | string | — | Alias for X-CPAAS-Key-Fingerprint | | cpaasKeyFingerprint | string | — | Alias for X-CPAAS-Key-Fingerprint | | placement | 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right' | 'bottom-left' | Fixed position of the floating widget | | offset | { bottom?, top?, left?, right? } | — | CSS pixel coords — overrides placement | | container | string | HTMLElement | — | Mount target. Auto-creates <div id="omnix-widget-root"> if omitted | | autoReady | boolean | true | Auto-call the Ready API right after SIP registration | | showAuxButton | boolean | false | Show the AUX menu in the agent status bar | | auxOptions | Array<{ code: string, label: string }> | [] | Custom AUX reason codes shown in the status dropdown | | onRegisterStatus | (status) => void | — | 'REGISTERED' or { status: 'FAILED', reason: string } | | onAgentStatus | (status: string) => void | — | 'READY' | 'NOT_READY' | 'AUX' | | onIncomingCall | (data) => void | — | Fired on incoming SIP INVITE | | onCallAnswered | (data) => void | — | Fired when call is established | | onCallEnded | (data) => void | — | Fired on BYE / hangup | | onCallUnanswered | () => void | — | Fired when incoming call is not answered (missed) |

auth object

| Field | Type | Description | |-------------|----------|------------------------------------------| | username | string | SIP username / extension number | | user_pbx | string | Alias for username | | pwd_pbx | string | SIP password | | secret | string | Alias for pwd_pbx | | pabx_host | string | SIP domain / WSS host (strips http(s)://) | | pbxurl | string | Alias for pabx_host | | port | number | WSS port (default 8089) |


X-CPAAS-Key-Fingerprint

This key is the API authentication credential used when the widget calls the CPaaS extension status endpoint:

POST https://api-cpaas.omnix.co.id/voice/extensions/status
Header: X-CPAAS-Key-Fingerprint: <your-fingerprint>

The endpoint is hit automatically whenever the agent status changes (Ready / AUX / Not Ready). Without this key, status updates will silently fail and — if autoReady: true (default) — the widget will report FAILED registration even if the SIP connection itself succeeded.

Accepted config locations

The widget looks for the fingerprint in the following order, using the first match:

| Priority | Config key | Example | |----------|------------|---------| | 1 | 'X-CPAAS-Key-Fingerprint' (top-level) | { 'X-CPAAS-Key-Fingerprint': 'abc123', auth: { ... } } | | 2 | fingerprint (top-level) | { fingerprint: 'abc123', auth: { ... } } | | 3 | cpaasKeyFingerprint (top-level) | { cpaasKeyFingerprint: 'abc123', auth: { ... } } | | 4 | env.fingerprint | { env: { fingerprint: 'abc123' }, auth: { ... } } | | 5 | env.X_CPAAS_Key_Fingerprint | { env: { X_CPAAS_Key_Fingerprint: 'abc123' }, auth: { ... } } | | 6 | pabxConfig['X-CPAAS-Key-Fingerprint'] | { pabxConfig: { 'X-CPAAS-Key-Fingerprint': 'abc123', auth: { ... } } } |

Recommended usage

// Option A — top-level key (simplest)
OmnixWidget.init({
  'X-CPAAS-Key-Fingerprint': 'your-fingerprint-here',
  auth: { username: '1001', pwd_pbx: 'secret', pabx_host: 'sip.example.com' },
  autoReady: true,
});

// Option B — inside pabxConfig (if your backend returns this shape)
OmnixWidget.init({
  pabxConfig: {
    'X-CPAAS-Key-Fingerprint': 'your-fingerprint-here',
    auth: { username: '1001', pwd_pbx: 'secret', pabx_host: 'sip.example.com' },
  },
});

// Option C — via env object
OmnixWidget.init({
  env: { fingerprint: 'your-fingerprint-here' },
  auth: { username: '1001', pwd_pbx: 'secret', pabx_host: 'sip.example.com' },
});

Important: If the fingerprint is missing and autoReady: true (default), the widget will emit { status: 'FAILED', reason: 'Failed to hit extension ready API' } via onRegisterStatus even though the SIP connection itself was successful. Set autoReady: false if you do not have a fingerprint yet.

Custom container / offset

OmnixWidget.init({
  container: '#my-widget-slot',   // CSS selector or DOM element
  // — or —
  offset: { bottom: 80, left: 10 }, // exact pixel position (bypasses placement)
  // ... rest of config
});

Instance API

OmnixWidget.init() returns an instance with these methods:

| Method | Description | |----------------|------------------------------------------------------------| | answer() | Answer the current incoming call | | hangup() | End the active / outgoing call | | reject() | Reject the current incoming call | | mute(bool) | true = mute microphone, false = unmute | | hold(bool) | true = put call on hold, false = resume | | dial(number) | Programmatically dial a number string | | destroy() | Unmount the widget and clean up the DOM container |


Agent status bar

When autoReady: false or showAuxButton: true a status bar appears at the bottom of the dialer.

Note: The agent status bar calls the CPaaS extension status API. You must provide X-CPAAS-Key-Fingerprint (or one of its aliases) for these calls to succeed.

OmnixWidget.init({
  auth: { ... },
  'X-CPAAS-Key-Fingerprint': 'your-fingerprint-here',
  autoReady:     false,          // agent starts as NOT_READY; must go Ready manually
  showAuxButton: true,           // show AUX dropdown
  auxOptions: [
    { code: 'BRK', label: 'Break' },
    { code: 'LCH', label: 'Lunch' },
    { code: 'TRN', label: 'Training' },
  ],
  onAgentStatus: (status) => console.log('Agent status changed:', status),
});

| Status | Badge colour | Meaning | |-------------|--------------|--------------------------------------| | READY | 🟢 Green | Agent is available for calls | | NOT_READY | ⚪ Gray | Agent is unavailable | | AUX | 🟡 Amber | Agent is on a break / custom reason |


React integration

import { useEffect, useRef } from 'react';
import { OmnixWidget } from 'voxnix';

function App() {
  const widgetRef = useRef(null);

  useEffect(() => {
    widgetRef.current = OmnixWidget.init({
      auth: {
        username:  '1001',
        pwd_pbx:   'secret',
        pabx_host: 'sip.example.com',
      },
      'X-CPAAS-Key-Fingerprint': 'your-fingerprint-here',
      placement:    'bottom-right',
      autoReady:    true,
      showAuxButton: true,
      auxOptions:   [{ code: 'BRK', label: 'Break' }],

      onIncomingCall:   (data) => { /* navigate, show notification, etc. */ },
      onCallAnswered:   (data) => { /* routing logic */ },
      onCallEnded:      ()     => { /* cleanup */ },
      onRegisterStatus: (s)    => { /* update UI */ },
      onAgentStatus:    (s)    => { /* s: 'READY' | 'NOT_READY' | 'AUX' */ },
    });

    return () => widgetRef.current?.destroy();
  }, []);

  return <div id="app">...</div>;
}

Vue integration

import { OmnixWidget } from 'voxnix';

// inside setup() or options API
onMounted(() => {
  const widget = OmnixWidget.init({
    auth: { username: '1001', pwd_pbx: 'secret', pabx_host: 'sip.example.com' },
    'X-CPAAS-Key-Fingerprint': 'your-fingerprint-here',
    autoReady: false,
    showAuxButton: true,
    auxOptions: [{ code: 'BRK', label: 'Break' }],
  });
  onUnmounted(() => widget.destroy());
});

Via CDN (plain HTML, no bundler)

<!-- Self-contained IIFE build (bundles React) -->
<script src="https://unpkg.com/voxnix/dist/voxnix.iife.js"></script>
<script>
  OmnixWidget.init({
    auth: {
      username:  '1001',
      pwd_pbx:   'secret',
      pabx_host: 'sip.example.com',
    },
    'X-CPAAS-Key-Fingerprint': 'your-fingerprint-here',
    placement:     'bottom-right',
    autoReady:     true,
    showAuxButton: true,
    auxOptions: [
      { code: 'BRK', label: 'Break' },
      { code: 'LCH', label: 'Lunch' },
    ],
    onRegisterStatus: (s) => console.log('SIP:', s),
    onIncomingCall:   (d) => console.log('Incoming:', d),
    onAgentStatus:    (s) => console.log('Agent:', s),
  });
</script>

If you need to use your own React instance, include react@18 and react-dom@18 UMD builds before the script tag and use dist/voxnix.js (ESM) or dist/voxnix.umd.cjs (CJS) instead.


Keyboard shortcuts

These shortcuts are active whenever the dialer widget is open:

| Key | State | Action | |------------------|---------|-------------------------------| | 0–9, *, # | Idle | Append digit to dial input | | Backspace | Idle | Delete last digit | | Enter | Idle | Dial the current number | | 0–9, *, # | In-call | Send DTMF tone |


Build

# ESM + UMD (peer React — for npm consumers)
yarn build:lib

# Self-contained IIFE (bundles React — for CDN / script tag)
yarn build:iife

# Both outputs
yarn build

Output files in dist/:

| File | Format | React | Use case | |--------------------|--------|----------|-----------------------| | voxnix.js | ESM | peer dep | import / bundlers | | voxnix.umd.cjs | UMD | peer dep | CommonJS / require | | voxnix.iife.js | IIFE | bundled | <script> / CDN |


Development

yarn install
yarn dev       # Vite dev server with hot reload
yarn watch     # Vite library watch mode

Changelog

v1.0.12

  • Rollback DevToast / console interceptor feature

v1.0.11 and earlier

  • Agent status bar (Ready / Not Ready / AUX) with configurable auxOptions
  • onAgentStatus callback
  • autoReady and showAuxButton config options
  • Keyboard shortcut support for dialer and DTMF
  • React 17 / 18 compatibility layer
  • Dual-SIP auth shape support (auth and pabxConfig.auth)