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 🙏

© 2025 – Pkg Stats / Ryan Hefner

vcon-js

v0.2.0

Published

JavaScript library for creating and managing vCons (Virtual Conversations)

Readme

vcon-js

A JavaScript/TypeScript library for creating and managing vCons (Virtual Conversations), compliant with IETF draft-ietf-vcon-vcon-core-01.

Installation

npm install vcon-js

Usage

Creating a new vCon

import { Vcon, Party, Dialog } from 'vcon-js';

// Create a new vCon
const vcon = Vcon.buildNew();

// Add parties
const party1 = new Party({
  tel: '+1234567890',
  name: 'John Doe',
  role: 'agent'
});
const party2 = new Party({
  tel: '+0987654321',
  name: 'Jane Smith',
  role: 'customer'
});

vcon.addParty(party1);
vcon.addParty(party2);

// Add a text dialog
const dialog = new Dialog({
  type: 'text',
  start: new Date(),
  parties: [0, 1],
  body: 'Hello, this is a conversation!',
  mediatype: 'text/plain'
});

vcon.addDialog(dialog);

// Convert to JSON
const json = vcon.toJson();

Loading from JSON

import { Vcon } from 'vcon-js';

const jsonString = '...'; // Your vCon JSON string
const vcon = Vcon.buildFromJson(jsonString);

Working with Attachments

import { Vcon, Attachment } from 'vcon-js';

const vcon = Vcon.buildNew();

// Add an inline attachment
const attachment = vcon.addAttachment({
  type: 'application/pdf',
  body: 'base64EncodedContent',
  encoding: 'base64url',
  filename: 'document.pdf'
});

// Add an external attachment
vcon.addAttachment({
  purpose: 'transcript',
  url: 'https://example.com/transcript.txt',
  content_hash: 'sha512-abc123...',
  mediatype: 'text/plain'
});

// Find an attachment by type
const pdfAttachment = vcon.findAttachmentByType('application/pdf');

// Find an attachment by purpose
const transcript = vcon.findAttachmentByPurpose('transcript');

Working with Analysis

import { Vcon } from 'vcon-js';

const vcon = Vcon.buildNew();

// Add inline analysis
vcon.addAnalysis({
  type: 'sentiment',
  dialog: 0,
  vendor: 'sentiment-analyzer',
  product: 'analyzer-v2',
  body: {
    score: 0.8,
    label: 'positive'
  },
  encoding: 'json'
});

// Add analysis with external reference
vcon.addAnalysis({
  type: 'transcription',
  dialog: [0, 1],
  vendor: 'whisper',
  url: 'https://example.com/transcription.json',
  content_hash: 'sha512-xyz789...',
  mediatype: 'application/json'
});

// Find analysis by type
const sentimentAnalysis = vcon.findAnalysisByType('sentiment');

Working with Dialog Types

vcon-core-01 defines four dialog types: recording, text, transfer, and incomplete.

import { Dialog } from 'vcon-js';

// Text dialog
const textDialog = new Dialog({
  type: 'text',
  start: new Date(),
  parties: [0, 1],
  body: 'Hello!',
  mediatype: 'text/plain'
});

// Recording dialog with external audio
const recordingDialog = new Dialog({
  type: 'recording',
  start: new Date(),
  parties: [0, 1],
  duration: 300
});
recordingDialog.addExternalData(
  'https://example.com/audio.wav',
  'audio/wav',
  { filename: 'call.wav', content_hash: 'sha512-abc...' }
);

// Incomplete dialog (e.g., no answer)
const incompleteDialog = new Dialog({
  type: 'incomplete',
  start: new Date(),
  parties: [0],
  disposition: 'no-answer'
});

// Check dialog types
console.log(textDialog.isText()); // true
console.log(recordingDialog.isRecording()); // true
console.log(incompleteDialog.isIncomplete()); // true

Working with Extensions (vcon-core-01)

import { Vcon } from 'vcon-js';

const vcon = Vcon.buildNew();

// Add a non-critical extension
vcon.addExtension('contact_center');

// Add a critical extension (must be understood by processors)
vcon.addCriticalExtension('encrypted');

