@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 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',
@@ -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 { answerIncomingSipCall, acceptCallQueueEntry, buildCSRFHeaders, connectSipSession, createRealtimeEventsClient, declineIncomingSipCall, DEFAULT_BASE_URL, disconnectSipSession, getSipSessionState, hangupSipCall, issueOperatorSipAccess, listCallParticipants, listCallQueueEntries, listCalls, listContacts, placeSipCall, setConferenceMuted, setOutputDevice, setOperatorStatus, setRemoteAudioElement, setSipCallHeld, subscribeSipSessionState, whoAmI, } from '@sippet-ai/sdk-js/client';
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({ 'content-type': 'application/json' }),
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);
@@ -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;
@@ -1,13 +1,19 @@
1
- import { buildCSRFHeaders, callCodec, listCallQueueEntries, listCalls, } from '@sippet-ai/sdk-js/client';
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
- return document.querySelector(WIDGET_SELECTOR);
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.15",
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.6",
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;