@sippet-ai/operator-widget 0.0.12
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/LICENSE +2 -0
- package/README.md +136 -0
- package/cdn/loader.js +146 -0
- package/custom-elements.json +2241 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/voip-widget/index.d.ts +18 -0
- package/dist/components/voip-widget/index.js +4 -0
- package/dist/components/voip-widget/voip-widget-contacts-tab.d.ts +14 -0
- package/dist/components/voip-widget/voip-widget-contacts-tab.js +45 -0
- package/dist/components/voip-widget/voip-widget-history-tab.d.ts +13 -0
- package/dist/components/voip-widget/voip-widget-history-tab.js +43 -0
- package/dist/components/voip-widget/voip-widget-launcher.d.ts +18 -0
- package/dist/components/voip-widget/voip-widget-launcher.js +100 -0
- package/dist/components/voip-widget/voip-widget-panel.d.ts +21 -0
- package/dist/components/voip-widget/voip-widget-panel.js +193 -0
- package/dist/components/voip-widget/voip-widget-phone-tab.d.ts +21 -0
- package/dist/components/voip-widget/voip-widget-phone-tab.js +187 -0
- package/dist/components/voip-widget/voip-widget-queue-tab.d.ts +14 -0
- package/dist/components/voip-widget/voip-widget-queue-tab.js +49 -0
- package/dist/components/voip-widget/voip-widget-settings-tab.d.ts +21 -0
- package/dist/components/voip-widget/voip-widget-settings-tab.js +135 -0
- package/dist/components/voip-widget/voip-widget.d.ts +142 -0
- package/dist/components/voip-widget/voip-widget.js +1329 -0
- package/dist/components/voip-widget/voip-widget.types.d.ts +22 -0
- package/dist/components/voip-widget/voip-widget.types.js +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/lib/realtime.d.ts +1 -0
- package/dist/lib/realtime.js +1 -0
- package/dist/lib/sippet.d.ts +40 -0
- package/dist/lib/sippet.js +197 -0
- package/dist/lib/tailwindMixin.d.ts +6 -0
- package/dist/lib/tailwindMixin.js +24 -0
- package/dist/styles/tailwind.global.css +2 -0
- package/dist/styles/tailwind.global.css.js +1 -0
- package/package.json +126 -0
- package/react/SippetAIVoipWidget.d.ts +158 -0
- package/react/SippetAIVoipWidget.js +72 -0
- package/react/SippetAIVoipWidgetContactsTab.d.ts +67 -0
- package/react/SippetAIVoipWidgetContactsTab.js +29 -0
- package/react/SippetAIVoipWidgetHistoryTab.d.ts +55 -0
- package/react/SippetAIVoipWidgetHistoryTab.js +26 -0
- package/react/SippetAIVoipWidgetLauncher.d.ts +83 -0
- package/react/SippetAIVoipWidgetLauncher.js +41 -0
- package/react/SippetAIVoipWidgetPanel.d.ts +87 -0
- package/react/SippetAIVoipWidgetPanel.js +43 -0
- package/react/SippetAIVoipWidgetPhoneTab.d.ts +87 -0
- package/react/SippetAIVoipWidgetPhoneTab.js +43 -0
- package/react/SippetAIVoipWidgetQueueTab.d.ts +67 -0
- package/react/SippetAIVoipWidgetQueueTab.js +27 -0
- package/react/SippetAIVoipWidgetSettingsTab.d.ts +91 -0
- package/react/SippetAIVoipWidgetSettingsTab.js +47 -0
- package/react/index.d.ts +8 -0
- package/react/index.js +8 -0
- package/react/react-utils.js +67 -0
- package/types/custom-element-jsx.d.ts +956 -0
- package/types/custom-element-svelte.d.ts +264 -0
- package/types/custom-element-vuejs.d.ts +234 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Sippet AI Operator Widget
|
|
2
|
+
|
|
3
|
+
A web component (with React wrappers) for embedding Sippet AI telephony controls in any app.
|
|
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.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @sippet-ai/operator-widget
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`@sippet-ai/sdk-js` is a dependency of the widget, so it will be installed automatically.
|
|
21
|
+
|
|
22
|
+
## Quick start (Web Component)
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<script type="module">
|
|
26
|
+
import '@sippet-ai/operator-widget';
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<sippetai-voip-widget
|
|
30
|
+
api-key="YOUR_PUBLISHABLE_API_KEY"
|
|
31
|
+
sip-url="sip.sippet.ai"
|
|
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"
|
|
37
|
+
></sippetai-voip-widget>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The widget renders a launcher button at the bottom-right of the page. Clicking it opens the panel.
|
|
41
|
+
|
|
42
|
+
## React usage
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { SippetAIVoipWidget } from '@sippet-ai/operator-widget/react';
|
|
46
|
+
|
|
47
|
+
export function SupportWidget() {
|
|
48
|
+
return (
|
|
49
|
+
<SippetAIVoipWidget
|
|
50
|
+
apiKey="YOUR_PUBLISHABLE_API_KEY"
|
|
51
|
+
sipUrl="sip.sippet.ai"
|
|
52
|
+
sipUser="1001"
|
|
53
|
+
sipPassword="1234"
|
|
54
|
+
sipWebSocketUrl="wss://sip.sippet.ai:7443"
|
|
55
|
+
userName="Agent"
|
|
56
|
+
userEmail="agent@example.com"
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Configuration
|
|
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`.
|
|
90
|
+
|
|
91
|
+
## Realtime events
|
|
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();
|
|
99
|
+
|
|
100
|
+
channel.on('incoming_call', payload => {
|
|
101
|
+
console.log('incoming_call', payload);
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Known event names:
|
|
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).
|
|
123
|
+
|
|
124
|
+
## Using `@sippet-ai/sdk-js` directly
|
|
125
|
+
|
|
126
|
+
If you need RPC calls outside the widget, use the SDK client directly:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import { createClient } from '@sippet-ai/sdk-js';
|
|
130
|
+
|
|
131
|
+
const client = createClient({ apiKey: 'YOUR_PUBLISHABLE_API_KEY' });
|
|
132
|
+
|
|
133
|
+
const calls = await client.listCalls({
|
|
134
|
+
fields: ['id', 'callUuid', 'status'],
|
|
135
|
+
});
|
|
136
|
+
```
|
package/cdn/loader.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
|
|
2
|
+
let observer;
|
|
3
|
+
let components = {
|
|
4
|
+
"sippetai-voip-widget-launcher": {
|
|
5
|
+
"importPath": "../dist/components/voip-widget/voip-widget-launcher.js",
|
|
6
|
+
"dependencies": []
|
|
7
|
+
},
|
|
8
|
+
"sippetai-voip-widget-panel": {
|
|
9
|
+
"importPath": "../dist/components/voip-widget/voip-widget-panel.js",
|
|
10
|
+
"dependencies": []
|
|
11
|
+
},
|
|
12
|
+
"sippetai-voip-widget-phone-tab": {
|
|
13
|
+
"importPath": "../dist/components/voip-widget/voip-widget-phone-tab.js",
|
|
14
|
+
"dependencies": []
|
|
15
|
+
},
|
|
16
|
+
"sippetai-voip-widget-queue-tab": {
|
|
17
|
+
"importPath": "../dist/components/voip-widget/voip-widget-queue-tab.js",
|
|
18
|
+
"dependencies": []
|
|
19
|
+
},
|
|
20
|
+
"sippetai-voip-widget-contacts-tab": {
|
|
21
|
+
"importPath": "../dist/components/voip-widget/voip-widget-contacts-tab.js",
|
|
22
|
+
"dependencies": []
|
|
23
|
+
},
|
|
24
|
+
"sippetai-voip-widget-history-tab": {
|
|
25
|
+
"importPath": "../dist/components/voip-widget/voip-widget-history-tab.js",
|
|
26
|
+
"dependencies": []
|
|
27
|
+
},
|
|
28
|
+
"sippetai-voip-widget-settings-tab": {
|
|
29
|
+
"importPath": "../dist/components/voip-widget/voip-widget-settings-tab.js",
|
|
30
|
+
"dependencies": []
|
|
31
|
+
},
|
|
32
|
+
"sippetai-voip-widget": {
|
|
33
|
+
"importPath": "../dist/components/voip-widget/voip-widget.js",
|
|
34
|
+
"dependencies": []
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const eagerLoad = [];
|
|
38
|
+
|
|
39
|
+
/** Update the lazy-loader configuration at runtime */
|
|
40
|
+
export async function updateConfig(config) {
|
|
41
|
+
if (config.components) {
|
|
42
|
+
components = { ...components, ...config.components };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if(config.prefix || config.suffix) {
|
|
46
|
+
components = getScopedComponents(config.prefix, config.suffix);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (config.rootElement) {
|
|
50
|
+
if (observer) {
|
|
51
|
+
observer.disconnect();
|
|
52
|
+
}
|
|
53
|
+
start(config.rootElement);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (config.eagerLoad) {
|
|
57
|
+
await Promise.allSettled(eagerLoad?.map((tagName) => register(tagName)));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getScopedComponents(prefix = "", suffix = "") {
|
|
62
|
+
const scopedComponents = {};
|
|
63
|
+
for (const [key, value] of Object.entries(components)) {
|
|
64
|
+
const newKey = prefix + key + suffix;
|
|
65
|
+
scopedComponents[newKey] = value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return scopedComponents;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Load any undefined custom elements and load the components in the list */
|
|
72
|
+
async function load(root) {
|
|
73
|
+
const rootTagName = root instanceof Element ? root.tagName.toLowerCase() : "";
|
|
74
|
+
const tags = [...root.querySelectorAll(":not(:defined)")]?.map((el) =>
|
|
75
|
+
el.tagName.toLowerCase()
|
|
76
|
+
) || [];
|
|
77
|
+
if (rootTagName.includes("-") && !customElements.get(rootTagName)) {
|
|
78
|
+
tags.push(rootTagName);
|
|
79
|
+
}
|
|
80
|
+
const tagsToRegister = [...new Set(tags)];
|
|
81
|
+
await Promise.allSettled(tagsToRegister?.map((tagName) => register(tagName)));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Register the component and any dependencies */
|
|
85
|
+
function register(tagName) {
|
|
86
|
+
const component = components[tagName];
|
|
87
|
+
|
|
88
|
+
if (customElements.get(tagName)) {
|
|
89
|
+
|
|
90
|
+
cleanUp(component, tagName);
|
|
91
|
+
return Promise.resolve();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!component) {
|
|
95
|
+
|
|
96
|
+
return Promise.resolve();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
import(component.importPath)
|
|
101
|
+
.then(() => {
|
|
102
|
+
|
|
103
|
+
cleanUp(component, tagName);
|
|
104
|
+
resolve();
|
|
105
|
+
})
|
|
106
|
+
.catch(() => {
|
|
107
|
+
console.error(`Unable to load <${tagName}> from ${component.importPath}`);
|
|
108
|
+
reject();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Remove the component from the list of components to load */
|
|
114
|
+
function cleanUp(component, tagName) {
|
|
115
|
+
delete components[tagName];
|
|
116
|
+
component.dependencies?.forEach((dependency) => {
|
|
117
|
+
delete components[dependency];
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (!Object.keys(component).length) {
|
|
121
|
+
observer.disconnect();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Initialize the loader */
|
|
126
|
+
async function start(root = document.body) {
|
|
127
|
+
|
|
128
|
+
// Eager load any components that are not defined in the Custom Elements Manifest
|
|
129
|
+
await Promise.allSettled(eagerLoad?.map((tagName) => register(tagName)));
|
|
130
|
+
|
|
131
|
+
// Watch for any new elements that are added to the DOM
|
|
132
|
+
observer = new MutationObserver((mutations) => {
|
|
133
|
+
for (const { addedNodes } of mutations) {
|
|
134
|
+
for (const node of addedNodes) {
|
|
135
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
136
|
+
load(node);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
load(root);
|
|
143
|
+
observer.observe(root, { subtree: true, childList: true });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
start();
|