// Check extensions
console.log(vcon.hasExtension('contact_center')); // true
console.log(vcon.isCriticalExtension('encrypted')); // true

Working with Groups

import { Vcon } from 'vcon-js';

const vcon = Vcon.buildNew();

// Add a group reference (for linking related vCons)
vcon.addGroup({ uuid: 'conversation-thread-uuid', type: 'thread' });

Working with Tags

import { Vcon } from 'vcon-js';

const vcon = Vcon.buildNew();

// Add a tag
vcon.addTag('category', 'support');

// Get a tag
const category = vcon.getTag('category');

Working with Party History

Track party events within a dialog (join, leave, hold, etc.):

import { Dialog, PartyHistory } from 'vcon-js';

const dialog = new Dialog({
  type: 'recording',
  start: new Date(),
  parties: [0, 1]
});

// Add party history events
dialog.party_history = [
  new PartyHistory(0, 'joined', new Date()).toDict(),
  new PartyHistory(1, 'joined', new Date(Date.now() + 5000)).toDict(),
  new PartyHistory(1, 'hold', new Date(Date.now() + 60000)).toDict(),
  new PartyHistory(1, 'resume', new Date(Date.now() + 120000)).toDict(),
  new PartyHistory(0, 'left', new Date(Date.now() + 300000)).toDict(),
  new PartyHistory(1, 'left', new Date(Date.now() + 300000)).toDict()
];

Transfer Dialogs

Represent call transfers between parties:

import { Dialog } from 'vcon-js';

const transferDialog = new Dialog({
  type: 'transfer',
  start: new Date(),
  parties: [0, 1, 2],  // Original caller, original agent, new agent
  transferor: 1,       // Agent initiating transfer
  transferee: 0,       // Caller being transferred
  transfer_target: 2   // New agent receiving transfer
});

Party Identifiers

vcon-core-01 supports multiple party identifier types:

import { Party } from 'vcon-js';

const party = new Party({
  tel: '+1234567890',           // Telephone URL
  sip: 'sip:[email protected]', // SIP address
  mailto: '[email protected]',   // Email address
  stir: 'eyJhbGci...',         // STIR PASSporT
  did: 'did:example:123',       // Decentralized Identifier
  name: 'John Doe',
  timezone: 'America/New_York',
  role: 'agent'
});

// Check if party has an identifier
console.log(party.hasIdentifier()); // true

// Get primary identifier
console.log(party.getPrimaryIdentifier()); // '+1234567890'

API Reference

Vcon

The main class for working with vCons.

Static Methods

  • buildNew(): Creates a new vCon with UUID and timestamp
  • buildFromJson(jsonString: string): Creates a vCon from JSON string

Instance Methods

  • addParty(party: Party): Adds a party to the vCon
  • addDialog(dialog: Dialog): Adds a dialog to the vCon
  • addAttachment(params): Adds an attachment (inline or external)
  • addAnalysis(params): Adds analysis data
  • addTag(tagName, tagValue): Adds a tag
  • addExtension(name): Adds a non-critical extension
  • addCriticalExtension(name): Adds a critical extension
  • addGroup(group): Adds a group reference
  • findPartyIndex(by, val): Finds a party index by property
  • findDialog(by, val): Finds a dialog by property
  • findAttachmentByType(type): Finds an attachment by type
  • findAttachmentByPurpose(purpose): Finds an attachment by purpose
  • findAnalysisByType(type): Finds analysis by type
  • hasExtension(name): Checks if extension is used
  • isCriticalExtension(name): Checks if extension is critical
  • getTag(tagName): Gets a tag value
  • toJson(): Converts the vCon to JSON string
  • toDict(): Converts the vCon to a plain object

Properties

  • uuid: Unique identifier
  • vcon: Version string
  • created_at: Creation timestamp (RFC3339)
  • updated_at: Last modification timestamp
  • subject: Conversation subject
  • parties: Array of parties
  • dialog: Array of dialogs
  • attachments: Array of attachments
  • analysis: Array of analysis results
  • tags: Tag dictionary
  • extensions: Non-critical extensions array
  • critical: Critical extensions array
  • group: Group references
  • redacted: Redaction reference
  • amended: Amendment reference
  • meta: Additional metadata

