@sippet-ai/operator-widget 0.0.15 → 0.0.17
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 +41 -0
- package/custom-elements.json +35 -0
- package/dist/components/voip-widget/voip-widget.d.ts +5 -0
- package/dist/components/voip-widget/voip-widget.js +68 -33
- package/dist/lib/sippet.d.ts +2 -0
- package/dist/lib/sippet.js +30 -7
- package/package.json +2 -2
- package/react/SippetAIVoipWidget.d.ts +5 -0
- package/react/SippetAIVoipWidget.js +2 -0
- package/types/custom-element-jsx.d.ts +16 -0
- package/types/custom-element-svelte.d.ts +4 -0
- package/types/custom-element-vuejs.d.ts +4 -0
package/README.md
CHANGED
|
@@ -93,6 +93,39 @@ export function SupportWidget() {
|
|
|
93
93
|
}
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
## Shared SDK + widget state
|
|
97
|
+
|
|
98
|
+
Initialize one SDK client with `initClient(...)` and pass that same object to
|
|
99
|
+
the widget as a property. This keeps SIP session/call state in one place, so
|
|
100
|
+
SDK actions (for example joining a call) are reflected in the widget UI.
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
import { SippetAIVoipWidget } from '@sippet-ai/operator-widget/react';
|
|
104
|
+
import { initClient } from '@sippet-ai/sdk-js/client';
|
|
105
|
+
|
|
106
|
+
const sdkClient = initClient({
|
|
107
|
+
baseUrl: 'https://api.sippet.ai',
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export function SupportWidget({ isWidgetOpen }: { isWidgetOpen: boolean }) {
|
|
111
|
+
return (
|
|
112
|
+
<SippetAIVoipWidget
|
|
113
|
+
client={sdkClient}
|
|
114
|
+
openWidget={isWidgetOpen}
|
|
115
|
+
getAccessToken={async () => {
|
|
116
|
+
const response = await fetch('/api/your-backend/operator-token', {
|
|
117
|
+
method: 'POST',
|
|
118
|
+
});
|
|
119
|
+
if (!response.ok) throw new Error('Failed to mint operator token');
|
|
120
|
+
const body = await response.json();
|
|
121
|
+
return body.token;
|
|
122
|
+
}}
|
|
123
|
+
apiOrigin="https://api.sippet.ai"
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
96
129
|
## Token rotation with backend endpoint
|
|
97
130
|
|
|
98
131
|
```tsx
|
|
@@ -120,12 +153,20 @@ export function SupportWidget() {
|
|
|
120
153
|
- `access-token` / `accessToken`: operator bearer token.
|
|
121
154
|
- `getAccessToken` (property only): async token resolver.
|
|
122
155
|
- `api-origin` / `apiOrigin`: API origin override.
|
|
156
|
+
- `client` (property only): shared SDK client instance from `@sippet-ai/sdk-js/client`.
|
|
157
|
+
- `open-widget` / `openWidget`: controls whether the panel is open.
|
|
123
158
|
|
|
124
159
|
## Helper API
|
|
125
160
|
|
|
126
161
|
```ts
|
|
127
162
|
import { sippet } from '@sippet-ai/operator-widget';
|
|
163
|
+
import { initClient } from '@sippet-ai/sdk-js/client';
|
|
164
|
+
|
|
165
|
+
const sdkClient = initClient({
|
|
166
|
+
baseUrl: 'https://api.sippet.ai',
|
|
167
|
+
});
|
|
128
168
|
|
|
169
|
+
sippet.setClient(sdkClient);
|
|
129
170
|
sippet.setGetAccessToken(async () => {
|
|
130
171
|
const response = await fetch('/api/your-backend/operator-token', {
|
|
131
172
|
method: 'POST',
|
package/custom-elements.json
CHANGED
|
@@ -1223,6 +1223,14 @@
|
|
|
1223
1223
|
"name": "clearSipCredentialRefresh",
|
|
1224
1224
|
"privacy": "private"
|
|
1225
1225
|
},
|
|
1226
|
+
{
|
|
1227
|
+
"kind": "field",
|
|
1228
|
+
"name": "client",
|
|
1229
|
+
"type": {
|
|
1230
|
+
"text": "SippetAIVoipWidgetClient | null"
|
|
1231
|
+
},
|
|
1232
|
+
"default": "null"
|
|
1233
|
+
},
|
|
1226
1234
|
{
|
|
1227
1235
|
"kind": "method",
|
|
1228
1236
|
"name": "configureSdkEndpoints",
|
|
@@ -1650,6 +1658,15 @@
|
|
|
1650
1658
|
"text": "openPanel(tab: VoipTab = 'phone') => void"
|
|
1651
1659
|
}
|
|
1652
1660
|
},
|
|
1661
|
+
{
|
|
1662
|
+
"kind": "field",
|
|
1663
|
+
"name": "openWidget",
|
|
1664
|
+
"type": {
|
|
1665
|
+
"text": "boolean"
|
|
1666
|
+
},
|
|
1667
|
+
"default": "false",
|
|
1668
|
+
"attribute": "open-widget"
|
|
1669
|
+
},
|
|
1653
1670
|
{
|
|
1654
1671
|
"kind": "method",
|
|
1655
1672
|
"name": "parseParticipantPayload",
|
|
@@ -1880,6 +1897,15 @@
|
|
|
1880
1897
|
}
|
|
1881
1898
|
]
|
|
1882
1899
|
},
|
|
1900
|
+
{
|
|
1901
|
+
"kind": "field",
|
|
1902
|
+
"name": "sdkClient",
|
|
1903
|
+
"type": {
|
|
1904
|
+
"text": "SippetAIVoipWidgetClient"
|
|
1905
|
+
},
|
|
1906
|
+
"privacy": "private",
|
|
1907
|
+
"readonly": true
|
|
1908
|
+
},
|
|
1883
1909
|
{
|
|
1884
1910
|
"kind": "field",
|
|
1885
1911
|
"name": "selectedMicId",
|
|
@@ -2342,6 +2368,15 @@
|
|
|
2342
2368
|
"fieldName": "open",
|
|
2343
2369
|
"propName": "open"
|
|
2344
2370
|
},
|
|
2371
|
+
{
|
|
2372
|
+
"name": "open-widget",
|
|
2373
|
+
"type": {
|
|
2374
|
+
"text": "boolean"
|
|
2375
|
+
},
|
|
2376
|
+
"default": "false",
|
|
2377
|
+
"fieldName": "openWidget",
|
|
2378
|
+
"propName": "openWidget"
|
|
2379
|
+
},
|
|
2345
2380
|
{
|
|
2346
2381
|
"name": "queueCount",
|
|
2347
2382
|
"type": {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
|
+
import type { Client as SippetSdkClient } from '@sippet-ai/sdk-js/client';
|
|
2
3
|
import type { Contact, HistoryEntry, QueuedCall, VoipTab } from './voip-widget.types.js';
|
|
3
4
|
import './voip-widget-launcher.js';
|
|
4
5
|
import './voip-widget-panel.js';
|
|
@@ -8,6 +9,7 @@ import './voip-widget-contacts-tab.js';
|
|
|
8
9
|
import './voip-widget-history-tab.js';
|
|
9
10
|
import './voip-widget-settings-tab.js';
|
|
10
11
|
declare const TwLitElement: typeof LitElement;
|
|
12
|
+
export type SippetAIVoipWidgetClient = Pick<SippetSdkClient, 'answerIncomingSipCall' | 'acceptCallQueueEntry' | 'buildCSRFHeaders' | 'callCodec' | 'connectSipSession' | 'createRealtimeEventsClient' | 'declineIncomingSipCall' | 'DEFAULT_BASE_URL' | 'disconnectSipSession' | 'getSipSessionState' | 'hangupSipCall' | 'issueOperatorSipAccess' | 'listCallParticipants' | 'listCallQueueEntries' | 'listCalls' | 'listContacts' | 'placeSipCall' | 'setConferenceMuted' | 'setOutputDevice' | 'setOperatorStatus' | 'setRemoteAudioElement' | 'setSipCallHeld' | 'subscribeSipSessionState' | 'whoAmI'>;
|
|
11
13
|
/**
|
|
12
14
|
* A VoIP widget web component allowing real-time telephony for Sippet AI integrations
|
|
13
15
|
*
|
|
@@ -17,6 +19,7 @@ declare const TwLitElement: typeof LitElement;
|
|
|
17
19
|
*
|
|
18
20
|
**/
|
|
19
21
|
export declare class SippetAIVoipWidget extends TwLitElement {
|
|
22
|
+
client: SippetAIVoipWidgetClient | null;
|
|
20
23
|
cookieAuth: boolean;
|
|
21
24
|
accessToken: string;
|
|
22
25
|
getAccessToken?: (() => string | Promise<string>) | null;
|
|
@@ -30,6 +33,7 @@ export declare class SippetAIVoipWidget extends TwLitElement {
|
|
|
30
33
|
history: HistoryEntry[];
|
|
31
34
|
queuedCalls: QueuedCall[];
|
|
32
35
|
open: boolean;
|
|
36
|
+
openWidget: boolean;
|
|
33
37
|
activeTab: VoipTab;
|
|
34
38
|
private dialNumber;
|
|
35
39
|
private callState;
|
|
@@ -70,6 +74,7 @@ export declare class SippetAIVoipWidget extends TwLitElement {
|
|
|
70
74
|
private widgetLockHeartbeat?;
|
|
71
75
|
private widgetLockPoller?;
|
|
72
76
|
private widgetTabId;
|
|
77
|
+
private get sdkClient();
|
|
73
78
|
private get sipServer();
|
|
74
79
|
private ensureTabId;
|
|
75
80
|
private readWidgetLock;
|
|
@@ -8,7 +8,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
import { html, LitElement } from 'lit';
|
|
9
9
|
import { property, query, state } from 'lit/decorators.js';
|
|
10
10
|
import { TW } from '../../lib/tailwindMixin.js';
|
|
11
|
-
import
|
|
11
|
+
import * as SippetSdkClientModule from '@sippet-ai/sdk-js/client';
|
|
12
12
|
import './voip-widget-launcher.js';
|
|
13
13
|
import './voip-widget-panel.js';
|
|
14
14
|
import './voip-widget-phone-tab.js';
|
|
@@ -24,6 +24,7 @@ const WIDGET_LOCK_HEARTBEAT_MS = 2000;
|
|
|
24
24
|
const WIDGET_LOCK_STALE_MS = 8000;
|
|
25
25
|
const AUTH_ERROR_MISSING_TOKEN = 'Cannot find any access token. Provide `access-token` or `getAccessToken`.';
|
|
26
26
|
const AUTH_ERROR_UNAUTHORIZED = 'Widget authentication failed. Sign in again or provide a valid access token.';
|
|
27
|
+
const DEFAULT_WIDGET_CLIENT = SippetSdkClientModule;
|
|
27
28
|
/**
|
|
28
29
|
* A VoIP widget web component allowing real-time telephony for Sippet AI integrations
|
|
29
30
|
*
|
|
@@ -35,6 +36,7 @@ const AUTH_ERROR_UNAUTHORIZED = 'Widget authentication failed. Sign in again or
|
|
|
35
36
|
export class SippetAIVoipWidget extends TwLitElement {
|
|
36
37
|
constructor() {
|
|
37
38
|
super(...arguments);
|
|
39
|
+
this.client = null;
|
|
38
40
|
this.cookieAuth = false;
|
|
39
41
|
this.accessToken = '';
|
|
40
42
|
this.apiOrigin = '';
|
|
@@ -47,6 +49,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
47
49
|
this.history = [];
|
|
48
50
|
this.queuedCalls = [];
|
|
49
51
|
this.open = false;
|
|
52
|
+
this.openWidget = false;
|
|
50
53
|
this.activeTab = 'phone';
|
|
51
54
|
this.dialNumber = '';
|
|
52
55
|
this.callState = 'idle';
|
|
@@ -172,6 +175,9 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
172
175
|
void this.loadQueueEntries();
|
|
173
176
|
};
|
|
174
177
|
}
|
|
178
|
+
get sdkClient() {
|
|
179
|
+
return this.client ?? DEFAULT_WIDGET_CLIENT;
|
|
180
|
+
}
|
|
175
181
|
get sipServer() {
|
|
176
182
|
if (this.sipWebSocketUrl)
|
|
177
183
|
return this.sipWebSocketUrl;
|
|
@@ -390,7 +396,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
390
396
|
if (this.cookieAuth) {
|
|
391
397
|
this.clearAuthError();
|
|
392
398
|
return {
|
|
393
|
-
headers: buildCSRFHeaders(),
|
|
399
|
+
headers: this.sdkClient.buildCSRFHeaders(),
|
|
394
400
|
fetchOptions: { credentials: 'include' },
|
|
395
401
|
};
|
|
396
402
|
}
|
|
@@ -406,7 +412,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
406
412
|
const config = await this.getRpcConfig();
|
|
407
413
|
if (!config)
|
|
408
414
|
return;
|
|
409
|
-
const result = await whoAmI({
|
|
415
|
+
const result = await this.sdkClient.whoAmI({
|
|
410
416
|
fields: ['id', 'fullName', 'email', { sipUser: ['id', 'sipUsername'] }],
|
|
411
417
|
...config,
|
|
412
418
|
});
|
|
@@ -432,12 +438,14 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
432
438
|
}
|
|
433
439
|
}
|
|
434
440
|
async fetchRealtimeSessionToken() {
|
|
435
|
-
const baseUrl = this.apiOrigin || DEFAULT_BASE_URL;
|
|
441
|
+
const baseUrl = this.apiOrigin || this.sdkClient.DEFAULT_BASE_URL;
|
|
436
442
|
const endpoint = new URL('/api/realtime/session', baseUrl).toString();
|
|
437
443
|
if (this.cookieAuth) {
|
|
438
444
|
const response = await fetch(endpoint, {
|
|
439
445
|
method: 'POST',
|
|
440
|
-
headers: buildCSRFHeaders({
|
|
446
|
+
headers: this.sdkClient.buildCSRFHeaders({
|
|
447
|
+
'content-type': 'application/json',
|
|
448
|
+
}),
|
|
441
449
|
credentials: 'include',
|
|
442
450
|
});
|
|
443
451
|
if (!response.ok) {
|
|
@@ -517,7 +525,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
517
525
|
if (!config)
|
|
518
526
|
return;
|
|
519
527
|
this.sipCredentialPromise = (async () => {
|
|
520
|
-
const result = await issueOperatorSipAccess({
|
|
528
|
+
const result = await this.sdkClient.issueOperatorSipAccess({
|
|
521
529
|
input: {},
|
|
522
530
|
...config,
|
|
523
531
|
});
|
|
@@ -633,7 +641,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
633
641
|
}
|
|
634
642
|
async applySpeakerSelection() {
|
|
635
643
|
try {
|
|
636
|
-
await setOutputDevice(this.selectedSpeakerId || null);
|
|
644
|
+
await this.sdkClient.setOutputDevice(this.selectedSpeakerId || null);
|
|
637
645
|
}
|
|
638
646
|
catch (error) {
|
|
639
647
|
// Some browsers restrict setSinkId without user gesture.
|
|
@@ -653,9 +661,9 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
653
661
|
this.sipStatus = 'connecting';
|
|
654
662
|
try {
|
|
655
663
|
if (this.remoteAudio) {
|
|
656
|
-
setRemoteAudioElement(this.remoteAudio);
|
|
664
|
+
this.sdkClient.setRemoteAudioElement(this.remoteAudio);
|
|
657
665
|
}
|
|
658
|
-
await connectSipSession({
|
|
666
|
+
await this.sdkClient.connectSipSession({
|
|
659
667
|
server,
|
|
660
668
|
domain: this.sipUrl,
|
|
661
669
|
username: this.sipUser,
|
|
@@ -672,20 +680,23 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
672
680
|
}
|
|
673
681
|
async teardownSip() {
|
|
674
682
|
try {
|
|
675
|
-
await disconnectSipSession();
|
|
683
|
+
await this.sdkClient.disconnectSipSession();
|
|
676
684
|
}
|
|
677
685
|
catch (error) {
|
|
678
686
|
// Best-effort cleanup.
|
|
679
687
|
}
|
|
680
688
|
}
|
|
681
689
|
firstUpdated() {
|
|
690
|
+
if (this.openWidget !== this.open) {
|
|
691
|
+
this.open = this.openWidget;
|
|
692
|
+
}
|
|
682
693
|
this.configureSdkEndpoints();
|
|
683
694
|
this.initWidgetLock();
|
|
684
695
|
if (this.remoteAudio) {
|
|
685
|
-
setRemoteAudioElement(this.remoteAudio);
|
|
696
|
+
this.sdkClient.setRemoteAudioElement(this.remoteAudio);
|
|
686
697
|
}
|
|
687
|
-
this.sipSessionUnsubscribe = subscribeSipSessionState(this.applySipSessionState);
|
|
688
|
-
this.applySipSessionState(getSipSessionState());
|
|
698
|
+
this.sipSessionUnsubscribe = this.sdkClient.subscribeSipSessionState(this.applySipSessionState);
|
|
699
|
+
this.applySipSessionState(this.sdkClient.getSipSessionState());
|
|
689
700
|
void this.loadOperatorIdentity();
|
|
690
701
|
void this.refreshSessionSipCredentials();
|
|
691
702
|
void this.refreshDevices();
|
|
@@ -698,9 +709,27 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
698
709
|
}
|
|
699
710
|
}
|
|
700
711
|
updated(changedProperties) {
|
|
712
|
+
if (changedProperties.has('openWidget') && this.openWidget !== this.open) {
|
|
713
|
+
this.open = this.openWidget;
|
|
714
|
+
}
|
|
715
|
+
if (changedProperties.has('open') && this.openWidget !== this.open) {
|
|
716
|
+
this.openWidget = this.open;
|
|
717
|
+
}
|
|
718
|
+
const clientChanged = changedProperties.has('client');
|
|
701
719
|
const authChanged = changedProperties.has('cookieAuth') ||
|
|
702
720
|
changedProperties.has('accessToken') ||
|
|
703
|
-
changedProperties.has('getAccessToken')
|
|
721
|
+
changedProperties.has('getAccessToken') ||
|
|
722
|
+
clientChanged;
|
|
723
|
+
if (clientChanged) {
|
|
724
|
+
const previousClient = changedProperties.get('client');
|
|
725
|
+
previousClient?.setRemoteAudioElement(null);
|
|
726
|
+
this.sipSessionUnsubscribe?.();
|
|
727
|
+
this.sipSessionUnsubscribe = this.sdkClient.subscribeSipSessionState(this.applySipSessionState);
|
|
728
|
+
this.applySipSessionState(this.sdkClient.getSipSessionState());
|
|
729
|
+
if (this.remoteAudio) {
|
|
730
|
+
this.sdkClient.setRemoteAudioElement(this.remoteAudio);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
704
733
|
if (changedProperties.has('apiOrigin')) {
|
|
705
734
|
this.configureSdkEndpoints();
|
|
706
735
|
void this.loadOperatorIdentity();
|
|
@@ -759,7 +788,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
759
788
|
this.teardownWidgetLock();
|
|
760
789
|
this.sipSessionUnsubscribe?.();
|
|
761
790
|
this.sipSessionUnsubscribe = undefined;
|
|
762
|
-
setRemoteAudioElement(null);
|
|
791
|
+
this.sdkClient.setRemoteAudioElement(null);
|
|
763
792
|
if (navigator.mediaDevices) {
|
|
764
793
|
navigator.mediaDevices.removeEventListener('devicechange', this.handleDeviceChange);
|
|
765
794
|
}
|
|
@@ -832,7 +861,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
832
861
|
'X-Call-Source: widget_operator',
|
|
833
862
|
];
|
|
834
863
|
try {
|
|
835
|
-
await placeSipCall({
|
|
864
|
+
await this.sdkClient.placeSipCall({
|
|
836
865
|
server: this.sipServer,
|
|
837
866
|
domain: this.sipUrl,
|
|
838
867
|
username: this.sipUser,
|
|
@@ -851,7 +880,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
851
880
|
}
|
|
852
881
|
async handleHangup() {
|
|
853
882
|
try {
|
|
854
|
-
await hangupSipCall();
|
|
883
|
+
await this.sdkClient.hangupSipCall();
|
|
855
884
|
}
|
|
856
885
|
catch (error) {
|
|
857
886
|
// Best-effort hangup.
|
|
@@ -860,7 +889,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
860
889
|
}
|
|
861
890
|
async handleAccept() {
|
|
862
891
|
try {
|
|
863
|
-
await answerIncomingSipCall();
|
|
892
|
+
await this.sdkClient.answerIncomingSipCall();
|
|
864
893
|
this.incomingCall = false;
|
|
865
894
|
this.setCallState('active');
|
|
866
895
|
this.open = true;
|
|
@@ -872,12 +901,12 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
872
901
|
async handleHold() {
|
|
873
902
|
try {
|
|
874
903
|
if (this.callState === 'incoming') {
|
|
875
|
-
await answerIncomingSipCall();
|
|
904
|
+
await this.sdkClient.answerIncomingSipCall();
|
|
876
905
|
this.setCallState('active');
|
|
877
906
|
return;
|
|
878
907
|
}
|
|
879
908
|
const nextHeld = !this.isHeld;
|
|
880
|
-
await setSipCallHeld(nextHeld);
|
|
909
|
+
await this.sdkClient.setSipCallHeld(nextHeld);
|
|
881
910
|
this.isHeld = nextHeld;
|
|
882
911
|
this.setCallState(nextHeld ? 'held' : 'active');
|
|
883
912
|
}
|
|
@@ -887,7 +916,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
887
916
|
}
|
|
888
917
|
async handleDecline() {
|
|
889
918
|
try {
|
|
890
|
-
await declineIncomingSipCall();
|
|
919
|
+
await this.sdkClient.declineIncomingSipCall();
|
|
891
920
|
}
|
|
892
921
|
catch (error) {
|
|
893
922
|
// Best-effort.
|
|
@@ -897,7 +926,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
897
926
|
}
|
|
898
927
|
async handleMuteToggle() {
|
|
899
928
|
const nextMuted = !this.isMuted;
|
|
900
|
-
await setConferenceMuted(nextMuted);
|
|
929
|
+
await this.sdkClient.setConferenceMuted(nextMuted);
|
|
901
930
|
this.isMuted = nextMuted;
|
|
902
931
|
}
|
|
903
932
|
handleTransfer() {
|
|
@@ -1087,7 +1116,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1087
1116
|
const config = await this.getRpcConfig();
|
|
1088
1117
|
if (!config)
|
|
1089
1118
|
return;
|
|
1090
|
-
const callLookup = await listCalls({
|
|
1119
|
+
const callLookup = await this.sdkClient.listCalls({
|
|
1091
1120
|
fields: ['id', 'callUuid'],
|
|
1092
1121
|
filter: { callUuid: { eq: callUuid } },
|
|
1093
1122
|
page: { limit: 1 },
|
|
@@ -1101,7 +1130,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1101
1130
|
let resolvedCallId = callRows[0]?.id ?? null;
|
|
1102
1131
|
let resolvedCallUuid = callRows[0]?.callUuid ?? null;
|
|
1103
1132
|
if (!resolvedCallId) {
|
|
1104
|
-
const activeCallsLookup = await listCalls({
|
|
1133
|
+
const activeCallsLookup = await this.sdkClient.listCalls({
|
|
1105
1134
|
fields: ['id', 'callUuid', 'status', 'sipUsername', 'startedAt'],
|
|
1106
1135
|
filter: this.sipUser
|
|
1107
1136
|
? {
|
|
@@ -1129,7 +1158,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1129
1158
|
resolvedCallUuid !== this.activeCallUuid) {
|
|
1130
1159
|
this.activeCallUuid = resolvedCallUuid;
|
|
1131
1160
|
}
|
|
1132
|
-
const result = await listCallParticipants(resolvedCallId
|
|
1161
|
+
const result = await this.sdkClient.listCallParticipants(resolvedCallId
|
|
1133
1162
|
? {
|
|
1134
1163
|
fields: ['id', 'memberUuid', 'role', 'joinedAt', 'leftAt'],
|
|
1135
1164
|
filter: { callId: { eq: resolvedCallId } },
|
|
@@ -1192,7 +1221,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1192
1221
|
this.contacts = [];
|
|
1193
1222
|
return;
|
|
1194
1223
|
}
|
|
1195
|
-
const result = await listContacts({
|
|
1224
|
+
const result = await this.sdkClient.listContacts({
|
|
1196
1225
|
fields: ['id', 'fullName', 'phoneE164'],
|
|
1197
1226
|
...config,
|
|
1198
1227
|
});
|
|
@@ -1238,7 +1267,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1238
1267
|
this.history = [];
|
|
1239
1268
|
return;
|
|
1240
1269
|
}
|
|
1241
|
-
const result = await listCalls({
|
|
1270
|
+
const result = await this.sdkClient.listCalls({
|
|
1242
1271
|
fields: ['direction', 'fromNumber', 'toNumber', 'startedAt', 'status'],
|
|
1243
1272
|
...config,
|
|
1244
1273
|
sort: '-startedAt',
|
|
@@ -1272,8 +1301,8 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1272
1301
|
this.setAuthError(AUTH_ERROR_MISSING_TOKEN);
|
|
1273
1302
|
return;
|
|
1274
1303
|
}
|
|
1275
|
-
const baseUrl = this.apiOrigin || DEFAULT_BASE_URL;
|
|
1276
|
-
const realtimeClient = createRealtimeEventsClient({
|
|
1304
|
+
const baseUrl = this.apiOrigin || this.sdkClient.DEFAULT_BASE_URL;
|
|
1305
|
+
const realtimeClient = this.sdkClient.createRealtimeEventsClient({
|
|
1277
1306
|
baseUrl,
|
|
1278
1307
|
getRealtimeToken: () => this.fetchRealtimeSessionToken(),
|
|
1279
1308
|
});
|
|
@@ -1329,7 +1358,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1329
1358
|
this.queueCount = 0;
|
|
1330
1359
|
return;
|
|
1331
1360
|
}
|
|
1332
|
-
const result = await listCallQueueEntries({
|
|
1361
|
+
const result = await this.sdkClient.listCallQueueEntries({
|
|
1333
1362
|
fields: [
|
|
1334
1363
|
'id',
|
|
1335
1364
|
'callerIdName',
|
|
@@ -1367,7 +1396,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1367
1396
|
console.warn('SippetAIVoipWidget: sipUser is required to accept queue entries.');
|
|
1368
1397
|
return;
|
|
1369
1398
|
}
|
|
1370
|
-
const result = await acceptCallQueueEntry({
|
|
1399
|
+
const result = await this.sdkClient.acceptCallQueueEntry({
|
|
1371
1400
|
identity: entryId,
|
|
1372
1401
|
input: {
|
|
1373
1402
|
operatorName: this.sipUser,
|
|
@@ -1386,7 +1415,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1386
1415
|
const config = await this.getRpcConfig();
|
|
1387
1416
|
if (!config)
|
|
1388
1417
|
return undefined;
|
|
1389
|
-
const result = await whoAmI({
|
|
1418
|
+
const result = await this.sdkClient.whoAmI({
|
|
1390
1419
|
fields: ['id', { sipUser: ['id', 'sipUsername'] }],
|
|
1391
1420
|
...config,
|
|
1392
1421
|
});
|
|
@@ -1411,7 +1440,7 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1411
1440
|
return;
|
|
1412
1441
|
if (!['available', 'on_break', 'logged_out'].includes(value))
|
|
1413
1442
|
return;
|
|
1414
|
-
const result = await setOperatorStatus({
|
|
1443
|
+
const result = await this.sdkClient.setOperatorStatus({
|
|
1415
1444
|
input: {
|
|
1416
1445
|
sipUserId,
|
|
1417
1446
|
status: value,
|
|
@@ -1659,6 +1688,9 @@ export class SippetAIVoipWidget extends TwLitElement {
|
|
|
1659
1688
|
`;
|
|
1660
1689
|
}
|
|
1661
1690
|
}
|
|
1691
|
+
__decorate([
|
|
1692
|
+
property({ attribute: false })
|
|
1693
|
+
], SippetAIVoipWidget.prototype, "client", void 0);
|
|
1662
1694
|
__decorate([
|
|
1663
1695
|
property({ type: Boolean, attribute: 'cookie-auth' })
|
|
1664
1696
|
], SippetAIVoipWidget.prototype, "cookieAuth", void 0);
|
|
@@ -1698,6 +1730,9 @@ __decorate([
|
|
|
1698
1730
|
__decorate([
|
|
1699
1731
|
property({ type: Boolean, reflect: true })
|
|
1700
1732
|
], SippetAIVoipWidget.prototype, "open", void 0);
|
|
1733
|
+
__decorate([
|
|
1734
|
+
property({ type: Boolean, attribute: 'open-widget' })
|
|
1735
|
+
], SippetAIVoipWidget.prototype, "openWidget", void 0);
|
|
1701
1736
|
__decorate([
|
|
1702
1737
|
property({ type: String })
|
|
1703
1738
|
], SippetAIVoipWidget.prototype, "activeTab", void 0);
|
package/dist/lib/sippet.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { SippetAIVoipWidgetClient } from '../components/voip-widget/index.js';
|
|
1
2
|
export declare const sippet: {
|
|
3
|
+
setClient(client: SippetAIVoipWidgetClient | null): void;
|
|
2
4
|
setAccessToken(accessToken: string | null): void;
|
|
3
5
|
setCookieAuth(enabled: boolean): void;
|
|
4
6
|
setGetAccessToken(getter: (() => string | Promise<string>) | null): void;
|
package/dist/lib/sippet.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as SippetSdkClientModule from '@sippet-ai/sdk-js/client';
|
|
2
2
|
const WIDGET_SELECTOR = 'sippetai-voip-widget';
|
|
3
|
+
const DEFAULT_SDK_CLIENT = SippetSdkClientModule;
|
|
3
4
|
let configuredAccessToken = null;
|
|
4
5
|
let configuredCookieAuth = false;
|
|
5
6
|
let configuredGetAccessToken = null;
|
|
6
7
|
let configuredApiOrigin = null;
|
|
8
|
+
let configuredClient = null;
|
|
7
9
|
function getWidget() {
|
|
8
10
|
if (typeof document === 'undefined')
|
|
9
11
|
return null;
|
|
10
|
-
|
|
12
|
+
const widget = document.querySelector(WIDGET_SELECTOR);
|
|
13
|
+
if (widget && configuredClient && widget.client !== configuredClient) {
|
|
14
|
+
widget.client = configuredClient;
|
|
15
|
+
}
|
|
16
|
+
return widget;
|
|
11
17
|
}
|
|
12
18
|
function requireWidget() {
|
|
13
19
|
const widget = getWidget();
|
|
@@ -52,6 +58,9 @@ function resolveApiOrigin(widget) {
|
|
|
52
58
|
? apiOrigin
|
|
53
59
|
: null;
|
|
54
60
|
}
|
|
61
|
+
function resolveSdkClient(widget) {
|
|
62
|
+
return configuredClient ?? widget?.client ?? DEFAULT_SDK_CLIENT;
|
|
63
|
+
}
|
|
55
64
|
function configureSdk(apiOrigin) {
|
|
56
65
|
if (!apiOrigin || typeof globalThis === 'undefined')
|
|
57
66
|
return;
|
|
@@ -64,10 +73,11 @@ function configureSdk(apiOrigin) {
|
|
|
64
73
|
}
|
|
65
74
|
async function rpcConfig() {
|
|
66
75
|
const widget = getWidget();
|
|
76
|
+
const sdkClient = resolveSdkClient(widget ?? undefined);
|
|
67
77
|
configureSdk(resolveApiOrigin(widget ?? undefined));
|
|
68
78
|
if (resolveCookieAuth(widget ?? undefined)) {
|
|
69
79
|
return {
|
|
70
|
-
headers: buildCSRFHeaders(),
|
|
80
|
+
headers: sdkClient.buildCSRFHeaders(),
|
|
71
81
|
fetchOptions: { credentials: 'include' },
|
|
72
82
|
};
|
|
73
83
|
}
|
|
@@ -79,6 +89,13 @@ async function rpcConfig() {
|
|
|
79
89
|
};
|
|
80
90
|
}
|
|
81
91
|
export const sippet = {
|
|
92
|
+
setClient(client) {
|
|
93
|
+
configuredClient = client;
|
|
94
|
+
const widget = getWidget();
|
|
95
|
+
if (widget) {
|
|
96
|
+
widget.client = client;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
82
99
|
setAccessToken(accessToken) {
|
|
83
100
|
configuredAccessToken =
|
|
84
101
|
typeof accessToken === 'string' ? accessToken : null;
|
|
@@ -134,8 +151,10 @@ export const sippet = {
|
|
|
134
151
|
return 'not implemented yet';
|
|
135
152
|
},
|
|
136
153
|
async callDetails(callUuid) {
|
|
154
|
+
const widget = getWidget();
|
|
155
|
+
const sdkClient = resolveSdkClient(widget ?? undefined);
|
|
137
156
|
const config = await rpcConfig();
|
|
138
|
-
const result = await listCalls({
|
|
157
|
+
const result = await sdkClient.listCalls({
|
|
139
158
|
fields: [
|
|
140
159
|
'id',
|
|
141
160
|
'callUuid',
|
|
@@ -159,7 +178,7 @@ export const sippet = {
|
|
|
159
178
|
if (!call) {
|
|
160
179
|
return { success: true, data: null };
|
|
161
180
|
}
|
|
162
|
-
const codecResult = await callCodec({
|
|
181
|
+
const codecResult = await sdkClient.callCodec({
|
|
163
182
|
input: { callUuid },
|
|
164
183
|
...config,
|
|
165
184
|
});
|
|
@@ -172,8 +191,10 @@ export const sippet = {
|
|
|
172
191
|
};
|
|
173
192
|
},
|
|
174
193
|
async getQueue() {
|
|
194
|
+
const widget = getWidget();
|
|
195
|
+
const sdkClient = resolveSdkClient(widget ?? undefined);
|
|
175
196
|
const config = await rpcConfig();
|
|
176
|
-
return listCallQueueEntries({
|
|
197
|
+
return sdkClient.listCallQueueEntries({
|
|
177
198
|
fields: [
|
|
178
199
|
'id',
|
|
179
200
|
'callUuid',
|
|
@@ -191,8 +212,10 @@ export const sippet = {
|
|
|
191
212
|
});
|
|
192
213
|
},
|
|
193
214
|
async getActiveCalls() {
|
|
215
|
+
const widget = getWidget();
|
|
216
|
+
const sdkClient = resolveSdkClient(widget ?? undefined);
|
|
194
217
|
const config = await rpcConfig();
|
|
195
|
-
return listCalls({
|
|
218
|
+
return sdkClient.listCalls({
|
|
196
219
|
fields: [
|
|
197
220
|
'id',
|
|
198
221
|
'callUuid',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sippet-ai/operator-widget",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "Sippet AI's operator widget to enable telephony calling features in any web application.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"author": "Sippet AI",
|
|
36
36
|
"license": "UNLICENSED",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@sippet-ai/sdk-js": "^0.0.
|
|
38
|
+
"@sippet-ai/sdk-js": "^0.0.7",
|
|
39
39
|
"code-bubble": "^1.3.3",
|
|
40
40
|
"lit": "^3.2.1",
|
|
41
41
|
"lucide": "^0.562.0",
|
|
@@ -33,6 +33,9 @@ export interface SippetAIVoipWidgetProps extends Pick<
|
|
|
33
33
|
/** undefined */
|
|
34
34
|
open?: boolean;
|
|
35
35
|
|
|
36
|
+
/** undefined */
|
|
37
|
+
openWidget?: boolean;
|
|
38
|
+
|
|
36
39
|
/** undefined */
|
|
37
40
|
accessToken?: SippetAIVoipWidgetElement["accessToken"];
|
|
38
41
|
|
|
@@ -107,7 +110,9 @@ export interface SippetAIVoipWidgetProps extends Pick<
|
|
|
107
110
|
* - `history`: undefined
|
|
108
111
|
* - `queuedCalls`: undefined
|
|
109
112
|
* - `open`: undefined
|
|
113
|
+
* - `open-widget`/`openWidget`: undefined
|
|
110
114
|
* - `activeTab`: undefined
|
|
115
|
+
* - `client`: undefined (property only)
|
|
111
116
|
* - `getAccessToken`: undefined (property only)
|
|
112
117
|
*
|
|
113
118
|
* ## Events
|
|
@@ -9,6 +9,7 @@ export const SippetAIVoipWidget = forwardRef((props, forwardedRef) => {
|
|
|
9
9
|
incomingCall,
|
|
10
10
|
incomingFromQueue,
|
|
11
11
|
open,
|
|
12
|
+
openWidget,
|
|
12
13
|
accessToken,
|
|
13
14
|
apiOrigin,
|
|
14
15
|
availability,
|
|
@@ -51,6 +52,7 @@ export const SippetAIVoipWidget = forwardRef((props, forwardedRef) => {
|
|
|
51
52
|
incomingCall: incomingCall ? true : undefined,
|
|
52
53
|
incomingFromQueue: incomingFromQueue ? true : undefined,
|
|
53
54
|
open: open ? true : undefined,
|
|
55
|
+
"open-widget": openWidget ? true : undefined,
|
|
54
56
|
style: { ...props.style },
|
|
55
57
|
},
|
|
56
58
|
props.children,
|
|
@@ -377,8 +377,14 @@ export type SippetAIVoipWidgetProps = {
|
|
|
377
377
|
/** */
|
|
378
378
|
open?: SippetAIVoipWidget["open"];
|
|
379
379
|
/** */
|
|
380
|
+
"open-widget"?: SippetAIVoipWidget["openWidget"];
|
|
381
|
+
/** */
|
|
382
|
+
openWidget?: SippetAIVoipWidget["openWidget"];
|
|
383
|
+
/** */
|
|
380
384
|
activeTab?: SippetAIVoipWidget["activeTab"];
|
|
381
385
|
/** */
|
|
386
|
+
client?: SippetAIVoipWidget["client"];
|
|
387
|
+
/** */
|
|
382
388
|
getAccessToken?: SippetAIVoipWidget["getAccessToken"];
|
|
383
389
|
|
|
384
390
|
/** */
|
|
@@ -419,8 +425,14 @@ export type SippetAIVoipWidgetSolidJsProps = {
|
|
|
419
425
|
/** */
|
|
420
426
|
"prop:open"?: SippetAIVoipWidget["open"];
|
|
421
427
|
/** */
|
|
428
|
+
"bool:open-widget"?: SippetAIVoipWidget["openWidget"];
|
|
429
|
+
/** */
|
|
430
|
+
"prop:openWidget"?: SippetAIVoipWidget["openWidget"];
|
|
431
|
+
/** */
|
|
422
432
|
"prop:activeTab"?: SippetAIVoipWidget["activeTab"];
|
|
423
433
|
/** */
|
|
434
|
+
"prop:client"?: SippetAIVoipWidget["client"];
|
|
435
|
+
/** */
|
|
424
436
|
"prop:getAccessToken"?: SippetAIVoipWidget["getAccessToken"];
|
|
425
437
|
/** */
|
|
426
438
|
"on:voip-transfer"?: (e: SippetAIVoipWidgetElementEvent) => void;
|
|
@@ -614,7 +626,9 @@ export type CustomElements = {
|
|
|
614
626
|
* - `history`: undefined
|
|
615
627
|
* - `queuedCalls`: undefined
|
|
616
628
|
* - `open`: undefined
|
|
629
|
+
* - `open-widget`/`openWidget`: undefined
|
|
617
630
|
* - `activeTab`: undefined
|
|
631
|
+
* - `client`: undefined (property only)
|
|
618
632
|
* - `getAccessToken`: undefined (property only)
|
|
619
633
|
*
|
|
620
634
|
* ## Events
|
|
@@ -828,7 +842,9 @@ export type CustomElementsSolidJs = {
|
|
|
828
842
|
* - `history`: undefined
|
|
829
843
|
* - `queuedCalls`: undefined
|
|
830
844
|
* - `open`: undefined
|
|
845
|
+
* - `open-widget`/`openWidget`: undefined
|
|
831
846
|
* - `activeTab`: undefined
|
|
847
|
+
* - `client`: undefined (property only)
|
|
832
848
|
* - `getAccessToken`: undefined (property only)
|
|
833
849
|
*
|
|
834
850
|
* ## Events
|
|
@@ -156,8 +156,12 @@ type SippetAIVoipWidgetProps = {
|
|
|
156
156
|
/** */
|
|
157
157
|
open?: boolean;
|
|
158
158
|
/** */
|
|
159
|
+
"open-widget"?: boolean;
|
|
160
|
+
/** */
|
|
159
161
|
activeTab?: VoipTab;
|
|
160
162
|
/** */
|
|
163
|
+
"bind:client"?: SippetAIVoipWidgetClient | null;
|
|
164
|
+
/** */
|
|
161
165
|
"bind:getAccessToken"?: (() => string | Promise<string>) | null | undefined;
|
|
162
166
|
/** */
|
|
163
167
|
"on:voip-transfer"?: (e: CustomEvent<CustomEvent>) => void;
|
|
@@ -119,8 +119,12 @@ type SippetAIVoipWidgetProps = {
|
|
|
119
119
|
/** */
|
|
120
120
|
open?: boolean;
|
|
121
121
|
/** */
|
|
122
|
+
"open-widget"?: boolean;
|
|
123
|
+
/** */
|
|
122
124
|
activeTab?: VoipTab;
|
|
123
125
|
/** */
|
|
126
|
+
client?: SippetAIVoipWidgetClient | null;
|
|
127
|
+
/** */
|
|
124
128
|
getAccessToken?: (() => string | Promise<string>) | null | undefined;
|
|
125
129
|
/** */
|
|
126
130
|
"onvoip-transfer"?: (e: CustomEvent<CustomEvent>) => void;
|