@sippet-ai/operator-widget 0.0.14 → 0.0.15
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 +93 -92
- package/custom-elements.json +131 -180
- package/dist/components/voip-widget/voip-widget-settings-tab.d.ts +0 -1
- package/dist/components/voip-widget/voip-widget-settings-tab.js +0 -16
- package/dist/components/voip-widget/voip-widget.d.ts +23 -18
- package/dist/components/voip-widget/voip-widget.js +432 -279
- package/dist/lib/realtime.d.ts +1 -1
- package/dist/lib/realtime.js +1 -1
- package/dist/lib/sippet.d.ts +3 -2
- package/dist/lib/sippet.js +47 -31
- package/dist/styles/tailwind.global.css +1 -1
- package/dist/styles/tailwind.global.css.js +1 -1
- package/package.json +2 -2
- package/react/SippetAIVoipWidget.d.ts +5 -32
- package/react/SippetAIVoipWidget.js +4 -18
- package/react/SippetAIVoipWidgetSettingsTab.d.ts +0 -4
- package/react/SippetAIVoipWidgetSettingsTab.js +0 -2
- package/types/custom-element-jsx.d.ts +18 -64
- package/types/custom-element-svelte.d.ts +4 -19
- package/types/custom-element-vuejs.d.ts +4 -19
package/README.md
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
# Sippet AI Operator Widget
|
|
2
2
|
|
|
3
|
-
A web component (with React wrappers) for embedding Sippet AI telephony controls
|
|
4
|
-
It provides a floating softphone UI, SIP/WebRTC call controls, queue handling, and light helpers
|
|
5
|
-
built on `@sippet-ai/sdk-js`.
|
|
6
|
-
|
|
7
|
-
## What it does
|
|
8
|
-
|
|
9
|
-
- Renders a floating VoIP widget with phone, queue, contacts, history, and settings tabs.
|
|
10
|
-
- Connects to SIP and WebRTC (mic/speaker selection and permissions).
|
|
11
|
-
- Listens to queue entries and call history.
|
|
12
|
-
- Exposes a small JS API (`sippet`) to trigger calls and query queues/history.
|
|
3
|
+
A web component (with React wrappers) for embedding Sippet AI operator telephony controls.
|
|
13
4
|
|
|
14
5
|
## Install
|
|
15
6
|
|
|
@@ -17,9 +8,64 @@ built on `@sippet-ai/sdk-js`.
|
|
|
17
8
|
npm install @sippet-ai/operator-widget
|
|
18
9
|
```
|
|
19
10
|
|
|
20
|
-
|
|
11
|
+
## Auth flow
|
|
12
|
+
|
|
13
|
+
1. Ensure your operator exists in Sippet's 'Team members' section in the settings
|
|
14
|
+
2. Operator logs in to your frontend.
|
|
15
|
+
3. Your frontend calls your backend (never call Sippet mint endpoint directly from browser).
|
|
16
|
+
4. Your backend validates the operator session and extracts the user's email.
|
|
17
|
+
5. Your backend mints the operator token using one of these methods:
|
|
18
|
+
- SDK server RPC call (recommended): `issueOperatorAccessToken` via `createServerClient` from `@sippet-ai/sdk-js/server`
|
|
19
|
+
- REST endpoint: `POST /api/operator/access`
|
|
20
|
+
6. Sippet finds the operator by email in the workspace tied to that secret key and returns an access token.
|
|
21
|
+
7. Your backend returns that token to frontend.
|
|
22
|
+
8. Frontend passes token to widget via `access-token` or `getAccessToken`.
|
|
23
|
+
|
|
24
|
+
## Minting options on your backend
|
|
25
|
+
|
|
26
|
+
### Option A: SDK server RPC call (recommended)
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { createServerClient } from '@sippet-ai/sdk-js/server';
|
|
30
|
+
|
|
31
|
+
const sippet = createServerClient({
|
|
32
|
+
apiKey: process.env.SIPPET_SECRET_API_KEY!,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const result = await sippet.issueOperatorAccessToken({
|
|
36
|
+
input: { operatorEmail: operator.email },
|
|
37
|
+
});
|
|
21
38
|
|
|
22
|
-
|
|
39
|
+
if (!result.success) {
|
|
40
|
+
throw new Error(result.errors.map(error => error.message).join(', '));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return result.data.token;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Option B: Raw REST endpoint
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const response = await fetch('https://api.sippet.ai/api/operator/access', {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: {
|
|
52
|
+
'content-type': 'application/json',
|
|
53
|
+
'x-api-key': process.env.SIPPET_SECRET_API_KEY!,
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({ operator_email: operator.email }),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (!response.ok) throw new Error('Failed to mint operator access token');
|
|
59
|
+
const body = await response.json();
|
|
60
|
+
return body.token;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Important requirement: operator email must exist in Sippet
|
|
64
|
+
|
|
65
|
+
The `operator_email` must map to an existing invited/created user in your Sippet workspace (team members).
|
|
66
|
+
If the email is not present in that workspace, token minting fails.
|
|
67
|
+
|
|
68
|
+
## Quick start (Web Component, token auth)
|
|
23
69
|
|
|
24
70
|
```html
|
|
25
71
|
<script type="module">
|
|
@@ -27,19 +73,12 @@ npm install @sippet-ai/operator-widget
|
|
|
27
73
|
</script>
|
|
28
74
|
|
|
29
75
|
<sippetai-voip-widget
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
sip-user="1001"
|
|
33
|
-
sip-password="1234"
|
|
34
|
-
sip-web-socket-url="wss://sip.sippet.ai:7443"
|
|
35
|
-
user-name="Agent"
|
|
36
|
-
user-email="agent@example.com"
|
|
76
|
+
access-token="YOUR_OPERATOR_ACCESS_TOKEN"
|
|
77
|
+
api-origin="https://api.sippet.ai"
|
|
37
78
|
></sippetai-voip-widget>
|
|
38
79
|
```
|
|
39
80
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
## React usage
|
|
81
|
+
## React usage (token auth)
|
|
43
82
|
|
|
44
83
|
```tsx
|
|
45
84
|
import { SippetAIVoipWidget } from '@sippet-ai/operator-widget/react';
|
|
@@ -47,89 +86,51 @@ import { SippetAIVoipWidget } from '@sippet-ai/operator-widget/react';
|
|
|
47
86
|
export function SupportWidget() {
|
|
48
87
|
return (
|
|
49
88
|
<SippetAIVoipWidget
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
sipUser="1001"
|
|
53
|
-
sipPassword="1234"
|
|
54
|
-
sipWebSocketUrl="wss://sip.sippet.ai:7443"
|
|
55
|
-
userName="Agent"
|
|
56
|
-
userEmail="agent@example.com"
|
|
89
|
+
accessToken="YOUR_OPERATOR_ACCESS_TOKEN"
|
|
90
|
+
apiOrigin="https://api.sippet.ai"
|
|
57
91
|
/>
|
|
58
92
|
);
|
|
59
93
|
}
|
|
60
94
|
```
|
|
61
95
|
|
|
62
|
-
##
|
|
63
|
-
|
|
64
|
-
- `api-key` (attribute) / `apiKey` (property). Required for contacts, history, queue polling, and realtime events.
|
|
65
|
-
- `api-origin` (attribute) / `apiOrigin` (property). Optional override for a self-hosted or local API origin.
|
|
66
|
-
- `sip-url`, `sip-user`, `sip-password`, `sip-web-socket-url`. Required for SIP calling.
|
|
67
|
-
- `user-name`, `user-email`. Displayed in the widget.
|
|
68
|
-
|
|
69
|
-
## Methods & events
|
|
70
|
-
|
|
71
|
-
Methods are available on the DOM element instance via the `sippet` helper.
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
import { sippet } from '@sippet-ai/operator-widget';
|
|
75
|
-
|
|
76
|
-
sippet.setApiKey('YOUR_PUBLISHABLE_API_KEY');
|
|
77
|
-
sippet.setApiOrigin('https://api.sippet.ai');
|
|
78
|
-
|
|
79
|
-
await sippet.call('+15551234567');
|
|
80
|
-
await sippet.answer();
|
|
81
|
-
await sippet.decline();
|
|
82
|
-
await sippet.hold();
|
|
83
|
-
|
|
84
|
-
const queue = await sippet.getQueue();
|
|
85
|
-
const activeCalls = await sippet.getActiveCalls();
|
|
86
|
-
const callDetails = await sippet.callDetails('CALL_UUID');
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
If the widget element already has `api-key`, you can omit `sippet.setApiKey`.
|
|
96
|
+
## Token rotation with backend endpoint
|
|
90
97
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
```ts
|
|
94
|
-
import { initSocket, joinEventsChannel } from '@sippet-ai/operator-widget';
|
|
95
|
-
|
|
96
|
-
initSocket({ publishableKey: 'YOUR_PUBLISHABLE_API_KEY' });
|
|
97
|
-
|
|
98
|
-
const channel = joinEventsChannel();
|
|
98
|
+
```tsx
|
|
99
|
+
import { SippetAIVoipWidget } from '@sippet-ai/operator-widget/react';
|
|
99
100
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
export function SupportWidget() {
|
|
102
|
+
return (
|
|
103
|
+
<SippetAIVoipWidget
|
|
104
|
+
apiOrigin="https://api.sippet.ai"
|
|
105
|
+
getAccessToken={async () => {
|
|
106
|
+
const response = await fetch('/api/your-backend/operator-token', {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
});
|
|
109
|
+
if (!response.ok) throw new Error('Failed to mint operator token');
|
|
110
|
+
const body = await response.json();
|
|
111
|
+
return body.token;
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
103
116
|
```
|
|
104
117
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
- `incoming_call`
|
|
108
|
-
- `call_answered`
|
|
109
|
-
- `call_ended`
|
|
110
|
-
- `operator_status_change`
|
|
111
|
-
- `call_queue_entry_updated`
|
|
112
|
-
- `call_queue_entry_deleted`
|
|
113
|
-
- `call_participant_joined`
|
|
114
|
-
- `call_participant_left`
|
|
115
|
-
- `call_transcript_delta`
|
|
116
|
-
- `call_transcript_completed`
|
|
117
|
-
|
|
118
|
-
## Permissions and runtime behavior
|
|
119
|
-
|
|
120
|
-
- Microphone access is required for calling; the widget prompts for audio permissions when opened.
|
|
121
|
-
- Speaker selection uses `setSinkId` when supported by the browser; some browsers require a user gesture.
|
|
122
|
-
- Queue entries are refreshed on realtime socket events and when the queue tab is opened (no polling loop).
|
|
118
|
+
## Configuration
|
|
123
119
|
|
|
124
|
-
|
|
120
|
+
- `access-token` / `accessToken`: operator bearer token.
|
|
121
|
+
- `getAccessToken` (property only): async token resolver.
|
|
122
|
+
- `api-origin` / `apiOrigin`: API origin override.
|
|
125
123
|
|
|
126
|
-
|
|
124
|
+
## Helper API
|
|
127
125
|
|
|
128
126
|
```ts
|
|
129
|
-
import {
|
|
127
|
+
import { sippet } from '@sippet-ai/operator-widget';
|
|
130
128
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
sippet.setGetAccessToken(async () => {
|
|
130
|
+
const response = await fetch('/api/your-backend/operator-token', {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
});
|
|
133
|
+
const body = await response.json();
|
|
134
|
+
return body.token;
|
|
134
135
|
});
|
|
135
136
|
```
|