Party

Class for representing parties in a vCon.

Properties

  • tel?: string: Telephone URL (TEL format)
  • sip?: string: SIP address
  • mailto?: string: Email address
  • stir?: string: STIR PASSporT
  • did?: string: Decentralized Identifier
  • name?: string: Display name
  • uuid?: string: Participant identifier
  • validation?: string: Identity validation method
  • gmlpos?: string: GML position
  • civicaddress?: CivicAddress: Civic address
  • timezone?: string: Location timezone
  • role?: string: Role in conversation
  • meta?: Record<string, any>: Additional metadata

Methods

  • toDict(): Converts to plain object
  • hasIdentifier(): Checks if party has any identifier
  • getPrimaryIdentifier(): Gets the primary identifier
  • validate(): Validates against vcon-core-01 recommendations

Dialog

Class for representing dialogs in a vCon.

Static Constants

Dialog.DIALOG_TYPES     // ['recording', 'text', 'transfer', 'incomplete']
Dialog.DISPOSITIONS     // ['no-answer', 'congestion', 'failed', 'busy', 'hung-up', 'voicemail-no-message']
Dialog.VALID_ENCODINGS  // ['base64url', 'json', 'none']

Properties

  • type: string: Dialog type (recording, text, transfer, incomplete)
  • start: Date | string: Start time (RFC3339)
  • parties?: number | number[]: Party indices
  • originator?: number: Originator party index
  • mediatype?: string: MIME type
  • filename?: string: Original filename
  • body?: string: Inline content
  • encoding?: string: Content encoding (base64url, json, none)
  • url?: string: External URL reference
  • content_hash?: string: Content hash for external files
  • duration?: number: Duration in seconds
  • disposition?: string: Disposition for incomplete dialogs
  • session_id?: SessionId: Session identifier
  • party_history?: PartyHistory[]: Party event history
  • application?: string: Application that created the dialog (e.g., 'zoom', 'teams')

Methods

  • toDict(): Converts to plain object
  • addExternalData(url, mediatype, options?): Adds external data reference
  • addInlineData(body, mediatype, options?): Adds inline data
  • isExternalData(): Checks if has external data
  • isInlineData(): Checks if has inline data
  • isText(): Checks if text type
  • isRecording(): Checks if recording type
  • isTransfer(): Checks if transfer type
  • isIncomplete(): Checks if incomplete type
  • isAudio(): Checks if audio content
  • isVideo(): Checks if video content
  • isEmail(): Checks if email content
  • validate(): Validates against vcon-core-01

Attachment

Class for representing attachments in a vCon.

Static Constants

Attachment.VALID_ENCODINGS  // ['base64url', 'json', 'none']

Properties

  • type?: string: Attachment type (MIME type)
  • purpose?: string: Purpose/category
  • start?: Date | string: Reference time
  • party?: number: Related party index
  • dialog?: number | number[]: Related dialog indices
  • mediatype?: string: Media type
  • filename?: string: Original filename
  • body?: any: Inline content
  • encoding?: string: Content encoding
  • url?: string: External URL
  • content_hash?: string: Content hash

Methods

  • toDict(): Converts to plain object
  • addExternalData(url, mediatype, options?): Adds external reference
  • addInlineData(body, mediatype, options?): Adds inline content
  • isExternalData(): Checks if has external data
  • isInlineData(): Checks if has inline data
  • validate(): Validates against vcon-core-01

PartyHistory

Class for tracking party events within a dialog.

Constructor

new PartyHistory(party: number, event: string, time: Date | string)

Properties

  • party: number: Party index
  • event: string: Event type (e.g., 'joined', 'left', 'hold', 'resume', 'mute', 'unmute')
  • time: Date | string: Event timestamp

Methods

  • toDict(): Converts to plain object with ISO timestamp
  • static fromDict(data): Creates PartyHistory from plain object

Constants

import { VCON_VERSION } from 'vcon-js';

console.log(VCON_VERSION); // '0.0.1'

Tutorial Examples

The examples/ directory contains three comprehensive tutorials demonstrating real-world usage:

Example 1: Text Chat Conversation

