@skippr/live-agent-sdk 0.15.0 → 0.16.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/esm/lib-exports.js +59 -36
- package/dist/skippr-sdk.js +115 -115
- package/package.json +1 -1
package/dist/esm/lib-exports.js
CHANGED
|
@@ -145,17 +145,21 @@ function useAuth({ appKey }) {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
// src/hooks/useSession.ts
|
|
148
|
-
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
148
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
149
149
|
var API_URL2 = "https://skipprapi-production.up.railway.app";
|
|
150
|
-
function
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
headers
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
150
|
+
async function exchangeForBearerToken(appKey, userToken) {
|
|
151
|
+
const resp = await fetch(`${API_URL2}/v1/auth/token-exchange`, {
|
|
152
|
+
method: "POST",
|
|
153
|
+
headers: {
|
|
154
|
+
"X-App-Key": appKey,
|
|
155
|
+
"X-User-Token": userToken
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
if (!resp.ok) {
|
|
159
|
+
throw new Error(`Token exchange failed: ${resp.status}`);
|
|
160
|
+
}
|
|
161
|
+
const { token } = await resp.json();
|
|
162
|
+
return token;
|
|
159
163
|
}
|
|
160
164
|
function useSession({ agentId, authToken, appKey, userToken }) {
|
|
161
165
|
const [connection, setConnection] = useState2(null);
|
|
@@ -163,32 +167,53 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
163
167
|
const [isStarting, setIsStarting] = useState2(false);
|
|
164
168
|
const [error, setError] = useState2("");
|
|
165
169
|
const [sessionId, setSessionId] = useState2(null);
|
|
166
|
-
const [
|
|
170
|
+
const [bearerToken, setBearerToken] = useState2(authToken ?? null);
|
|
171
|
+
useEffect2(() => {
|
|
172
|
+
let stale = false;
|
|
173
|
+
if (authToken) {
|
|
174
|
+
setBearerToken(authToken);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (appKey && userToken) {
|
|
178
|
+
exchangeForBearerToken(appKey, userToken).then((token) => {
|
|
179
|
+
if (!stale)
|
|
180
|
+
setBearerToken(token);
|
|
181
|
+
}).catch((e) => {
|
|
182
|
+
if (!stale)
|
|
183
|
+
setError(e instanceof Error ? e.message : "Token exchange failed");
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return () => {
|
|
187
|
+
stale = true;
|
|
188
|
+
};
|
|
189
|
+
}, [authToken, appKey, userToken]);
|
|
167
190
|
const startSession = useCallback2(async () => {
|
|
191
|
+
if (!bearerToken) {
|
|
192
|
+
setError("No auth token available");
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const headers = { Authorization: `Bearer ${bearerToken}` };
|
|
168
196
|
setIsStarting(true);
|
|
169
197
|
setError("");
|
|
170
198
|
try {
|
|
171
|
-
const authHeaders = resolveAuthHeaders(authToken, appKey, userToken);
|
|
172
199
|
const createResp = await fetch(`${API_URL2}/v1/sessions`, {
|
|
173
200
|
method: "POST",
|
|
174
|
-
headers: { "Content-Type": "application/json", ...
|
|
201
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
175
202
|
body: JSON.stringify({ agentId })
|
|
176
203
|
});
|
|
177
204
|
if (!createResp.ok) {
|
|
178
205
|
throw new Error(`Failed to create session: ${createResp.status}`);
|
|
179
206
|
}
|
|
180
207
|
const { session } = await createResp.json();
|
|
181
|
-
const sessionHeaders = { "X-Session-Token": session.sessionToken };
|
|
182
208
|
const startResp = await fetch(`${API_URL2}/v1/sessions/${session.id}/start`, {
|
|
183
209
|
method: "POST",
|
|
184
|
-
headers
|
|
210
|
+
headers
|
|
185
211
|
});
|
|
186
212
|
if (!startResp.ok) {
|
|
187
213
|
throw new Error(`Failed to start session: ${startResp.status}`);
|
|
188
214
|
}
|
|
189
215
|
const { connection: conn } = await startResp.json();
|
|
190
216
|
setSessionId(session.id);
|
|
191
|
-
setSessionToken(session.sessionToken);
|
|
192
217
|
setConnection({
|
|
193
218
|
livekitUrl: conn.livekitUrl,
|
|
194
219
|
token: conn.token
|
|
@@ -199,14 +224,13 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
199
224
|
} finally {
|
|
200
225
|
setIsStarting(false);
|
|
201
226
|
}
|
|
202
|
-
}, [agentId,
|
|
227
|
+
}, [agentId, bearerToken]);
|
|
203
228
|
const disconnect = useCallback2(async () => {
|
|
204
|
-
if (sessionId &&
|
|
205
|
-
const sessionHeaders = { "X-Session-Token": sessionToken };
|
|
229
|
+
if (sessionId && bearerToken) {
|
|
206
230
|
try {
|
|
207
231
|
await fetch(`${API_URL2}/v1/sessions/${sessionId}/complete`, {
|
|
208
232
|
method: "POST",
|
|
209
|
-
headers: { "Content-Type": "application/json",
|
|
233
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearerToken}` },
|
|
210
234
|
body: JSON.stringify({})
|
|
211
235
|
});
|
|
212
236
|
} catch {}
|
|
@@ -215,15 +239,14 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
215
239
|
setShouldConnect(false);
|
|
216
240
|
setConnection(null);
|
|
217
241
|
setSessionId(null);
|
|
218
|
-
|
|
219
|
-
}, [sessionId, sessionToken]);
|
|
242
|
+
}, [sessionId, bearerToken]);
|
|
220
243
|
return { connection, shouldConnect, isStarting, error, startSession, disconnect };
|
|
221
244
|
}
|
|
222
245
|
|
|
223
246
|
// src/components/Sidebar.tsx
|
|
224
247
|
import { useConnectionState } from "@livekit/components-react";
|
|
225
248
|
import { ConnectionState } from "livekit-client";
|
|
226
|
-
import { useEffect as
|
|
249
|
+
import { useEffect as useEffect7 } from "react";
|
|
227
250
|
|
|
228
251
|
// src/hooks/useCombinedMessages.ts
|
|
229
252
|
import { useVoiceAssistant } from "@livekit/components-react";
|
|
@@ -321,11 +344,11 @@ import { useCallback as useCallback3 } from "react";
|
|
|
321
344
|
|
|
322
345
|
// src/hooks/useAgentState.ts
|
|
323
346
|
import { useRemoteParticipants } from "@livekit/components-react";
|
|
324
|
-
import { useEffect as
|
|
347
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
325
348
|
function useAgentState(attributeKey, parse, initial) {
|
|
326
349
|
const [value, setValue] = useState3(initial);
|
|
327
350
|
const remoteParticipants = useRemoteParticipants();
|
|
328
|
-
|
|
351
|
+
useEffect3(() => {
|
|
329
352
|
const agentParticipant = remoteParticipants.find((p) => p.attributes?.[attributeKey]);
|
|
330
353
|
if (agentParticipant) {
|
|
331
354
|
const attr = agentParticipant.attributes?.[attributeKey];
|
|
@@ -666,7 +689,7 @@ function ChatHeader({ onClose }) {
|
|
|
666
689
|
}
|
|
667
690
|
|
|
668
691
|
// src/components/LoginFlow.tsx
|
|
669
|
-
import { useCallback as useCallback5, useEffect as
|
|
692
|
+
import { useCallback as useCallback5, useEffect as useEffect4, useRef, useState as useState4 } from "react";
|
|
670
693
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
671
694
|
var OTP_LENGTH = 6;
|
|
672
695
|
var DIGIT_KEYS = ["d0", "d1", "d2", "d3", "d4", "d5"];
|
|
@@ -765,14 +788,14 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
765
788
|
const [resendCooldown, setResendCooldown] = useState4(0);
|
|
766
789
|
const inputRefs = useRef([]);
|
|
767
790
|
const submittedRef = useRef(false);
|
|
768
|
-
|
|
791
|
+
useEffect4(() => {
|
|
769
792
|
inputRefs.current[0]?.focus();
|
|
770
793
|
}, []);
|
|
771
|
-
|
|
794
|
+
useEffect4(() => {
|
|
772
795
|
if (error)
|
|
773
796
|
submittedRef.current = false;
|
|
774
797
|
}, [error]);
|
|
775
|
-
|
|
798
|
+
useEffect4(() => {
|
|
776
799
|
if (resendCooldown <= 0)
|
|
777
800
|
return;
|
|
778
801
|
const timer = setTimeout(() => setResendCooldown((c) => c - 1), 1000);
|
|
@@ -915,7 +938,7 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
915
938
|
// src/components/MeetingControls.tsx
|
|
916
939
|
import { useLocalParticipant as useLocalParticipant3 } from "@livekit/components-react";
|
|
917
940
|
import { ScreenSharePresets } from "livekit-client";
|
|
918
|
-
import { useCallback as useCallback6, useEffect as
|
|
941
|
+
import { useCallback as useCallback6, useEffect as useEffect5, useRef as useRef2, useState as useState5 } from "react";
|
|
919
942
|
|
|
920
943
|
// src/lib/format.ts
|
|
921
944
|
function formatTime(seconds) {
|
|
@@ -950,7 +973,7 @@ function MeetingControls({ onHangUp }) {
|
|
|
950
973
|
const isScreenSharing = localParticipant.isScreenShareEnabled;
|
|
951
974
|
const endTimeRef = useRef2(null);
|
|
952
975
|
const [remaining, setRemaining] = useState5(null);
|
|
953
|
-
|
|
976
|
+
useEffect5(() => {
|
|
954
977
|
if (maxCallDuration === null || endTimeRef.current !== null)
|
|
955
978
|
return;
|
|
956
979
|
endTimeRef.current = Date.now() + maxCallDuration * 1000;
|
|
@@ -980,7 +1003,7 @@ function MeetingControls({ onHangUp }) {
|
|
|
980
1003
|
console.error("Failed to toggle screen share:", e);
|
|
981
1004
|
}
|
|
982
1005
|
}, [localParticipant, isScreenSharing]);
|
|
983
|
-
|
|
1006
|
+
useEffect5(() => {
|
|
984
1007
|
toggleMute().then(() => toggleScreenShare());
|
|
985
1008
|
}, []);
|
|
986
1009
|
return /* @__PURE__ */ jsxs3("div", {
|
|
@@ -1038,7 +1061,7 @@ function MeetingControls({ onHangUp }) {
|
|
|
1038
1061
|
}
|
|
1039
1062
|
|
|
1040
1063
|
// src/components/MessageList.tsx
|
|
1041
|
-
import { useEffect as
|
|
1064
|
+
import { useEffect as useEffect6, useRef as useRef3 } from "react";
|
|
1042
1065
|
|
|
1043
1066
|
// src/components/ChatInput.tsx
|
|
1044
1067
|
import { useState as useState6 } from "react";
|
|
@@ -1124,7 +1147,7 @@ function MessageList({
|
|
|
1124
1147
|
}) {
|
|
1125
1148
|
const scrollRef = useRef3(null);
|
|
1126
1149
|
const lastMessage = messages.length > 0 ? messages[messages.length - 1] : undefined;
|
|
1127
|
-
|
|
1150
|
+
useEffect6(() => {
|
|
1128
1151
|
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1129
1152
|
}, [messages.length, lastMessage?.content]);
|
|
1130
1153
|
const showTyping = isStreaming && lastMessage?.role === "assistant" && lastMessage.content === "";
|
|
@@ -1286,11 +1309,11 @@ function Sidebar() {
|
|
|
1286
1309
|
verifyOtp,
|
|
1287
1310
|
isAuthSubmitting
|
|
1288
1311
|
} = useLiveAgent();
|
|
1289
|
-
|
|
1312
|
+
useEffect7(() => {
|
|
1290
1313
|
document.body.style.transition = "margin-right 300ms ease-in-out";
|
|
1291
1314
|
document.body.style.marginRight = isPanelOpen ? `${SIDEBAR_WIDTH}px` : "0px";
|
|
1292
1315
|
}, [isPanelOpen]);
|
|
1293
|
-
|
|
1316
|
+
useEffect7(() => {
|
|
1294
1317
|
return () => {
|
|
1295
1318
|
document.body.style.marginRight = "";
|
|
1296
1319
|
document.body.style.transition = "";
|