{"_id":"@asitni/sip-simple","name":"@asitni/sip-simple","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@asitni/sip-simple","version":"1.0.0","description":"TypeScript SIP client library with WebRTC support","type":"module","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.esm.js","require":"./dist/index.cjs.js","types":"./dist/index.d.ts"}},"scripts":{"build":"rollup -c","build:watch":"rollup -c -w","dev":"rollup -c -w","clean":"rimraf dist","clean:all":"rimraf dist node_modules package-lock.json","reinstall":"npm run clean:all && npm install","prebuild":"npm run clean","type-check":"tsc --noEmit","lint":"eslint src/**/*.ts","test":"","prepare":"npm run build","prepublishOnly":"npm run test && npm run build"},"keywords":["sip","webrtc","voip","typescript","telephony"],"author":{"name":"Sitnikov Andrei","email":"sitnikov.andrei@mail.ru"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/SitnikovAndrei/sip-simple.git"},"bugs":{"url":"https://github.com/SitnikovAndrei/sip-simple/issues"},"homepage":"https://github.com/SitnikovAndrei/sip-simple#readme","peerDependencies":{"sip.js":"^0.21.0"},"devDependencies":{"@rollup/plugin-commonjs":"^25.0.7","@rollup/plugin-node-resolve":"^15.2.3","@rollup/plugin-terser":"^0.4.4","@rollup/plugin-typescript":"^11.1.5","@types/jest":"^29.5.8","@typescript-eslint/eslint-plugin":"^6.12.0","@typescript-eslint/parser":"^6.12.0","eslint":"^8.54.0","jest":"^29.7.0","jest-environment-jsdom":"^30.0.2","rimraf":"^5.0.5","rollup":"^4.6.1","rollup-plugin-dts":"^6.1.0","sip.js":"^0.21.0","ts-jest":"^29.1.1","tslib":"^2.6.2","typescript":"^5.2.2"},"engines":{"node":">=16.0.0"},"_id":"@asitni/sip-simple@1.0.0","gitHead":"93b585ddd27c68afbcfd5db197a5f16308d975c5","_nodeVersion":"22.16.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-SKQ58xf+9zI9utyn0Mjxc4hyWhtwtwzFggm1F5PFLu86ZMzHbSwTs3IwLPl4bxJxP33IZbQf1FwpF/TP/OP8oA==","shasum":"7c69e51c617ca9b0088ae9e541086d00e9c661c6","tarball":"https://registry.npmjs.org/@asitni/sip-simple/-/sip-simple-1.0.0.tgz","fileCount":10,"unpackedSize":374451,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCB45k359kYUEK/9g6GGwxRV10pDjBV8hbqfZZicP3JCwIhAKp6GiCtaDzlfw6tCAA1FRT9+2OzLUd/FAM+r2l+9T2A"}]},"_npmUser":{"name":"asitni","email":"sitnikov.andrei@mail.ru","actor":{"name":"asitni","email":"sitnikov.andrei@mail.ru","type":"user"}},"directories":{},"maintainers":[{"name":"asitni","email":"sitnikov.andrei@mail.ru"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sip-simple_1.0.0_1750589241283_0.330347486682667"},"_hasShrinkwrap":false}},"time":{"created":"2025-06-22T10:47:21.197Z","1.0.0":"2025-06-22T10:47:21.496Z","modified":"2025-06-22T10:47:21.758Z"},"maintainers":[{"name":"asitni","email":"sitnikov.andrei@mail.ru"}],"description":"TypeScript SIP client library with WebRTC support","homepage":"https://github.com/SitnikovAndrei/sip-simple#readme","keywords":["sip","webrtc","voip","typescript","telephony"],"repository":{"type":"git","url":"git+https://github.com/SitnikovAndrei/sip-simple.git"},"author":{"name":"Sitnikov Andrei","email":"sitnikov.andrei@mail.ru"},"bugs":{"url":"https://github.com/SitnikovAndrei/sip-simple/issues"},"license":"MIT","readme":"# TypeScript SIP Client Library\r\n\r\nA modern, fully-typed SIP client library built with TypeScript for browser-based VoIP applications. Features WebRTC integration, persistent call history, and comprehensive device management.\r\n\r\n## ✨ Features\r\n\r\n- 🎯 **Full TypeScript Support** - Complete type safety with comprehensive type definitions\r\n- 📞 **Complete SIP Functionality** - Make, receive, hold, transfer calls with full SIP protocol support\r\n- 🎵 **Advanced Audio Management** - Device selection, mute/unmute, DTMF, volume control\r\n- 📱 **WebRTC Integration** - High-quality peer-to-peer audio communication\r\n- 💾 **Persistent Storage** - Call history with localStorage and memory fallback\r\n- 🔄 **Auto-Reconnection** - Smart reconnection with exponential backoff\r\n- 🎛️ **Event-Driven Architecture** - Comprehensive event system for real-time updates\r\n- 📊 **Call Statistics** - Detailed audio quality and connection analytics\r\n- 🏗️ **Modern Build System** - Multiple formats (ESM, CJS, UMD) with tree-shaking support\r\n- 🧪 **Testing Ready** - Built-in test utilities and comprehensive coverage\r\n\r\n## 📦 Installation\r\n\r\n```bash\r\nnpm install @your-org/sip-client sip.js\r\n```\r\n\r\n## 🚀 Quick Start\r\n\r\n```typescript\r\nimport { SIPModule, SIPConfig } from '@your-org/sip-client';\r\n\r\n// Create SIP client instance\r\nconst sipClient = new SIPModule();\r\n\r\n// Configure connection\r\nconst config: SIPConfig = {\r\n  sipUri: 'sip:username@your-domain.com',\r\n  wsUri: 'wss://your-sip-server.com:8089/ws',\r\n  password: 'your-password',\r\n  displayName: 'Your Display Name'\r\n};\r\n\r\n// Setup event listeners\r\nsipClient.on('connected', () => {\r\n  console.log('✅ Connected to SIP server');\r\n});\r\n\r\nsipClient.on('registered', () => {\r\n  console.log('📝 Successfully registered');\r\n});\r\n\r\nsipClient.on('incomingCall', (callData) => {\r\n  console.log(`📞 Incoming call from: ${callData.number}`);\r\n  \r\n  // Answer the call\r\n  sipClient.answer();\r\n  \r\n  // Or reject it\r\n  // sipClient.reject();\r\n});\r\n\r\nsipClient.on('callAccepted', () => {\r\n  console.log('🎉 Call established');\r\n});\r\n\r\nsipClient.on('callEnded', (data) => {\r\n  console.log(`📴 Call ended: ${data.reason}`);\r\n});\r\n\r\n// Connect and start calling\r\nasync function start() {\r\n  try {\r\n    const result = await sipClient.connect(config);\r\n    if (result.success) {\r\n      console.log('🔌 Connected successfully');\r\n      \r\n      // Make a call\r\n      await sipClient.makeCall('1234567890');\r\n    }\r\n  } catch (error) {\r\n    console.error('❌ Connection failed:', error);\r\n  }\r\n}\r\n\r\nstart();\r\n```\r\n\r\n## 🔧 Configuration\r\n\r\n### Basic Configuration\r\n\r\n```typescript\r\ninterface SIPConfig {\r\n  sipUri: string;              // SIP URI (sip:user@domain.com)\r\n  wsUri: string;               // WebSocket URI (wss://server:port/path)\r\n  password: string;            // Authentication password\r\n  displayName?: string;        // Display name for calls\r\n  iceServers?: RTCIceServer[]; // STUN/TURN servers\r\n  connection?: ConnectionConfig;\r\n  registrationExpires?: number; // Registration expiration (seconds)\r\n}\r\n```\r\n\r\n### Advanced Connection Settings\r\n\r\n```typescript\r\ninterface ConnectionConfig {\r\n  connectionTimeout?: number;        // Connection timeout (ms) - default: 10000\r\n  maxReconnectionAttempts?: number;  // Max reconnection attempts - default: 5\r\n  reconnectionTimeout?: number;      // Reconnection delay (ms) - default: 4000\r\n  registrationExpires?: number;      // Registration expiration - default: 300\r\n}\r\n```\r\n\r\n### Example with Advanced Settings\r\n\r\n```typescript\r\nconst config: SIPConfig = {\r\n  sipUri: 'sip:alice@company.com',\r\n  wsUri: 'wss://sip.company.com:8089/ws',\r\n  password: 'secure-password',\r\n  displayName: 'Alice Johnson',\r\n  iceServers: [\r\n    { urls: 'stun:stun.l.google.com:19302' },\r\n    { \r\n      urls: 'turn:your-turn-server.com:3478',\r\n      username: 'turnuser',\r\n      credential: 'turnpass'\r\n    }\r\n  ],\r\n  connection: {\r\n    connectionTimeout: 15000,\r\n    maxReconnectionAttempts: 10,\r\n    reconnectionTimeout: 2000,\r\n    registrationExpires: 600\r\n  }\r\n};\r\n```\r\n\r\n## 📞 Core API\r\n\r\n### Connection Management\r\n\r\n```typescript\r\n// Connect to SIP server\r\nconst result = await sipClient.connect(config);\r\n\r\n// Disconnect\r\nawait sipClient.disconnect();\r\n\r\n// Reconnect with last configuration\r\nawait sipClient.reconnect();\r\n\r\n// Check connection status\r\nconst isConnected = sipClient.isConnected(); // boolean\r\nconst state = sipClient.getState(); // ModuleState\r\n```\r\n\r\n### Call Management\r\n\r\n```typescript\r\n// Make outgoing call\r\nconst result = await sipClient.makeCall('1234567890');\r\n// With custom domain\r\nawait sipClient.makeCall('1234567890', 'custom-domain.com');\r\n\r\n// Handle incoming calls\r\nsipClient.on('incomingCall', async (callData) => {\r\n  console.log(`Call from: ${callData.number}`);\r\n  \r\n  // Answer\r\n  await sipClient.answer();\r\n  \r\n  // Or reject\r\n  // await sipClient.reject();\r\n});\r\n\r\n// Call control\r\nawait sipClient.hangup();           // End call\r\nawait sipClient.hold();             // Put on hold\r\nawait sipClient.unhold();           // Remove from hold\r\nawait sipClient.transfer('5551234'); // Transfer call\r\n\r\n// Check call status\r\nconst hasActiveCall = sipClient.hasActiveCall();\r\nconst callState = sipClient.getCallState();\r\n```\r\n\r\n### Audio Control\r\n\r\n```typescript\r\n// Microphone control\r\nconst muteResult = sipClient.toggleMute();\r\nconsole.log(`Muted: ${muteResult.muted}`);\r\n\r\n// Volume control (0.0 - 1.0)\r\nsipClient.setVolume(0.8);\r\nconst currentVolume = sipClient.getVolume();\r\n\r\n// DTMF tones\r\nsipClient.sendDTMF('1');           // Send single digit\r\nsipClient.sendDTMF('*', 200, 100); // Custom duration and gap\r\n\r\n// Check audio status\r\nconst isMuted = sipClient.isMuted();\r\n```\r\n\r\n### Device Management\r\n\r\n```typescript\r\n// Get available devices\r\nconst devices = await sipClient.getAvailableDevices();\r\nconsole.log('Microphones:', devices.microphones);\r\nconsole.log('Speakers:', devices.speakers);\r\n\r\n// Set devices\r\nawait sipClient.setMicrophone(deviceId);  // null for default\r\nawait sipClient.setSpeaker(deviceId);\r\n\r\n// Get current devices\r\nconst current = sipClient.getCurrentDevices();\r\n\r\n// Test devices\r\nconst micTest = await sipClient.testMicrophone(deviceId);\r\nif (micTest.success) {\r\n  console.log('Audio level:', micTest.getLevel?.()); // 0-100\r\n  micTest.stop?.(); // Stop test\r\n}\r\n\r\nawait sipClient.testSpeaker(deviceId); // Plays test tone\r\n\r\n// Check speaker selection support\r\nconst supportsSelection = sipClient.isSpeakerSelectionSupported();\r\n```\r\n\r\n## 📊 Call History & Statistics\r\n\r\n```typescript\r\n// Get call history\r\nconst history = sipClient.getCallHistory(10); // Last 10 calls\r\nhistory.forEach(call => {\r\n  console.log(`${call.direction} call ${call.number} - ${call.duration}ms`);\r\n});\r\n\r\n// Get call statistics\r\nconst stats = sipClient.getCallStatistics();\r\nconsole.log(`Total calls: ${stats.totalCalls}`);\r\nconsole.log(`Answered: ${stats.answeredCalls}`);\r\nconsole.log(`Average duration: ${stats.averageDuration}ms`);\r\n\r\n// Clear history\r\nsipClient.clearCallHistory();\r\n\r\n// Get real-time call stats\r\nconst callStats = await sipClient.getCallStats();\r\nif (callStats) {\r\n  console.log(`Audio quality - Jitter: ${callStats.jitter}ms`);\r\n  console.log(`Packets lost: ${callStats.packetsLost}`);\r\n}\r\n```\r\n\r\n## 🎛️ Event System\r\n\r\n### Connection Events\r\n\r\n```typescript\r\nsipClient.on('connected', () => {\r\n  // Connected to SIP server transport\r\n});\r\n\r\nsipClient.on('registered', () => {\r\n  // Successfully registered with SIP server\r\n});\r\n\r\nsipClient.on('disconnected', () => {\r\n  // Disconnected from SIP server\r\n});\r\n\r\nsipClient.on('registrationFailed', (error: string) => {\r\n  // Registration failed\r\n});\r\n```\r\n\r\n### Call Events\r\n\r\n```typescript\r\nsipClient.on('callStarted', (callData: CallData) => {\r\n  // Outgoing call initiated\r\n});\r\n\r\nsipClient.on('incomingCall', (callData: CallData) => {\r\n  // Incoming call received\r\n});\r\n\r\nsipClient.on('callProgress', () => {\r\n  // Call is ringing/progressing\r\n});\r\n\r\nsipClient.on('callAccepted', () => {\r\n  // Call was answered/established\r\n});\r\n\r\nsipClient.on('callEnded', (data: { reason: CallEndReason }) => {\r\n  // Call ended - reasons: 'remote_hangup', 'local_hangup', 'cancelled', 'rejected', 'terminated'\r\n});\r\n\r\nsipClient.on('callAnswered', () => {\r\n  // You answered an incoming call\r\n});\r\n\r\nsipClient.on('callRejected', () => {\r\n  // You rejected an incoming call\r\n});\r\n```\r\n\r\n### Audio & Control Events\r\n\r\n```typescript\r\nsipClient.on('muteToggled', (data: { muted: boolean }) => {\r\n  // Microphone mute status changed\r\n});\r\n\r\nsipClient.on('callHeld', () => {\r\n  // Call put on hold\r\n});\r\n\r\nsipClient.on('callUnheld', () => {\r\n  // Call removed from hold\r\n});\r\n\r\nsipClient.on('dtmfSent', (data: { digit: string }) => {\r\n  // DTMF tone sent\r\n});\r\n```\r\n\r\n### Transfer Events\r\n\r\n```typescript\r\nsipClient.on('callRefer', (data: { referTo?: string; referredBy?: string }) => {\r\n  // Call transfer initiated\r\n});\r\n\r\nsipClient.on('transferAccepted', () => {\r\n  // Transfer accepted\r\n});\r\n\r\nsipClient.on('transferRejected', () => {\r\n  // Transfer rejected\r\n});\r\n```\r\n\r\n### System Events\r\n\r\n```typescript\r\nsipClient.on('error', (error: string) => {\r\n  // Error occurred\r\n});\r\n\r\nsipClient.on('stateChanged', (data: { oldState: ModuleState; newState: ModuleState }) => {\r\n  // Module state changed\r\n});\r\n```\r\n\r\n## 🏗️ Advanced Usage\r\n\r\n### Custom Event Handling\r\n\r\n```typescript\r\nimport { SIPModule, CallEndReason } from '@your-org/sip-client';\r\n\r\nclass CustomSIPHandler {\r\n  private sipClient: SIPModule;\r\n  \r\n  constructor() {\r\n    this.sipClient = new SIPModule();\r\n    this.setupEvents();\r\n  }\r\n  \r\n  private setupEvents() {\r\n    // Auto-answer incoming calls\r\n    this.sipClient.on('incomingCall', (callData) => {\r\n      if (this.shouldAutoAnswer(callData.number)) {\r\n        this.sipClient.answer();\r\n      }\r\n    });\r\n    \r\n    // Auto-redial on call failure\r\n    this.sipClient.on('callEnded', (data) => {\r\n      if (data.reason === CallEndReason.REJECTED && this.shouldRetry()) {\r\n        setTimeout(() => this.retryCall(), 5000);\r\n      }\r\n    });\r\n  }\r\n  \r\n  private shouldAutoAnswer(number: string): boolean {\r\n    // Your logic here\r\n    return this.whitelist.includes(number);\r\n  }\r\n}\r\n```\r\n\r\n### Integration with React\r\n\r\n```typescript\r\nimport { useEffect, useState } from 'react';\r\nimport { SIPModule, SIPConfig, CallData } from '@your-org/sip-client';\r\n\r\nexport function useSIPClient(config: SIPConfig) {\r\n  const [sipClient] = useState(() => new SIPModule());\r\n  const [isConnected, setIsConnected] = useState(false);\r\n  const [currentCall, setCurrentCall] = useState<CallData | null>(null);\r\n  \r\n  useEffect(() => {\r\n    sipClient.on('connected', () => setIsConnected(true));\r\n    sipClient.on('disconnected', () => setIsConnected(false));\r\n    sipClient.on('incomingCall', setCurrentCall);\r\n    sipClient.on('callEnded', () => setCurrentCall(null));\r\n    \r\n    sipClient.connect(config);\r\n    \r\n    return () => sipClient.destroy();\r\n  }, []);\r\n  \r\n  return { sipClient, isConnected, currentCall };\r\n}\r\n```\r\n\r\n## 🎯 TypeScript Types\r\n\r\n### Core Types\r\n\r\n```typescript\r\ninterface CallData {\r\n  sessionId: string;\r\n  number: string;\r\n  direction: 'incoming' | 'outgoing';\r\n  startTime: Date;\r\n  establishedTime?: Date;\r\n  endTime?: Date;\r\n  state?: string;\r\n}\r\n\r\ninterface OperationResult {\r\n  success: boolean;\r\n  error?: string;\r\n  sessionId?: string;\r\n  deviceId?: string;\r\n}\r\n\r\ninterface AudioStats {\r\n  bytesReceived: number;\r\n  bytesSent: number;\r\n  packetsLost: number;\r\n  jitter: number;\r\n  rtt: number;\r\n  audioLevel: number;\r\n}\r\n```\r\n\r\n### Enums\r\n\r\n```typescript\r\nenum CallEndReason {\r\n  REMOTE_HANGUP = 'remote_hangup',\r\n  LOCAL_HANGUP = 'local_hangup',\r\n  CANCELLED = 'cancelled',\r\n  REJECTED = 'rejected',\r\n  TERMINATED = 'terminated'\r\n}\r\n\r\nenum ModuleState {\r\n  IDLE = 'idle',\r\n  CONNECTING = 'connecting',\r\n  CONNECTED = 'connected',\r\n  CALLING = 'calling',\r\n  IN_CALL = 'in_call',\r\n  DISCONNECTING = 'disconnecting',\r\n  ERROR = 'error'\r\n}\r\n```\r\n\r\n## 🏪 Storage & Persistence\r\n\r\nThe library automatically manages call history using localStorage with graceful fallback:\r\n\r\n```typescript\r\n// Check storage availability\r\nconst hasStorage = sipClient.isStorageAvailable();\r\n\r\n// History is automatically persisted\r\nconst history = sipClient.getCallHistory();\r\n\r\n// Clear if needed\r\nsipClient.clearCallHistory();\r\n```\r\n\r\n## 🔧 Error Handling\r\n\r\n```typescript\r\n// Method-level error handling\r\nconst result = await sipClient.makeCall('1234567890');\r\nif (!result.success) {\r\n  console.error('Call failed:', result.error);\r\n}\r\n\r\n// Global error handling\r\nsipClient.on('error', (error) => {\r\n  console.error('SIP Error:', error);\r\n  // Handle connection issues, call failures, etc.\r\n});\r\n```\r\n\r\n## 🌐 Browser Support\r\n\r\n- **Chrome/Chromium 60+**\r\n- **Firefox 60+**\r\n- **Safari 12+**\r\n- **Edge 79+**\r\n\r\n**Requirements:**\r\n- WebRTC API support\r\n- getUserMedia API support\r\n- WebSocket support\r\n- ES2020+ support\r\n\r\n## 🚀 Performance\r\n\r\n- **Tree-shakeable** - Only import what you need\r\n- **Memory efficient** - Automatic cleanup and resource management\r\n- **Optimized builds** - Separate ESM, CJS, and UMD bundles\r\n- **Lazy loading** - sip.js loaded on demand\r\n\r\n## 🧪 Testing\r\n\r\n```bash\r\n# Run tests\r\nnpm test\r\n\r\n# Type checking\r\nnpm run type-check\r\n\r\n# Build verification\r\nnpm run build\r\n```\r\n\r\n## 🔗 Integration Examples\r\n\r\n### Express.js Backend Integration\r\n\r\n```typescript\r\n// server.js\r\nimport express from 'express';\r\nimport { SIPModule } from '@your-org/sip-client';\r\n\r\nconst app = express();\r\nconst sipClient = new SIPModule();\r\n\r\napp.post('/api/call', async (req, res) => {\r\n  const { number } = req.body;\r\n  const result = await sipClient.makeCall(number);\r\n  res.json(result);\r\n});\r\n```\r\n\r\n### WebSocket Notifications\r\n\r\n```typescript\r\n// Send call events to WebSocket clients\r\nsipClient.on('incomingCall', (callData) => {\r\n  websocketServer.broadcast({\r\n    type: 'incoming_call',\r\n    data: callData\r\n  });\r\n});\r\n```\r\n\r\n## 📋 Migration Guide\r\n\r\n### From v0.x to v1.x\r\n\r\n```typescript\r\n// Old way (v0.x)\r\nimport SIPClient from '@your-org/sip-client';\r\nconst client = new SIPClient();\r\n\r\n// New way (v1.x)\r\nimport { SIPModule } from '@your-org/sip-client';\r\nconst client = new SIPModule();\r\n```\r\n\r\n## 🤝 Contributing\r\n\r\n1. Fork the repository\r\n2. Create a feature branch: `git checkout -b feature/amazing-feature`\r\n3. Make your changes and add tests\r\n4. Run tests: `npm test`\r\n5. Commit: `git commit -m 'Add amazing feature'`\r\n6. Push: `git push origin feature/amazing-feature`\r\n7. Submit a pull request\r\n\r\n## 📄 License\r\n\r\nMIT License - see [LICENSE](LICENSE) file for details.\r\n\r\n## 📞 Support\r\n\r\n- **GitHub Issues**: [Report bugs](https://github.com/your-org/sip-client/issues)\r\n- **Discussions**: [Community support](https://github.com/your-org/sip-client/discussions)\r\n- **Documentation**: [Full API docs](https://your-org.github.io/sip-client)\r\n\r\n## 🙏 Acknowledgments\r\n\r\n- Built on top of [sip.js](https://sipjs.com/)\r\n- WebRTC implementation inspired by modern standards\r\n- TypeScript best practices from the community\r\n\r\n---\r\n\r\n**Made with ❤️ for the WebRTC community**","readmeFilename":"README.md","_rev":"1-8261be6fa0d99156c2674143daef7799"}