File: examples/01-text-chat.ts Run: npm run example:chat

A customer support chat conversation demonstrating:

  • Creating parties with different identifiers (tel, mailto)
  • Building a multi-turn text conversation
  • Setting conversation subject and tags
  • Serializing and deserializing vCons
// Quick start - text chat
const vcon = Vcon.buildNew();
vcon.addParty(new Party({ tel: '+1-555-123-4567', name: 'Customer', role: 'customer' }));
vcon.addParty(new Party({ mailto: '[email protected]', name: 'Agent', role: 'agent' }));

vcon.addDialog(new Dialog({
  type: 'text',
  start: new Date().toISOString(),
  parties: [0, 1],
  originator: 0,
  body: 'Hi, I need help with my account.',
  mediatype: 'text/plain'
}));

Example 2: Phone Call Recording with Analysis

File: examples/02-call-recording.ts Run: npm run example:call

An insurance claim phone call demonstrating:

  • Recording type dialogs with duration
  • External media references with content_hash
  • Party validation (STIR/SHAKEN)
  • Multiple analysis types (transcription, sentiment, topic classification)
  • Contact center extensions
  • Party history tracking (join, hold, resume, leave events)
// Quick start - call recording
const vcon = Vcon.buildNew();
vcon.addExtension('contact_center');

const recordingDialog = new Dialog({
  type: 'recording',
  start: new Date().toISOString(),
  parties: [0, 1],
  duration: 847,
  campaign: 'claims-inbound'
});

recordingDialog.addExternalData(
  'https://storage.example.com/call.wav',
  'audio/wav',
  { content_hash: 'sha512-abc123...' }
);

vcon.addAnalysis({
  type: 'transcription',
  dialog: 0,
  vendor: 'whisper',
  product: 'large-v3',
  body: { segments: [...] }
});

Example 3: Video Conference with Attachments

File: examples/03-video-conference.ts Run: npm run example:conference

A multi-party product roadmap meeting demonstrating:

  • 5+ party conferences
  • Video recording dialogs
  • Incomplete dialogs (failed join attempts)
  • Multiple attachments (presentations, notes, chat transcripts)
  • Inline and external content storage
  • Group references for meeting series
  • Meeting-specific analysis (action items, summaries)
  • Validation of dialog objects
// Quick start - video conference
const vcon = Vcon.buildNew();
vcon.subject = 'Q1 Product Roadmap Review';
vcon.addExtension('meeting');

// Add multiple participants
['Host', 'Engineer', 'Designer', 'QA', 'Marketing'].forEach((role, i) => {
  vcon.addParty(new Party({ mailto: `${role.toLowerCase()}@company.com`, role: i === 0 ? 'host' : 'participant' }));
});

// Add recording with party history
const videoDialog = new Dialog({
  type: 'recording',
  start: new Date().toISOString(),
  parties: [0, 1, 2, 3, 4],
  duration: 3720,
  application: 'zoom'
});

// Add attachments
vcon.addAttachment({
  purpose: 'presentation',
  filename: 'roadmap.pptx',
  body: '...',
  encoding: 'base64url'
});

// Link to meeting series
vcon.addGroup({ uuid: 'roadmap-series-2025', type: 'meeting-series' });

Running All Examples

# Run individual examples
npm run example:chat        # Text chat conversation
npm run example:call        # Phone call with analysis
npm run example:conference  # Video conference

# Run all examples
npm run examples

vcon-core-01 Compliance

This library implements the IETF draft-ietf-vcon-vcon-core-01 specification, including:

  • Dialog Types: recording, text, transfer, incomplete
  • Dispositions: no-answer, congestion, failed, busy, hung-up, voicemail-no-message
  • Encodings: base64url, json, none
  • Content Hash: SHA-512 hash format for external references
  • Extensions: Support for extensions and critical arrays
  • Party Identifiers: tel, sip, mailto, stir, did, uuid
  • Date Format: RFC3339 timestamps

Development

npm install          # Install dependencies
npm run build        # Compile TypeScript
npm test             # Run tests (61 tests)
npm run lint         # Run ESLint
npm run format       # Format with Prettier

License

MIT