@cognigy/click-to-call-sdk 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # Click To Call SDK
2
+
3
+ A standalone, framework-agnostic SDK for SIP-based voice calling with WebRTC. Built on JsSIP.
4
+
5
+ ## Features
6
+
7
+ - ๐Ÿš€ **Framework Agnostic** โ€” works with React, Angular, Vue, or vanilla JS.
8
+ - ๐Ÿ”’ **Type Safe** โ€” full TypeScript support.
9
+ - ๐Ÿ“ž **SIP/WebRTC** โ€” built on JsSIP for reliable communication.
10
+ - ๐ŸŽ›๏ธ **Full Control** โ€” start, end, mute, unmute, send info messages.
11
+ - ๐Ÿ”„ **Event Driven** โ€” 17 events for real-time state updates.
12
+ - ๐ŸŽต **Auto Audio** โ€” remote audio plays automatically; raw stream available via `captureAudio` event.
13
+ - ๐Ÿ’ฌ **Transcription** โ€” real-time transcription events, auto-separated from info messages.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @cognigy/click-to-call-sdk
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import { createWebRTCClient, checkWebRTCSupport } from '@cognigy/click-to-call-sdk';
25
+
26
+ // 1. Check browser support
27
+ const support = checkWebRTCSupport();
28
+ if (!support.supported) throw new Error('Missing: ' + support.missing);
29
+
30
+ // 2. Create client
31
+ const client = await createWebRTCClient({
32
+ endpointUrl: 'https://your-cognigy-environment.com/token',
33
+ userId: 'user-123',
34
+ });
35
+
36
+ // 3. Listen to events
37
+ client.on('answered', (session) => console.log('Call answered:', session.id));
38
+ client.on('ended', (session, endInfo) => console.log('Call ended:', endInfo.cause));
39
+ client.on('error', (error) => console.error('Error:', error.message));
40
+
41
+ // 4. Connect and call
42
+ await client.connectAndCall();
43
+
44
+ // 5. Cleanup on page unload
45
+ window.addEventListener('beforeunload', () => {
46
+ void client.destroy().catch(() => {
47
+ // Ignore errors during page unload
48
+ });
49
+ });
50
+ ```
51
+
52
+ > **Note:** The call must be initiated from a user gesture (e.g. button click) for browser autoplay policies to allow audio.
53
+
54
+ ## Configuration
55
+
56
+ ```typescript
57
+ interface WebRTCClientConfig {
58
+ endpointUrl: string; // URL to fetch SIP configuration
59
+ userId?: string; // Optional user identifier
60
+ pcConfig?: RTCConfiguration; // WebRTC peer connection config
61
+ captureAudio?: boolean; // Enable captureAudio event to receive raw MediaStream
62
+ }
63
+ ```
64
+
65
+ ## API
66
+
67
+ | Method | Description |
68
+ |-------------------------|----------------------------------------------|
69
+ | `connect()` | Connect to SIP server and register |
70
+ | `disconnect()` | Disconnect from SIP server |
71
+ | `connectAndCall()` | Connect + start call in one step |
72
+ | `startCall()` | Start a call (must be connected first) |
73
+ | `endCall()` | End the current call |
74
+ | `mute()` / `unmute()` | Toggle microphone |
75
+ | `sendInfo(text, data?)` | Send info message during a call |
76
+ | `isConnected()` | Check connection state |
77
+ | `getCurrentSession()` | Get active `CallSession` or `null` |
78
+ | `on(event, callback)` | Add event listener (returns `this`) |
79
+ | `off(event, callback)` | Remove event listener (returns `this`) |
80
+ | `destroy()` | Disconnect, end calls, release all resources |
81
+
82
+ ## Events
83
+
84
+ | Event | Callback |
85
+ |-----------------|-------------------------------------------------------------------------|
86
+ | `connecting` | `()` |
87
+ | `connected` | `()` |
88
+ | `disconnected` | `()` |
89
+ | `registered` | `()` |
90
+ | `unregistered` | `()` |
91
+ | `ringing` | `(session: CallSession)` |
92
+ | `answered` | `(session: CallSession)` |
93
+ | `ended` | `(session: CallSession, endInfo: CallEndInfo)` |
94
+ | `failed` | `(session: CallSession, endInfo: CallEndInfo)` |
95
+ | `muted` | `(session: CallSession)` |
96
+ | `unmuted` | `(session: CallSession)` |
97
+ | `captureAudio` | Remote audio stream available (requires opt-in) `(stream: MediaStream)` |
98
+ | `audioEnded` | `()` |
99
+ | `infoSent` | `(text: string, data: Record<string, any>)` |
100
+ | `infoReceived` | `(data: { originator: string; info: { body: string } })` |
101
+ | `transcription` | `(transcription: { originator: string; messages: { text: string }[] })` |
102
+ | `error` | `(error: Error)` |
103
+
104
+ ## Browser Compatibility
105
+
106
+ Chrome 93+ ยท Firefox 92+ ยท Safari 15.4+ ยท Edge 93+
107
+
108
+ ## Documentation
109
+
110
+ For the full guide, API reference, event reference, and troubleshooting:
111
+
112
+ - [Getting Started](https://docs.cognigy.com/click-to-call/sdkgetting-started.mdx)
113
+ - [API Reference](https://docs.cognigy.com/click-to-call/sdkapi-reference/overview.mdx)
114
+ - [Event Reference](https://docs.cognigy.com/click-to-call/sdkevent-reference/overview.mdx)
115
+ - [Custom Audio](https://docs.cognigy.com/click-to-call/sdkcustom-audio.mdx)
116
+ - [Security](https://docs.cognigy.com/click-to-call/sdksecurity.mdx)
117
+ - [Troubleshooting](https://docs.cognigy.com/click-to-call/sdktroubleshooting.mdx)
118
+
119
+ ## License
120
+
121
+ MIT
@@ -0,0 +1,22 @@
1
+ import { SDKEventEmitter } from './utils/events.js';
2
+ export declare class AudioManager extends SDKEventEmitter {
3
+ private state;
4
+ constructor();
5
+ private initializeDefaultAudio;
6
+ handleRemoteStream(stream: MediaStream): void;
7
+ private playDefaultAudio;
8
+ stopAudio(): void;
9
+ setVolume(volume: number): void;
10
+ getVolume(): number;
11
+ setMuted(muted: boolean): void;
12
+ isMuted(): boolean;
13
+ getCurrentStream(): MediaStream | null;
14
+ setCaptureAudio(enabled: boolean): void;
15
+ getState(): {
16
+ hasRemoteAudio: boolean;
17
+ hasCurrentStream: boolean;
18
+ volume: number;
19
+ muted: boolean;
20
+ };
21
+ destroy(): void;
22
+ }
@@ -0,0 +1,32 @@
1
+ import { EndpointConfig } from './types/index.js';
2
+ export declare class ConfigManager {
3
+ private config;
4
+ private readonly endpointUrl;
5
+ private userId;
6
+ private readonly userProvidedId;
7
+ constructor(endpointUrl: string, userId?: string);
8
+ fetchConfig(): Promise<EndpointConfig>;
9
+ getConfig(): EndpointConfig | null;
10
+ getSipCredentials(): {
11
+ fullUsername: string;
12
+ password: string;
13
+ username: string;
14
+ wsUri: string;
15
+ applicationSid: string;
16
+ realm: string;
17
+ };
18
+ getApplicationSid(): string;
19
+ isActive(): boolean;
20
+ getPrivacySettings(): {
21
+ enabled: boolean;
22
+ text: string;
23
+ cancelButtonText: string;
24
+ submitButtonText: string;
25
+ urlText: string;
26
+ url: string;
27
+ };
28
+ clearConfig(): void;
29
+ isConfigValid(): boolean;
30
+ getPeerConnectionConfig(): RTCConfiguration | undefined;
31
+ }
32
+ export declare function createConfigManager(endpointUrl: string): ConfigManager;
@@ -0,0 +1,29 @@
1
+ import { SDKEventEmitter } from './utils/events.js';
2
+ import { ExtendedRTCSession } from './types/internal.js';
3
+ import { CallSession } from './types/index.js';
4
+ export declare class SessionManager extends SDKEventEmitter {
5
+ private sessions;
6
+ private activeSessionId;
7
+ private audioManager?;
8
+ constructor(_pcConfig?: RTCConfiguration);
9
+ setAudioManager(audioManager: any): void;
10
+ createSession(rtcSession: ExtendedRTCSession): string;
11
+ private setupSessionEventHandlers;
12
+ private handleNewInfo;
13
+ private setupPeerConnectionHandlers;
14
+ private handleSessionEnd;
15
+ private updateSession;
16
+ private getPublicSession;
17
+ private calculateDuration;
18
+ setActiveSession(sessionId: string): void;
19
+ getActiveSession(): CallSession | null;
20
+ getSession(sessionId: string): CallSession | null;
21
+ getAllSessions(): CallSession[];
22
+ mute(): void;
23
+ unmute(): void;
24
+ sendInfo(text: string, data?: Record<string, any>): void;
25
+ terminate(sipCode?: number, sipReason?: string): void;
26
+ private getActiveSessionState;
27
+ private removeSession;
28
+ destroy(): void;
29
+ }
@@ -0,0 +1,20 @@
1
+ import { UA as IUA } from 'jssip';
2
+ import { SDKEventEmitter } from './utils/events.js';
3
+ import { InternalClientConfig, InternalClientSettings, SipManagerState } from './types/internal.js';
4
+ export declare class SipManager extends SDKEventEmitter {
5
+ private ua;
6
+ private pcConfig?;
7
+ private state;
8
+ initialize(client: InternalClientConfig, settings: InternalClientSettings): void;
9
+ private setupEventHandlers;
10
+ private handleNewSession;
11
+ start(): void;
12
+ stop(): void;
13
+ call(number: string, originalNumber?: string): void;
14
+ getState(): SipManagerState;
15
+ isConnected(): boolean;
16
+ isRegistered(): boolean;
17
+ isConnecting(): boolean;
18
+ getUserAgent(): IUA | null;
19
+ destroy(): void;
20
+ }
@@ -0,0 +1,31 @@
1
+ import { SDKEventEmitter } from './utils/events.js';
2
+ import { WebRTCClient as IWebRTCClient, WebRTCClientConfig, CallSession, EventName, EventCallback } from './types/index.js';
3
+ export declare class WebRTCClient extends SDKEventEmitter implements IWebRTCClient {
4
+ private configManager;
5
+ private sipManager;
6
+ private sessionManager;
7
+ private audioManager;
8
+ private isInitialized;
9
+ private isDestroyed;
10
+ constructor(config: WebRTCClientConfig);
11
+ private setupEventHandlers;
12
+ connect(): Promise<void>;
13
+ disconnect(): Promise<void>;
14
+ startCall(): Promise<void>;
15
+ endCall(): Promise<void>;
16
+ mute(): Promise<void>;
17
+ unmute(): Promise<void>;
18
+ connectAndCall(): Promise<void>;
19
+ sendInfo(text: string, data?: Record<string, any>): Promise<void>;
20
+ on<T extends EventName>(event: T, callback: EventCallback<T>): this;
21
+ off<T extends EventName>(event: T, callback: EventCallback<T>): this;
22
+ isConnected(): boolean;
23
+ getCurrentSession(): CallSession | null;
24
+ destroy(): Promise<void>;
25
+ getStatus(): {
26
+ connected: boolean;
27
+ registered: boolean;
28
+ activeSession: CallSession | null;
29
+ audioState: any;
30
+ };
31
+ }
@@ -0,0 +1,13 @@
1
+ import { WebRTCClient } from './WebRTCClient.js';
2
+ import { isWebRTCSupported } from './utils/helpers.js';
3
+ import { WebRTCClientConfig } from './types/index.js';
4
+ export type { WebRTCClient as IWebRTCClient, WebRTCClientConfig, CreateWebRTCClientOptions, CreateWebRTCClient, EndpointConfig, SipConnectivityInfo, CallSession, CallEndInfo, SessionStatus, EventName, EventCallback, WebRTCClientEvents, } from './types/index.js';
5
+ export { WebRTCClient };
6
+ export { isWebRTCSupported };
7
+ export declare function createWebRTCClient(config: WebRTCClientConfig): Promise<WebRTCClient>;
8
+ export declare const VERSION = "1.0.0";
9
+ export declare const SDK_NAME = "@cognigy/webrtc-sdk";
10
+ export declare function checkWebRTCSupport(): {
11
+ supported: boolean;
12
+ missing: string[];
13
+ };
@@ -0,0 +1,102 @@
1
+ export interface EndpointConfig {
2
+ organisationId: string;
3
+ projectId: string;
4
+ endpointSettings: {
5
+ snapshotId: string | null;
6
+ endpointUrlToken: string;
7
+ endpointName: string;
8
+ channel: string;
9
+ localeReferenceId: string;
10
+ collectAnalytics: boolean;
11
+ active: boolean;
12
+ version?: string;
13
+ sipConnectivityInfo: SipConnectivityInfo;
14
+ webrtcWidgetConfig: {
15
+ active: boolean;
16
+ label?: string;
17
+ };
18
+ };
19
+ settings?: {
20
+ privacyNotice?: {
21
+ enabled: boolean;
22
+ text: string;
23
+ cancelButtonText: string;
24
+ submitButtonText: string;
25
+ urlText: string;
26
+ url: string;
27
+ };
28
+ };
29
+ }
30
+ export interface SipConnectivityInfo {
31
+ userId?: string;
32
+ username: string;
33
+ applicationSid: string;
34
+ password: string;
35
+ wsUri: string;
36
+ realm: string;
37
+ clientSid?: string;
38
+ }
39
+ export interface WebRTCClientConfig {
40
+ endpointUrl: string;
41
+ userId?: string;
42
+ pcConfig?: RTCConfiguration;
43
+ captureAudio?: boolean;
44
+ }
45
+ export interface CallSession {
46
+ id: string;
47
+ status: SessionStatus;
48
+ direction: 'incoming' | 'outgoing';
49
+ startTime: Date;
50
+ answerTime?: Date;
51
+ duration: number;
52
+ muted: boolean;
53
+ localHold: boolean;
54
+ remoteHold: boolean;
55
+ }
56
+ export type SessionStatus = 'init' | 'ringing' | 'answered' | 'failed' | 'ended';
57
+ export interface CallEndInfo {
58
+ originator: 'local' | 'remote' | null;
59
+ cause: string | null;
60
+ description?: string | null;
61
+ }
62
+ export interface WebRTCClientEvents {
63
+ 'connecting': () => void;
64
+ 'connected': () => void;
65
+ 'disconnected': () => void;
66
+ 'registered': () => void;
67
+ 'unregistered': () => void;
68
+ 'ringing': (session: CallSession) => void;
69
+ 'answered': (session: CallSession) => void;
70
+ 'ended': (session: CallSession, endInfo: CallEndInfo) => void;
71
+ 'failed': (session: CallSession, endInfo: CallEndInfo) => void;
72
+ 'muted': (session: CallSession) => void;
73
+ 'unmuted': (session: CallSession) => void;
74
+ 'audioEnded': () => void;
75
+ 'infoSent': (text: string, data: Record<string, any>) => void;
76
+ 'infoReceived': (data: {
77
+ originator: string;
78
+ info: any;
79
+ }) => void;
80
+ 'error': (error: Error) => void;
81
+ 'captureAudio': (stream: MediaStream) => void;
82
+ }
83
+ export type EventName = keyof WebRTCClientEvents;
84
+ export type EventCallback<T extends EventName> = WebRTCClientEvents[T];
85
+ export interface WebRTCClient {
86
+ startCall(): Promise<void>;
87
+ endCall(): Promise<void>;
88
+ mute(): Promise<void>;
89
+ unmute(): Promise<void>;
90
+ sendInfo(text: string, data?: Record<string, any>): Promise<void>;
91
+ on<T extends EventName>(event: T, callback: EventCallback<T>): this;
92
+ off<T extends EventName>(event: T, callback: EventCallback<T>): this;
93
+ isConnected(): boolean;
94
+ getCurrentSession(): CallSession | null;
95
+ connect(): Promise<void>;
96
+ disconnect(): Promise<void>;
97
+ destroy(): Promise<void>;
98
+ connectAndCall(): Promise<void>;
99
+ }
100
+ export interface CreateWebRTCClientOptions extends WebRTCClientConfig {
101
+ }
102
+ export type CreateWebRTCClient = (config: CreateWebRTCClientOptions) => Promise<WebRTCClient>;
@@ -0,0 +1,55 @@
1
+ import { RTCSession } from 'jssip/lib/RTCSession';
2
+ import { UA } from 'jssip';
3
+ import { CallEndInfo, SessionStatus } from './index.js';
4
+ export type ExtendedRTCSession = Omit<RTCSession, 'sendInfo'> & {
5
+ _connection: RTCSession['connection'];
6
+ sendInfo: (text: string, data: Record<string, any>) => void;
7
+ data: {
8
+ originalNumber?: string;
9
+ replaces?: boolean;
10
+ [key: string]: any;
11
+ };
12
+ };
13
+ export interface SessionOptions {
14
+ pcConfig?: RTCConfiguration;
15
+ onSession: (rtcSession: ExtendedRTCSession) => void;
16
+ }
17
+ export interface InternalClientConfig {
18
+ fullUsername: string;
19
+ password: string;
20
+ username: string;
21
+ }
22
+ export interface InternalClientSettings {
23
+ wsUri: string;
24
+ pcConfig?: RTCConfiguration;
25
+ }
26
+ export interface SessionState {
27
+ id: string;
28
+ startTime: Date;
29
+ status: SessionStatus;
30
+ active: boolean;
31
+ endInfo: CallEndInfo;
32
+ muted: boolean;
33
+ localHold: boolean;
34
+ remoteHold: boolean;
35
+ doingAttendedTransfer: boolean;
36
+ autoMerge: boolean;
37
+ rtcSession: ExtendedRTCSession;
38
+ }
39
+ export interface AudioState {
40
+ remoteAudio: HTMLAudioElement | null;
41
+ currentStream: MediaStream | null;
42
+ captureAudio: boolean;
43
+ }
44
+ export interface SipManagerState {
45
+ ua: UA | null;
46
+ connected: boolean;
47
+ registered: boolean;
48
+ connecting: boolean;
49
+ }
50
+ export interface EventEmitter {
51
+ on(event: string, listener: (...args: any[]) => void): this;
52
+ off(event: string, listener: (...args: any[]) => void): this;
53
+ emit(event: string, ...args: any[]): void;
54
+ removeAllListeners(event?: string): void;
55
+ }
@@ -0,0 +1,35 @@
1
+ import { EventEmitter as NodeEventEmitter } from 'events';
2
+ import { EventEmitter } from '../types/internal.js';
3
+ export declare class SDKEventEmitter extends NodeEventEmitter implements EventEmitter {
4
+ constructor();
5
+ on(event: string, listener: (...args: any[]) => void): this;
6
+ off(event: string, listener: (...args: any[]) => void): this;
7
+ emit(event: string, ...args: any[]): boolean;
8
+ removeAllListeners(event?: string): this;
9
+ once(event: string, listener: (...args: any[]) => void): this;
10
+ listenerCount(event: string): number;
11
+ listeners(event: string): ((...args: any[]) => void)[];
12
+ }
13
+ export declare const COGNIGY_WEBRTC_EVENTS: {
14
+ readonly CONNECTING: "connecting";
15
+ readonly CONNECTED: "connected";
16
+ readonly DISCONNECTED: "disconnected";
17
+ readonly REGISTERED: "registered";
18
+ readonly UNREGISTERED: "unregistered";
19
+ readonly RINGING: "ringing";
20
+ readonly ANSWERED: "answered";
21
+ readonly ENDED: "ended";
22
+ readonly FAILED: "failed";
23
+ readonly MUTED: "muted";
24
+ readonly UNMUTED: "unmuted";
25
+ readonly AUDIO_ENDED: "audioEnded";
26
+ readonly INFO_SENT: "infoSent";
27
+ readonly ERROR: "error";
28
+ readonly SESSION_CREATED: "sessionCreated";
29
+ readonly SESSION_UPDATED: "sessionUpdated";
30
+ readonly SESSION_DESTROYED: "sessionDestroyed";
31
+ readonly INFO_RECEIVED: "infoReceived";
32
+ readonly TRANSCRIPTION: "transcription";
33
+ readonly CAPTURE_AUDIO: "captureAudio";
34
+ };
35
+ export type SDKEventName = typeof COGNIGY_WEBRTC_EVENTS[keyof typeof COGNIGY_WEBRTC_EVENTS];
@@ -0,0 +1,12 @@
1
+ export declare function randomId(prefix?: string): string;
2
+ export declare function isValidSipUri(uri: string): boolean;
3
+ export declare function isValidWsUri(uri: string): boolean;
4
+ export declare function delay(ms: number): Promise<void>;
5
+ export declare function safeJsonParse<T>(jsonString: string, fallback: T): T;
6
+ export declare function isBrowser(): boolean;
7
+ export declare function isWebRTCSupported(): boolean;
8
+ export declare function validateEndpointConfig(config: any): boolean;
9
+ export declare function getNestedProperty(obj: any, path: string): any;
10
+ export declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
11
+ export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T>;
12
+ export declare function formatDuration(seconds: number): string;