@thunderphone/widget 0.1.0
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/dist/index.css +112 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +270 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +243 -0
- package/dist/index.mjs.map +1 -0
- package/dist/mount.css +112 -0
- package/dist/mount.css.map +1 -0
- package/dist/mount.global.js +57719 -0
- package/dist/mount.global.js.map +1 -0
- package/package.json +38 -0
package/dist/index.css
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* src/style.css */
|
|
2
|
+
.tp-widget {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: 12px;
|
|
6
|
+
font-family:
|
|
7
|
+
-apple-system,
|
|
8
|
+
BlinkMacSystemFont,
|
|
9
|
+
"Segoe UI",
|
|
10
|
+
Roboto,
|
|
11
|
+
sans-serif;
|
|
12
|
+
}
|
|
13
|
+
.tp-status {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
gap: 2px;
|
|
17
|
+
}
|
|
18
|
+
.tp-status__name {
|
|
19
|
+
font-size: 14px;
|
|
20
|
+
font-weight: 500;
|
|
21
|
+
color: #18181b;
|
|
22
|
+
}
|
|
23
|
+
.tp-status__text {
|
|
24
|
+
font-size: 12px;
|
|
25
|
+
color: #71717a;
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
gap: 6px;
|
|
29
|
+
}
|
|
30
|
+
.tp-status--connected {
|
|
31
|
+
color: #059669;
|
|
32
|
+
}
|
|
33
|
+
.tp-status--error {
|
|
34
|
+
color: #dc2626;
|
|
35
|
+
}
|
|
36
|
+
.tp-status__dot {
|
|
37
|
+
width: 6px;
|
|
38
|
+
height: 6px;
|
|
39
|
+
border-radius: 50%;
|
|
40
|
+
background: #059669;
|
|
41
|
+
animation: tp-pulse 2s ease-in-out infinite;
|
|
42
|
+
}
|
|
43
|
+
.tp-icon {
|
|
44
|
+
width: 20px;
|
|
45
|
+
height: 20px;
|
|
46
|
+
}
|
|
47
|
+
.tp-button-group {
|
|
48
|
+
display: inline-flex;
|
|
49
|
+
gap: 8px;
|
|
50
|
+
}
|
|
51
|
+
.tp-button {
|
|
52
|
+
display: inline-flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
width: 44px;
|
|
56
|
+
height: 44px;
|
|
57
|
+
border-radius: 50%;
|
|
58
|
+
border: none;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
transition: background-color 0.15s, transform 0.1s;
|
|
61
|
+
}
|
|
62
|
+
.tp-button:active {
|
|
63
|
+
transform: scale(0.95);
|
|
64
|
+
}
|
|
65
|
+
.tp-button--start {
|
|
66
|
+
background: #18181b;
|
|
67
|
+
color: white;
|
|
68
|
+
}
|
|
69
|
+
.tp-button--start:hover {
|
|
70
|
+
background: #27272a;
|
|
71
|
+
}
|
|
72
|
+
.tp-button--start:disabled {
|
|
73
|
+
opacity: 0.5;
|
|
74
|
+
cursor: not-allowed;
|
|
75
|
+
}
|
|
76
|
+
.tp-button--mute {
|
|
77
|
+
background: #f4f4f5;
|
|
78
|
+
color: #18181b;
|
|
79
|
+
}
|
|
80
|
+
.tp-button--mute:hover {
|
|
81
|
+
background: #e4e4e7;
|
|
82
|
+
}
|
|
83
|
+
.tp-button--end {
|
|
84
|
+
background: #dc2626;
|
|
85
|
+
color: white;
|
|
86
|
+
}
|
|
87
|
+
.tp-button--end:hover {
|
|
88
|
+
background: #b91c1c;
|
|
89
|
+
}
|
|
90
|
+
.tp-button--loading {
|
|
91
|
+
opacity: 0.7;
|
|
92
|
+
}
|
|
93
|
+
.tp-spin {
|
|
94
|
+
animation: tp-spin 1s linear infinite;
|
|
95
|
+
}
|
|
96
|
+
@keyframes tp-spin {
|
|
97
|
+
from {
|
|
98
|
+
transform: rotate(0deg);
|
|
99
|
+
}
|
|
100
|
+
to {
|
|
101
|
+
transform: rotate(360deg);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
@keyframes tp-pulse {
|
|
105
|
+
0%, 100% {
|
|
106
|
+
opacity: 1;
|
|
107
|
+
}
|
|
108
|
+
50% {
|
|
109
|
+
opacity: 0.5;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/style.css"],"sourcesContent":[".tp-widget {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n.tp-status {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.tp-status__name {\n font-size: 14px;\n font-weight: 500;\n color: #18181b;\n}\n\n.tp-status__text {\n font-size: 12px;\n color: #71717a;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.tp-status--connected {\n color: #059669;\n}\n\n.tp-status--error {\n color: #dc2626;\n}\n\n.tp-status__dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: #059669;\n animation: tp-pulse 2s ease-in-out infinite;\n}\n\n.tp-icon {\n width: 20px;\n height: 20px;\n}\n\n.tp-button-group {\n display: inline-flex;\n gap: 8px;\n}\n\n.tp-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n border-radius: 50%;\n border: none;\n cursor: pointer;\n transition: background-color 0.15s, transform 0.1s;\n}\n\n.tp-button:active {\n transform: scale(0.95);\n}\n\n.tp-button--start {\n background: #18181b;\n color: white;\n}\n\n.tp-button--start:hover {\n background: #27272a;\n}\n\n.tp-button--start:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.tp-button--mute {\n background: #f4f4f5;\n color: #18181b;\n}\n\n.tp-button--mute:hover {\n background: #e4e4e7;\n}\n\n.tp-button--end {\n background: #dc2626;\n color: white;\n}\n\n.tp-button--end:hover {\n background: #b91c1c;\n}\n\n.tp-button--loading {\n opacity: 0.7;\n}\n\n.tp-spin {\n animation: tp-spin 1s linear infinite;\n}\n\n@keyframes tp-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n@keyframes tp-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n"],"mappings":";AAAA,CAAC;AACC,WAAS;AACT,eAAa;AACb,OAAK;AACL;AAAA,IAAa,aAAa;AAAA,IAAE,kBAAkB;AAAA,IAAE,UAAU;AAAA,IAAE,MAAM;AAAA,IAAE;AACtE;AAEA,CAAC;AACC,WAAS;AACT,kBAAgB;AAChB,OAAK;AACP;AAEA,CAAC;AACC,aAAW;AACX,eAAa;AACb,SAAO;AACT;AAEA,CAAC;AACC,aAAW;AACX,SAAO;AACP,WAAS;AACT,eAAa;AACb,OAAK;AACP;AAEA,CAAC;AACC,SAAO;AACT;AAEA,CAAC;AACC,SAAO;AACT;AAEA,CAAC;AACC,SAAO;AACP,UAAQ;AACR,iBAAe;AACf,cAAY;AACZ,aAAW,SAAS,GAAG,YAAY;AACrC;AAEA,CAAC;AACC,SAAO;AACP,UAAQ;AACV;AAEA,CAAC;AACC,WAAS;AACT,OAAK;AACP;AAEA,CAAC;AACC,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,SAAO;AACP,UAAQ;AACR,iBAAe;AACf,UAAQ;AACR,UAAQ;AACR,cAAY,iBAAiB,KAAK,EAAE,UAAU;AAChD;AAEA,CAZC,SAYS;AACR,aAAW,MAAM;AACnB;AAEA,CAAC;AACC,cAAY;AACZ,SAAO;AACT;AAEA,CALC,gBAKgB;AACf,cAAY;AACd;AAEA,CATC,gBASgB;AACf,WAAS;AACT,UAAQ;AACV;AAEA,CAAC;AACC,cAAY;AACZ,SAAO;AACT;AAEA,CALC,eAKe;AACd,cAAY;AACd;AAEA,CAAC;AACC,cAAY;AACZ,SAAO;AACT;AAEA,CALC,cAKc;AACb,cAAY;AACd;AAEA,CAAC;AACC,WAAS;AACX;AAEA,CAAC;AACC,aAAW,QAAQ,GAAG,OAAO;AAC/B;AAEA,WAJC;AAKC;AAAO,eAAW,OAAO;AAAO;AAChC;AAAK,eAAW,OAAO;AAAS;AAClC;AAEA,WA1Ea;AA2EX;AAAW,aAAS;AAAG;AACvB;AAAM,aAAS;AAAK;AACtB;","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface WidgetError {
|
|
4
|
+
error: string;
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
type WidgetState = 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error';
|
|
8
|
+
interface ThunderPhoneWidgetProps {
|
|
9
|
+
apiKey: string;
|
|
10
|
+
agentId: number;
|
|
11
|
+
apiBase?: string;
|
|
12
|
+
onConnect?: () => void;
|
|
13
|
+
onDisconnect?: () => void;
|
|
14
|
+
onError?: (error: WidgetError) => void;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare function ThunderPhoneWidget({ apiKey, agentId, apiBase, onConnect, onDisconnect, onError, className, }: ThunderPhoneWidgetProps): react_jsx_runtime.JSX.Element;
|
|
19
|
+
|
|
20
|
+
export { ThunderPhoneWidget, type ThunderPhoneWidgetProps, type WidgetError, type WidgetState };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface WidgetError {
|
|
4
|
+
error: string;
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
type WidgetState = 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error';
|
|
8
|
+
interface ThunderPhoneWidgetProps {
|
|
9
|
+
apiKey: string;
|
|
10
|
+
agentId: number;
|
|
11
|
+
apiBase?: string;
|
|
12
|
+
onConnect?: () => void;
|
|
13
|
+
onDisconnect?: () => void;
|
|
14
|
+
onError?: (error: WidgetError) => void;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare function ThunderPhoneWidget({ apiKey, agentId, apiBase, onConnect, onDisconnect, onError, className, }: ThunderPhoneWidgetProps): react_jsx_runtime.JSX.Element;
|
|
19
|
+
|
|
20
|
+
export { ThunderPhoneWidget, type ThunderPhoneWidgetProps, type WidgetError, type WidgetState };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ThunderPhoneWidget: () => ThunderPhoneWidget
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/ThunderPhoneWidget.tsx
|
|
28
|
+
var import_react3 = require("react");
|
|
29
|
+
var import_components_react2 = require("@livekit/components-react");
|
|
30
|
+
|
|
31
|
+
// src/AudioHandler.tsx
|
|
32
|
+
var import_react = require("react");
|
|
33
|
+
var import_components_react = require("@livekit/components-react");
|
|
34
|
+
var import_livekit_client = require("livekit-client");
|
|
35
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
|
+
function AudioHandler({ onAgentConnected, onDisconnected }) {
|
|
37
|
+
const room = (0, import_components_react.useRoomContext)();
|
|
38
|
+
const audioRef = (0, import_react.useRef)(null);
|
|
39
|
+
(0, import_react.useEffect)(() => {
|
|
40
|
+
if (room.remoteParticipants.size > 0) {
|
|
41
|
+
onAgentConnected();
|
|
42
|
+
}
|
|
43
|
+
const handleParticipantConnected = () => onAgentConnected();
|
|
44
|
+
const handleDisconnect = () => onDisconnected();
|
|
45
|
+
const attachTrack = (track, _pub, _participant) => {
|
|
46
|
+
if (track.kind === import_livekit_client.Track.Kind.Audio && audioRef.current) {
|
|
47
|
+
const stream = new MediaStream([track.mediaStreamTrack]);
|
|
48
|
+
audioRef.current.srcObject = stream;
|
|
49
|
+
audioRef.current.play().catch(() => {
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
room.on(import_livekit_client.RoomEvent.ParticipantConnected, handleParticipantConnected);
|
|
54
|
+
room.on(import_livekit_client.RoomEvent.Disconnected, handleDisconnect);
|
|
55
|
+
room.on(import_livekit_client.RoomEvent.TrackSubscribed, attachTrack);
|
|
56
|
+
for (const participant of room.remoteParticipants.values()) {
|
|
57
|
+
for (const pub of participant.trackPublications.values()) {
|
|
58
|
+
if (pub.track && pub.isSubscribed && pub.track.kind === import_livekit_client.Track.Kind.Audio && audioRef.current) {
|
|
59
|
+
const stream = new MediaStream([pub.track.mediaStreamTrack]);
|
|
60
|
+
audioRef.current.srcObject = stream;
|
|
61
|
+
audioRef.current.play().catch(() => {
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return () => {
|
|
67
|
+
room.off(import_livekit_client.RoomEvent.ParticipantConnected, handleParticipantConnected);
|
|
68
|
+
room.off(import_livekit_client.RoomEvent.Disconnected, handleDisconnect);
|
|
69
|
+
room.off(import_livekit_client.RoomEvent.TrackSubscribed, attachTrack);
|
|
70
|
+
};
|
|
71
|
+
}, [room, onAgentConnected, onDisconnected]);
|
|
72
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("audio", { ref: audioRef, autoPlay: true });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/WidgetButton.tsx
|
|
76
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
77
|
+
function WidgetButton({ state, muted, onClick, onMuteToggle }) {
|
|
78
|
+
if (state === "connected") {
|
|
79
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "tp-button-group", children: [
|
|
80
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "tp-button tp-button--mute", onClick: onMuteToggle, type: "button", children: muted ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { className: "tp-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
81
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "1", y1: "1", x2: "23", y2: "23" }),
|
|
82
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6" }),
|
|
83
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M17 16.95A7 7 0 0 1 5 12v-2m14 0v2c0 .76-.13 1.49-.36 2.18" }),
|
|
84
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
|
|
85
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
|
|
86
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { className: "tp-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
87
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
|
|
88
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
|
|
89
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
|
|
90
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
|
|
91
|
+
] }) }),
|
|
92
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "tp-button tp-button--end", onClick, type: "button", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "tp-icon", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) }) })
|
|
93
|
+
] });
|
|
94
|
+
}
|
|
95
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
96
|
+
"button",
|
|
97
|
+
{
|
|
98
|
+
className: `tp-button tp-button--start ${state === "connecting" ? "tp-button--loading" : ""}`,
|
|
99
|
+
onClick,
|
|
100
|
+
disabled: state === "connecting",
|
|
101
|
+
type: "button",
|
|
102
|
+
children: state === "connecting" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "tp-icon tp-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { className: "tp-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
103
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
|
|
104
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
|
|
105
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
|
|
106
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
|
|
107
|
+
] })
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/WidgetStatus.tsx
|
|
113
|
+
var import_react2 = require("react");
|
|
114
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
115
|
+
function WidgetStatus({ state, agentName, errorMessage }) {
|
|
116
|
+
const [elapsed, setElapsed] = (0, import_react2.useState)(0);
|
|
117
|
+
(0, import_react2.useEffect)(() => {
|
|
118
|
+
if (state !== "connected") {
|
|
119
|
+
setElapsed(0);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const interval = setInterval(() => setElapsed((s) => s + 1), 1e3);
|
|
123
|
+
return () => clearInterval(interval);
|
|
124
|
+
}, [state]);
|
|
125
|
+
const formatTime = (seconds) => {
|
|
126
|
+
const m = Math.floor(seconds / 60);
|
|
127
|
+
const s = seconds % 60;
|
|
128
|
+
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
129
|
+
};
|
|
130
|
+
const statusText = {
|
|
131
|
+
idle: "Ready",
|
|
132
|
+
connecting: "Connecting...",
|
|
133
|
+
connected: formatTime(elapsed),
|
|
134
|
+
disconnected: "Disconnected",
|
|
135
|
+
error: "Unable to connect"
|
|
136
|
+
};
|
|
137
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tp-status", children: [
|
|
138
|
+
agentName && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tp-status__name", children: agentName }),
|
|
139
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `tp-status__text tp-status--${state}`, children: [
|
|
140
|
+
state === "connected" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tp-status__dot" }),
|
|
141
|
+
errorMessage && state === "error" ? errorMessage : statusText[state]
|
|
142
|
+
] })
|
|
143
|
+
] });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/api.ts
|
|
147
|
+
var DEFAULT_API_BASE = "https://api.thunderphone.com/v1";
|
|
148
|
+
var WidgetAPIError = class extends Error {
|
|
149
|
+
constructor(code, message) {
|
|
150
|
+
super(message);
|
|
151
|
+
this.code = code;
|
|
152
|
+
this.name = "WidgetAPIError";
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
async function createWidgetSession(apiKey, agentId, apiBase) {
|
|
156
|
+
const base = apiBase || DEFAULT_API_BASE;
|
|
157
|
+
const response = await fetch(`${base}/widget/session`, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
headers: {
|
|
160
|
+
"Content-Type": "application/json",
|
|
161
|
+
"X-API-Key": apiKey
|
|
162
|
+
},
|
|
163
|
+
body: JSON.stringify({ agent_id: agentId })
|
|
164
|
+
});
|
|
165
|
+
if (!response.ok) {
|
|
166
|
+
const data = await response.json().catch(() => ({
|
|
167
|
+
error: "unknown",
|
|
168
|
+
message: "Unable to connect."
|
|
169
|
+
}));
|
|
170
|
+
throw new WidgetAPIError(data.error, data.message);
|
|
171
|
+
}
|
|
172
|
+
return response.json();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/ThunderPhoneWidget.tsx
|
|
176
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
177
|
+
function ThunderPhoneWidget({
|
|
178
|
+
apiKey,
|
|
179
|
+
agentId,
|
|
180
|
+
apiBase,
|
|
181
|
+
onConnect,
|
|
182
|
+
onDisconnect,
|
|
183
|
+
onError,
|
|
184
|
+
className
|
|
185
|
+
}) {
|
|
186
|
+
const [state, setState] = (0, import_react3.useState)("idle");
|
|
187
|
+
const [session, setSession] = (0, import_react3.useState)(null);
|
|
188
|
+
const [muted, setMuted] = (0, import_react3.useState)(false);
|
|
189
|
+
const [errorMessage, setErrorMessage] = (0, import_react3.useState)();
|
|
190
|
+
const handleConnect = (0, import_react3.useCallback)(async () => {
|
|
191
|
+
if (state === "connecting" || state === "connected") return;
|
|
192
|
+
setState("connecting");
|
|
193
|
+
setErrorMessage(void 0);
|
|
194
|
+
try {
|
|
195
|
+
const sess = await createWidgetSession(apiKey, agentId, apiBase);
|
|
196
|
+
setSession(sess);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
setState("error");
|
|
199
|
+
if (err instanceof WidgetAPIError) {
|
|
200
|
+
setErrorMessage(err.message);
|
|
201
|
+
onError?.({ error: err.code, message: err.message });
|
|
202
|
+
} else {
|
|
203
|
+
setErrorMessage("Unable to connect.");
|
|
204
|
+
onError?.({ error: "unknown", message: "Unable to connect." });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}, [apiKey, agentId, apiBase, state, onError]);
|
|
208
|
+
const handleDisconnect = (0, import_react3.useCallback)(() => {
|
|
209
|
+
setState("disconnected");
|
|
210
|
+
setSession(null);
|
|
211
|
+
setMuted(false);
|
|
212
|
+
onDisconnect?.();
|
|
213
|
+
setTimeout(() => setState("idle"), 1500);
|
|
214
|
+
}, [onDisconnect]);
|
|
215
|
+
const handleAgentConnected = (0, import_react3.useCallback)(() => {
|
|
216
|
+
setState("connected");
|
|
217
|
+
onConnect?.();
|
|
218
|
+
}, [onConnect]);
|
|
219
|
+
const handleClick = () => {
|
|
220
|
+
if (state === "connected") {
|
|
221
|
+
handleDisconnect();
|
|
222
|
+
} else if (state === "idle" || state === "error" || state === "disconnected") {
|
|
223
|
+
handleConnect();
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const handleMuteToggle = (0, import_react3.useCallback)(() => {
|
|
227
|
+
setMuted((m) => !m);
|
|
228
|
+
}, []);
|
|
229
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `tp-widget ${className || ""}`, children: [
|
|
230
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
231
|
+
WidgetStatus,
|
|
232
|
+
{
|
|
233
|
+
state,
|
|
234
|
+
agentName: session?.agent_name || null,
|
|
235
|
+
errorMessage
|
|
236
|
+
}
|
|
237
|
+
),
|
|
238
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
239
|
+
WidgetButton,
|
|
240
|
+
{
|
|
241
|
+
state,
|
|
242
|
+
muted,
|
|
243
|
+
onClick: handleClick,
|
|
244
|
+
onMuteToggle: handleMuteToggle
|
|
245
|
+
}
|
|
246
|
+
),
|
|
247
|
+
session && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
248
|
+
import_components_react2.LiveKitRoom,
|
|
249
|
+
{
|
|
250
|
+
token: session.token,
|
|
251
|
+
serverUrl: session.server_url,
|
|
252
|
+
audio: !muted,
|
|
253
|
+
video: false,
|
|
254
|
+
connect: true,
|
|
255
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
256
|
+
AudioHandler,
|
|
257
|
+
{
|
|
258
|
+
onAgentConnected: handleAgentConnected,
|
|
259
|
+
onDisconnected: handleDisconnect
|
|
260
|
+
}
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
)
|
|
264
|
+
] });
|
|
265
|
+
}
|
|
266
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
267
|
+
0 && (module.exports = {
|
|
268
|
+
ThunderPhoneWidget
|
|
269
|
+
});
|
|
270
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/ThunderPhoneWidget.tsx","../src/AudioHandler.tsx","../src/WidgetButton.tsx","../src/WidgetStatus.tsx","../src/api.ts"],"sourcesContent":["import './style.css'\n\nexport { ThunderPhoneWidget } from './ThunderPhoneWidget'\nexport type { ThunderPhoneWidgetProps, WidgetError, WidgetState } from './types'\n","import { useCallback, useState } from 'react'\nimport { LiveKitRoom } from '@livekit/components-react'\nimport { AudioHandler } from './AudioHandler'\nimport { WidgetButton } from './WidgetButton'\nimport { WidgetStatus } from './WidgetStatus'\nimport { createWidgetSession, WidgetAPIError } from './api'\nimport type { ThunderPhoneWidgetProps, WidgetState, WidgetSessionResponse } from './types'\n\nexport function ThunderPhoneWidget({\n apiKey,\n agentId,\n apiBase,\n onConnect,\n onDisconnect,\n onError,\n className,\n}: ThunderPhoneWidgetProps) {\n const [state, setState] = useState<WidgetState>('idle')\n const [session, setSession] = useState<WidgetSessionResponse | null>(null)\n const [muted, setMuted] = useState(false)\n const [errorMessage, setErrorMessage] = useState<string | undefined>()\n\n const handleConnect = useCallback(async () => {\n if (state === 'connecting' || state === 'connected') return\n setState('connecting')\n setErrorMessage(undefined)\n try {\n const sess = await createWidgetSession(apiKey, agentId, apiBase)\n setSession(sess)\n } catch (err) {\n setState('error')\n if (err instanceof WidgetAPIError) {\n setErrorMessage(err.message)\n onError?.({ error: err.code, message: err.message })\n } else {\n setErrorMessage('Unable to connect.')\n onError?.({ error: 'unknown', message: 'Unable to connect.' })\n }\n }\n }, [apiKey, agentId, apiBase, state, onError])\n\n const handleDisconnect = useCallback(() => {\n setState('disconnected')\n setSession(null)\n setMuted(false)\n onDisconnect?.()\n setTimeout(() => setState('idle'), 1500)\n }, [onDisconnect])\n\n const handleAgentConnected = useCallback(() => {\n setState('connected')\n onConnect?.()\n }, [onConnect])\n\n const handleClick = () => {\n if (state === 'connected') {\n handleDisconnect()\n } else if (state === 'idle' || state === 'error' || state === 'disconnected') {\n handleConnect()\n }\n }\n\n const handleMuteToggle = useCallback(() => {\n setMuted(m => !m)\n }, [])\n\n return (\n <div className={`tp-widget ${className || ''}`}>\n <WidgetStatus\n state={state}\n agentName={session?.agent_name || null}\n errorMessage={errorMessage}\n />\n <WidgetButton\n state={state}\n muted={muted}\n onClick={handleClick}\n onMuteToggle={handleMuteToggle}\n />\n {session && (\n <LiveKitRoom\n token={session.token}\n serverUrl={session.server_url}\n audio={!muted}\n video={false}\n connect={true}\n >\n <AudioHandler\n onAgentConnected={handleAgentConnected}\n onDisconnected={handleDisconnect}\n />\n </LiveKitRoom>\n )}\n </div>\n )\n}\n","import { useEffect, useRef } from 'react'\nimport { useRoomContext } from '@livekit/components-react'\nimport { RoomEvent, Track, type RemoteTrackPublication, type RemoteParticipant } from 'livekit-client'\n\ninterface AudioHandlerProps {\n onAgentConnected: () => void\n onDisconnected: () => void\n}\n\nexport function AudioHandler({ onAgentConnected, onDisconnected }: AudioHandlerProps) {\n const room = useRoomContext()\n const audioRef = useRef<HTMLAudioElement>(null)\n\n useEffect(() => {\n if (room.remoteParticipants.size > 0) {\n onAgentConnected()\n }\n\n const handleParticipantConnected = () => onAgentConnected()\n const handleDisconnect = () => onDisconnected()\n\n const attachTrack = (\n track: { kind: Track.Kind; mediaStreamTrack: MediaStreamTrack },\n _pub: RemoteTrackPublication,\n _participant: RemoteParticipant,\n ) => {\n if (track.kind === Track.Kind.Audio && audioRef.current) {\n const stream = new MediaStream([track.mediaStreamTrack])\n audioRef.current.srcObject = stream\n audioRef.current.play().catch(() => {})\n }\n }\n\n room.on(RoomEvent.ParticipantConnected, handleParticipantConnected)\n room.on(RoomEvent.Disconnected, handleDisconnect)\n room.on(RoomEvent.TrackSubscribed, attachTrack)\n\n for (const participant of room.remoteParticipants.values()) {\n for (const pub of participant.trackPublications.values()) {\n if (pub.track && pub.isSubscribed && pub.track.kind === Track.Kind.Audio && audioRef.current) {\n const stream = new MediaStream([pub.track.mediaStreamTrack])\n audioRef.current.srcObject = stream\n audioRef.current.play().catch(() => {})\n }\n }\n }\n\n return () => {\n room.off(RoomEvent.ParticipantConnected, handleParticipantConnected)\n room.off(RoomEvent.Disconnected, handleDisconnect)\n room.off(RoomEvent.TrackSubscribed, attachTrack)\n }\n }, [room, onAgentConnected, onDisconnected])\n\n return <audio ref={audioRef} autoPlay />\n}\n","import type { WidgetState } from './types'\n\ninterface WidgetButtonProps {\n state: WidgetState\n muted: boolean\n onClick: () => void\n onMuteToggle: () => void\n}\n\nexport function WidgetButton({ state, muted, onClick, onMuteToggle }: WidgetButtonProps) {\n if (state === 'connected') {\n return (\n <div className=\"tp-button-group\">\n <button className=\"tp-button tp-button--mute\" onClick={onMuteToggle} type=\"button\">\n {muted ? (\n <svg className=\"tp-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" />\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\" />\n <path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2c0 .76-.13 1.49-.36 2.18\" />\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" />\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n </svg>\n ) : (\n <svg className=\"tp-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" />\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n </svg>\n )}\n </button>\n <button className=\"tp-button tp-button--end\" onClick={onClick} type=\"button\">\n <svg className=\"tp-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <rect x=\"6\" y=\"6\" width=\"12\" height=\"12\" rx=\"2\" />\n </svg>\n </button>\n </div>\n )\n }\n\n return (\n <button\n className={`tp-button tp-button--start ${state === 'connecting' ? 'tp-button--loading' : ''}`}\n onClick={onClick}\n disabled={state === 'connecting'}\n type=\"button\"\n >\n {state === 'connecting' ? (\n <svg className=\"tp-icon tp-spin\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n ) : (\n <svg className=\"tp-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" />\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n </svg>\n )}\n </button>\n )\n}\n","import { useEffect, useState } from 'react'\nimport type { WidgetState } from './types'\n\ninterface WidgetStatusProps {\n state: WidgetState\n agentName: string | null\n errorMessage?: string\n}\n\nexport function WidgetStatus({ state, agentName, errorMessage }: WidgetStatusProps) {\n const [elapsed, setElapsed] = useState(0)\n\n useEffect(() => {\n if (state !== 'connected') {\n setElapsed(0)\n return\n }\n const interval = setInterval(() => setElapsed(s => s + 1), 1000)\n return () => clearInterval(interval)\n }, [state])\n\n const formatTime = (seconds: number) => {\n const m = Math.floor(seconds / 60)\n const s = seconds % 60\n return `${m}:${s.toString().padStart(2, '0')}`\n }\n\n const statusText: Record<WidgetState, string> = {\n idle: 'Ready',\n connecting: 'Connecting...',\n connected: formatTime(elapsed),\n disconnected: 'Disconnected',\n error: 'Unable to connect',\n }\n\n return (\n <div className=\"tp-status\">\n {agentName && <div className=\"tp-status__name\">{agentName}</div>}\n <div className={`tp-status__text tp-status--${state}`}>\n {state === 'connected' && <span className=\"tp-status__dot\" />}\n {errorMessage && state === 'error' ? errorMessage : statusText[state]}\n </div>\n </div>\n )\n}\n","import type { WidgetSessionResponse, WidgetError } from './types'\n\nconst DEFAULT_API_BASE = 'https://api.thunderphone.com/v1'\n\nexport class WidgetAPIError extends Error {\n constructor(public code: string, message: string) {\n super(message)\n this.name = 'WidgetAPIError'\n }\n}\n\nexport async function createWidgetSession(\n apiKey: string,\n agentId: number,\n apiBase?: string,\n): Promise<WidgetSessionResponse> {\n const base = apiBase || DEFAULT_API_BASE\n const response = await fetch(`${base}/widget/session`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify({ agent_id: agentId }),\n })\n\n if (!response.ok) {\n const data: WidgetError = await response.json().catch(() => ({\n error: 'unknown',\n message: 'Unable to connect.',\n }))\n throw new WidgetAPIError(data.error, data.message)\n }\n\n return response.json()\n}\n"],"mappings":"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","names":["import_react","import_components_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime"]}
|