@convirza/dialer-sdk 1.0.0 → 1.0.1
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 +33 -204
- package/dist/api/DialerAPI.d.ts +0 -2
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/services/CallHistoryService.d.ts +3 -11
- package/dist/ui/ConvirzaDialerElement.d.ts +1 -1
- package/dist/utils/sip-loader.d.ts +19 -0
- package/package.json +1 -1
- package/dist/api/CallHistoryAPI.d.ts +0 -16
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @convirza/dialer-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A browser-based calling widget that lets users make and receive calls directly from the web app, with call history, call parking, device controls.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -43,18 +43,6 @@ Production-ready embeddable WebRTC SIP dialer widget. Auto-configures from OAuth
|
|
|
43
43
|
npm install @convirza/dialer-sdk
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
**Peer dependency** — SIP.js must be loaded separately (UMD global `SIP` or `sip`):
|
|
47
|
-
|
|
48
|
-
```html
|
|
49
|
-
<script src="https://cdn.jsdelivr.net/npm/sip.js@0.13.8/dist/sip.js"></script>
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Or install via npm and bundle it yourself:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npm install sip.js@^0.13.8
|
|
56
|
-
```
|
|
57
|
-
|
|
58
46
|
---
|
|
59
47
|
|
|
60
48
|
## Quick Start
|
|
@@ -75,11 +63,10 @@ const accessToken = localStorage.getItem('access_token');
|
|
|
75
63
|
const refreshToken = localStorage.getItem('refresh_token');
|
|
76
64
|
|
|
77
65
|
// Initialize widget (auto-fetches SIP config from OAuth session endpoint)
|
|
66
|
+
// OAuth/API URLs hardcoded in SDK — points to staging by default
|
|
78
67
|
convirzaDialer.init({
|
|
79
68
|
access_token: accessToken,
|
|
80
69
|
refresh_token: refreshToken,
|
|
81
|
-
oauth_endpoint: 'https://stag-5-oauth.convirza.com/oauth/internal',
|
|
82
|
-
api_url: 'https://stag-5-dialer-apis.convirza.com',
|
|
83
70
|
dark_theme: true,
|
|
84
71
|
primaryColor: '#6366f1',
|
|
85
72
|
brandName: 'Acme Corp',
|
|
@@ -134,7 +121,6 @@ const refreshToken = localStorage.getItem('refresh_token');
|
|
|
134
121
|
initDialer({
|
|
135
122
|
access_token: accessToken,
|
|
136
123
|
refresh_token: refreshToken,
|
|
137
|
-
api_url: 'https://stag-5-dialer-apis.convirza.com',
|
|
138
124
|
});
|
|
139
125
|
|
|
140
126
|
if (isDialerInitialized()) {
|
|
@@ -157,9 +143,7 @@ Embed the dialer widget as a custom HTML element.
|
|
|
157
143
|
dialer.setAttribute('access-token', accessToken);
|
|
158
144
|
dialer.setAttribute('refresh-token', refreshToken);
|
|
159
145
|
dialer.setAttribute('auto-configure', 'true');
|
|
160
|
-
dialer.setAttribute('oauth-endpoint', 'https://stag-5-oauth.convirza.com/oauth/internal');
|
|
161
146
|
dialer.setAttribute('theme', 'dark');
|
|
162
|
-
dialer.setAttribute('api-url', 'https://stag-5-dialer-apis.convirza.com');
|
|
163
147
|
|
|
164
148
|
// Listen for token refresh (only fires if access_token expires)
|
|
165
149
|
dialer.addEventListener('token-refreshed', (e) => {
|
|
@@ -182,8 +166,6 @@ Embed the dialer widget as a custom HTML element.
|
|
|
182
166
|
- `access-token` — Access token from user login (used first)
|
|
183
167
|
- `refresh-token` — Refresh token (fallback if access_token expires)
|
|
184
168
|
- `auto-configure="true"` — Enables auto-config flow
|
|
185
|
-
- `oauth-endpoint` — OAuth base URL (default: `https://stag-5-oauth.convirza.com/oauth/internal`)
|
|
186
|
-
- `api-url` — API base URL for park slots, call history
|
|
187
169
|
|
|
188
170
|
**Events:**
|
|
189
171
|
|
|
@@ -222,7 +204,6 @@ localStorage.setItem('refresh_token', refresh_token);
|
|
|
222
204
|
convirzaDialer.init({
|
|
223
205
|
access_token: localStorage.getItem('access_token'),
|
|
224
206
|
refresh_token: localStorage.getItem('refresh_token'),
|
|
225
|
-
oauth_endpoint: 'https://stag-5-oauth.convirza.com/oauth/internal',
|
|
226
207
|
});
|
|
227
208
|
```
|
|
228
209
|
|
|
@@ -349,28 +330,23 @@ Initialize the dialer and inject the widget into the page. **Must be called befo
|
|
|
349
330
|
convirzaDialer.init(config: DialerInitConfig): void
|
|
350
331
|
```
|
|
351
332
|
|
|
352
|
-
| Field
|
|
353
|
-
|
|
|
354
|
-
| `access_token`
|
|
355
|
-
| `refresh_token`
|
|
356
|
-
| `
|
|
357
|
-
| `
|
|
358
|
-
| `
|
|
359
|
-
| `
|
|
360
|
-
| `
|
|
361
|
-
| `
|
|
362
|
-
| `primaryColor` | `string` | No | CSS color for primary UI elements (hex/rgb) |
|
|
363
|
-
| `accentColor` | `string` | No | CSS color for accent elements |
|
|
364
|
-
|
|
365
|
-
OAuth response provides SIP credentials automatically. User never sees SIP details.
|
|
333
|
+
| Field | Type | Required | Description |
|
|
334
|
+
| --------------- | --------- | -------- | -------------------------------------------- |
|
|
335
|
+
| `access_token` | `string` | Yes | Access token from user login session |
|
|
336
|
+
| `refresh_token` | `string` | Yes | Refresh token (used if access_token expires) |
|
|
337
|
+
| `brandName` | `string` | No | Brand name shown in widget header |
|
|
338
|
+
| `brandLogo` | `string` | No | URL of brand logo image |
|
|
339
|
+
| `dark_theme` | `boolean` | No | Use dark theme (default `false`) |
|
|
340
|
+
| `showPopup` | `boolean` | No | Start with widget expanded |
|
|
341
|
+
| `primaryColor` | `string` | No | CSS color for primary UI elements (hex/rgb) |
|
|
342
|
+
| `accentColor` | `string` | No | CSS color for accent elements |
|
|
366
343
|
|
|
367
344
|
**Example:**
|
|
368
345
|
|
|
369
346
|
```js
|
|
370
347
|
convirzaDialer.init({
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
password: 'userpassword',
|
|
348
|
+
access_token: 'eyJhbGc...',
|
|
349
|
+
refresh_token: 'eyJhbGc...',
|
|
374
350
|
dark_theme: true,
|
|
375
351
|
primaryColor: '#6366f1',
|
|
376
352
|
brandName: 'Acme Corp',
|
|
@@ -1208,48 +1184,6 @@ const result = await api.fetchOrderedNumbers({
|
|
|
1208
1184
|
|
|
1209
1185
|
---
|
|
1210
1186
|
|
|
1211
|
-
### `CallHistoryAPI`
|
|
1212
|
-
|
|
1213
|
-
REST client for persisting and querying call history.
|
|
1214
|
-
|
|
1215
|
-
```ts
|
|
1216
|
-
import { CallHistoryAPI } from '@convirza/dialer-sdk';
|
|
1217
|
-
|
|
1218
|
-
const api = new CallHistoryAPI('https://api.convirza.com', 'Bearer-token');
|
|
1219
|
-
|
|
1220
|
-
const history = await api.fetchHistory({
|
|
1221
|
-
userId: 'user-123',
|
|
1222
|
-
sipDomain: 'sip.example.com',
|
|
1223
|
-
limit: 50,
|
|
1224
|
-
offset: 0,
|
|
1225
|
-
});
|
|
1226
|
-
// history: { calls: CallRecord[], total: number, hasMore: boolean }
|
|
1227
|
-
|
|
1228
|
-
const saved = await api.saveCall({
|
|
1229
|
-
callId: 'abc-123',
|
|
1230
|
-
userId: 'user-123',
|
|
1231
|
-
sipDomain: 'sip.example.com',
|
|
1232
|
-
callerIdNumber: '+15551234567',
|
|
1233
|
-
phoneNumber: '+19876543210',
|
|
1234
|
-
direction: 'outbound',
|
|
1235
|
-
disposition: 'answered',
|
|
1236
|
-
startedAt: Date.now(),
|
|
1237
|
-
durationSeconds: 42,
|
|
1238
|
-
createdAt: Date.now(),
|
|
1239
|
-
});
|
|
1240
|
-
|
|
1241
|
-
const updated = await api.updateCall(saved.callId, { disposition: 'missed' });
|
|
1242
|
-
```
|
|
1243
|
-
|
|
1244
|
-
| Method | Description |
|
|
1245
|
-
| ----------------------------- | -------------------------------- |
|
|
1246
|
-
| `setAuthToken(token)` | Update the bearer token |
|
|
1247
|
-
| `fetchHistory(params)` | Fetch paginated call history |
|
|
1248
|
-
| `saveCall(record)` | Create a new call history record |
|
|
1249
|
-
| `updateCall(callId, updates)` | Patch an existing call record |
|
|
1250
|
-
|
|
1251
|
-
---
|
|
1252
|
-
|
|
1253
1187
|
## Web Component Reference
|
|
1254
1188
|
|
|
1255
1189
|
### Web Component Attributes
|
|
@@ -1261,8 +1195,6 @@ The `<convirza-dialer>` custom element accepts the following HTML attributes:
|
|
|
1261
1195
|
| `access-token` | `string` | Yes\* | Access token from user login |
|
|
1262
1196
|
| `refresh-token` | `string` | Yes\* | Refresh token (fallback if access_token expires) |
|
|
1263
1197
|
| `auto-configure` | `'true' \| 'false'` | Yes\* | Enable auto-config from OAuth session |
|
|
1264
|
-
| `oauth-endpoint` | `string` | No | OAuth base URL (default: stag-5 internal) |
|
|
1265
|
-
| `api-url` | `string` | No | API base URL for park/history |
|
|
1266
1198
|
| `brand-name` | `string` | No | Brand name in header |
|
|
1267
1199
|
| `brand-logo` | `string` | No | URL for brand logo |
|
|
1268
1200
|
| `theme` | `'light' \| 'dark'` | No | UI theme (default: dark) |
|
|
@@ -1273,8 +1205,6 @@ The `<convirza-dialer>` custom element accepts the following HTML attributes:
|
|
|
1273
1205
|
| `z-index` | `number` | No | CSS z-index of the widget |
|
|
1274
1206
|
| `park-poll-interval` | `number` | No | Park slots polling interval in ms (default 5000) |
|
|
1275
1207
|
|
|
1276
|
-
**Required only for auto-configure mode.** Widget fetches SIP credentials from OAuth session endpoint automatically.
|
|
1277
|
-
|
|
1278
1208
|
### Web Component Public Methods
|
|
1279
1209
|
|
|
1280
1210
|
All methods can be called on the element reference.
|
|
@@ -1420,7 +1350,7 @@ element.setTheme({
|
|
|
1420
1350
|
|
|
1421
1351
|
#### `element.clearCallHistoryCache()`
|
|
1422
1352
|
|
|
1423
|
-
Clear IndexedDB call history
|
|
1353
|
+
Clear IndexedDB call history.
|
|
1424
1354
|
|
|
1425
1355
|
```ts
|
|
1426
1356
|
async clearCallHistoryCache(): Promise<void>
|
|
@@ -1514,17 +1444,14 @@ Call parking allows transferring an active call to a shared "parking lot" where
|
|
|
1514
1444
|
**HTML Attributes:**
|
|
1515
1445
|
|
|
1516
1446
|
```html
|
|
1517
|
-
<convirza-dialer
|
|
1518
|
-
api-url="https://stag-5-dialer-apis.convirza.com"
|
|
1519
|
-
auth-token="Bearer xyz"
|
|
1520
|
-
park-poll-interval="5000"
|
|
1521
|
-
></convirza-dialer>
|
|
1447
|
+
<convirza-dialer auth-token="Bearer xyz" park-poll-interval="5000"></convirza-dialer>
|
|
1522
1448
|
```
|
|
1523
1449
|
|
|
1524
|
-
- `api-url`: Base API URL — park endpoint is `{api-url}/v3/park-slots`
|
|
1525
1450
|
- `auth-token`: JWT or API key for backend auth
|
|
1526
1451
|
- `park-poll-interval`: Poll interval in ms (default: 5000)
|
|
1527
1452
|
|
|
1453
|
+
**Note:** API URL hardcoded in SDK — park endpoint auto-detected as `{API_URL}/v3/park-slots`
|
|
1454
|
+
|
|
1528
1455
|
#### Backend API
|
|
1529
1456
|
|
|
1530
1457
|
**Required endpoint:**
|
|
@@ -1578,81 +1505,30 @@ element.addEventListener('call-park-failed', (e) => {
|
|
|
1578
1505
|
|
|
1579
1506
|
### Call History Persistence
|
|
1580
1507
|
|
|
1581
|
-
Call history
|
|
1582
|
-
|
|
1583
|
-
1. **IndexedDB** (local cache) — instant load, offline support
|
|
1584
|
-
2. **Backend API** (source of truth) — multi-device sync, compliance
|
|
1585
|
-
|
|
1586
|
-
Widget saves to IndexedDB immediately (non-blocking), then syncs to backend async.
|
|
1508
|
+
Call history saved to **IndexedDB** (browser-local storage). No backend sync.
|
|
1587
1509
|
|
|
1588
1510
|
#### Data Flow
|
|
1589
1511
|
|
|
1590
1512
|
**On call end:**
|
|
1591
1513
|
|
|
1592
1514
|
1. Widget generates UUID `callId`
|
|
1593
|
-
2. Saves to IndexedDB
|
|
1594
|
-
3.
|
|
1595
|
-
4. Reloads history from IndexedDB to update UI
|
|
1515
|
+
2. Saves to IndexedDB
|
|
1516
|
+
3. Reloads history to update UI
|
|
1596
1517
|
|
|
1597
1518
|
**On SIP registration:**
|
|
1598
1519
|
|
|
1599
1520
|
1. Initialize `CallHistoryService`
|
|
1600
|
-
2. Load from IndexedDB
|
|
1601
|
-
3. Background-sync from backend (replaces IndexedDB cache)
|
|
1521
|
+
2. Load from IndexedDB
|
|
1602
1522
|
|
|
1603
1523
|
**On page reload:**
|
|
1604
1524
|
|
|
1605
1525
|
- IndexedDB persists → history visible immediately
|
|
1606
|
-
- Backend sync refreshes on reconnect
|
|
1607
|
-
|
|
1608
|
-
#### Configuration
|
|
1609
1526
|
|
|
1610
|
-
|
|
1527
|
+
#### Storage Scope
|
|
1611
1528
|
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
- `api-url`: Base API URL — history endpoint = `{api-url}/api/call-history`
|
|
1617
|
-
- `auth-token`: JWT or API key for backend auth
|
|
1618
|
-
|
|
1619
|
-
**If `api-url` not set:**
|
|
1620
|
-
|
|
1621
|
-
- IndexedDB-only mode (no backend sync)
|
|
1622
|
-
- History persists locally but not across devices
|
|
1623
|
-
|
|
1624
|
-
#### Backend API
|
|
1625
|
-
|
|
1626
|
-
**Required endpoints:**
|
|
1627
|
-
|
|
1628
|
-
```
|
|
1629
|
-
GET /api/call-history?userId={id}&sipDomain={domain}&limit=100&offset=0
|
|
1630
|
-
POST /api/call-history
|
|
1631
|
-
PATCH /api/call-history/{callId}
|
|
1632
|
-
```
|
|
1633
|
-
|
|
1634
|
-
**Database schema (PostgreSQL):**
|
|
1635
|
-
|
|
1636
|
-
```sql
|
|
1637
|
-
CREATE TABLE call_history (
|
|
1638
|
-
id BIGSERIAL PRIMARY KEY,
|
|
1639
|
-
call_id VARCHAR(100) UNIQUE NOT NULL,
|
|
1640
|
-
user_id VARCHAR(50) NOT NULL,
|
|
1641
|
-
sip_domain VARCHAR(100) NOT NULL,
|
|
1642
|
-
phone_number VARCHAR(50) NOT NULL,
|
|
1643
|
-
direction VARCHAR(10) NOT NULL CHECK (direction IN ('inbound', 'outbound')),
|
|
1644
|
-
status VARCHAR(20) NOT NULL CHECK (status IN ('answered', 'missed', 'rejected', 'failed')),
|
|
1645
|
-
started_at TIMESTAMPTZ NOT NULL,
|
|
1646
|
-
ended_at TIMESTAMPTZ,
|
|
1647
|
-
duration_seconds INTEGER DEFAULT 0,
|
|
1648
|
-
recording_url VARCHAR(500),
|
|
1649
|
-
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
1650
|
-
INDEX idx_user_domain_started (user_id, sip_domain, started_at DESC),
|
|
1651
|
-
INDEX idx_call_id (call_id)
|
|
1652
|
-
);
|
|
1653
|
-
```
|
|
1654
|
-
|
|
1655
|
-
See `docs/CALL_HISTORY_API.md` for full spec, Node.js examples, security notes.
|
|
1529
|
+
- **Per-browser only** — not synced across devices
|
|
1530
|
+
- **Offline support** — no network dependency
|
|
1531
|
+
- **Privacy** — stays local, never uploaded
|
|
1656
1532
|
|
|
1657
1533
|
#### Events
|
|
1658
1534
|
|
|
@@ -1664,6 +1540,13 @@ element.addEventListener('history-updated', (e) => {
|
|
|
1664
1540
|
});
|
|
1665
1541
|
```
|
|
1666
1542
|
|
|
1543
|
+
#### API Methods
|
|
1544
|
+
|
|
1545
|
+
```js
|
|
1546
|
+
// Clear all call history
|
|
1547
|
+
await dialer.clearCallHistoryCache();
|
|
1548
|
+
```
|
|
1549
|
+
|
|
1667
1550
|
### Audio Device Management
|
|
1668
1551
|
|
|
1669
1552
|
Microphone and speaker selection with hot-swapping during calls.
|
|
@@ -1686,35 +1569,6 @@ await sip.setSpeaker(deviceId);
|
|
|
1686
1569
|
- Microphone switching: Chrome, Firefox, Safari, Edge
|
|
1687
1570
|
- Speaker switching (`setSinkId`): Chrome, Edge only (silently no-ops in Firefox/Safari)
|
|
1688
1571
|
|
|
1689
|
-
### Call Quality Monitoring
|
|
1690
|
-
|
|
1691
|
-
Polls `RTCPeerConnection.getStats()` every 2s and emits quality metrics.
|
|
1692
|
-
|
|
1693
|
-
**Metrics:**
|
|
1694
|
-
|
|
1695
|
-
- **Bitrate** (kbps)
|
|
1696
|
-
- **Packet loss** (%)
|
|
1697
|
-
- **Jitter** (ms)
|
|
1698
|
-
- **Latency** (ms, round-trip)
|
|
1699
|
-
- **Audio level** (0–1)
|
|
1700
|
-
- **Quality** (`excellent` | `good` | `fair` | `poor`)
|
|
1701
|
-
|
|
1702
|
-
**Usage:**
|
|
1703
|
-
|
|
1704
|
-
```js
|
|
1705
|
-
const sip = new SipAdapter(config, {
|
|
1706
|
-
onQualityChange: (metrics) => {
|
|
1707
|
-
if (metrics.quality === 'poor') {
|
|
1708
|
-
console.warn('Poor call quality:', metrics);
|
|
1709
|
-
}
|
|
1710
|
-
},
|
|
1711
|
-
});
|
|
1712
|
-
|
|
1713
|
-
// Or poll manually
|
|
1714
|
-
const metrics = sip.getCallQuality();
|
|
1715
|
-
console.log('Packet loss:', metrics.packetLoss + '%');
|
|
1716
|
-
```
|
|
1717
|
-
|
|
1718
1572
|
### Theming
|
|
1719
1573
|
|
|
1720
1574
|
#### HTML Attributes (static)
|
|
@@ -1808,31 +1662,6 @@ Requires a browser with WebRTC (`RTCPeerConnection`) and WebSocket support.
|
|
|
1808
1662
|
|
|
1809
1663
|
---
|
|
1810
1664
|
|
|
1811
|
-
## Project Structure
|
|
1812
|
-
|
|
1813
|
-
```
|
|
1814
|
-
convirza-dialer-1/
|
|
1815
|
-
├── packages/web-sdk/
|
|
1816
|
-
│ ├── src/ # Source code (TypeScript)
|
|
1817
|
-
│ │ ├── ui/ # Web component
|
|
1818
|
-
│ │ ├── sip/ # SIP adapter
|
|
1819
|
-
│ │ ├── api/ # REST clients
|
|
1820
|
-
│ │ ├── media/ # Audio device management
|
|
1821
|
-
│ │ ├── constants/ # Configuration
|
|
1822
|
-
│ │ └── types/ # TypeScript types
|
|
1823
|
-
│ ├── test/ # Unit tests
|
|
1824
|
-
│ ├── dist/ # Built output (published)
|
|
1825
|
-
│ │ ├── index.esm.js # ES modules
|
|
1826
|
-
│ │ ├── index.cjs.js # CommonJS
|
|
1827
|
-
│ │ ├── index.umd.js # UMD (browser)
|
|
1828
|
-
│ │ └── types/ # TypeScript declarations
|
|
1829
|
-
│ └── package.json # Package metadata
|
|
1830
|
-
└── demo/ # Demo files (root level, not published)
|
|
1831
|
-
├── demo.html # Interactive demo
|
|
1832
|
-
├── sip.bundle.js # Bundled SIP.js
|
|
1833
|
-
└── README.md # Demo instructions
|
|
1834
|
-
```
|
|
1835
|
-
|
|
1836
1665
|
**For development:** Work in `src/` directory.
|
|
1837
1666
|
**For users:** Import from `dist/` (handled automatically by package.json).
|
|
1838
1667
|
|