@skippr/live-agent-sdk 0.35.0 → 0.37.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/README.md +26 -7
- package/dist/esm/lib-exports.js +314 -230
- package/dist/skippr-sdk.js +147 -147
- package/dist/types/components/LiveAgent.d.ts +1 -0
- package/dist/types/context/LiveAgentContext.d.ts +14 -3
- package/dist/types/hooks/useAuth.d.ts +1 -1
- package/dist/types/hooks/useAvailableModules.d.ts +3 -1
- package/dist/types/hooks/useSession.d.ts +8 -13
- package/dist/types/lib/session.d.ts +4 -0
- package/package.json +1 -1
package/dist/esm/lib-exports.js
CHANGED
|
@@ -8,7 +8,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
8
8
|
|
|
9
9
|
// src/components/LiveAgent.tsx
|
|
10
10
|
import { LiveKitRoom, RoomAudioRenderer } from "@livekit/components-react";
|
|
11
|
-
import { useCallback as useCallback8, useMemo as
|
|
11
|
+
import { useCallback as useCallback8, useMemo as useMemo5, useRef as useRef10, useState as useState11 } from "react";
|
|
12
12
|
|
|
13
13
|
// src/context/LiveAgentContext.tsx
|
|
14
14
|
import { createContext } from "react";
|
|
@@ -137,12 +137,24 @@ function useAuth({ appKey }) {
|
|
|
137
137
|
setIsSubmitting(false);
|
|
138
138
|
}
|
|
139
139
|
}, [appKey]);
|
|
140
|
-
const logout = useCallback(() => {
|
|
140
|
+
const logout = useCallback(async () => {
|
|
141
|
+
const token = authToken;
|
|
141
142
|
if (appKey)
|
|
142
143
|
clearStoredToken(appKey);
|
|
143
144
|
setAuthToken(null);
|
|
144
145
|
setError("");
|
|
145
|
-
|
|
146
|
+
if (!token)
|
|
147
|
+
return;
|
|
148
|
+
try {
|
|
149
|
+
await fetch(`${API_URL}/v1/auth/logout`, {
|
|
150
|
+
method: "POST",
|
|
151
|
+
credentials: "omit",
|
|
152
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
153
|
+
});
|
|
154
|
+
} catch (e) {
|
|
155
|
+
console.warn("[Skippr] Failed to revoke session on logout:", e);
|
|
156
|
+
}
|
|
157
|
+
}, [appKey, authToken]);
|
|
146
158
|
return {
|
|
147
159
|
isAuthenticated,
|
|
148
160
|
isValidating,
|
|
@@ -160,23 +172,17 @@ import { useCallback as useCallback2, useEffect as useEffect2, useState as useSt
|
|
|
160
172
|
var API_URL2 = "https://specialist.skippr.ai/api";
|
|
161
173
|
function useAvailableModules({
|
|
162
174
|
enabled,
|
|
163
|
-
bearerToken
|
|
175
|
+
bearerToken,
|
|
176
|
+
authedFetch
|
|
164
177
|
}) {
|
|
165
178
|
const [modules, setModules] = useState2([]);
|
|
166
179
|
const [isLoading, setIsLoading] = useState2(false);
|
|
167
180
|
const [error, setError] = useState2(null);
|
|
168
181
|
const fetchModules = useCallback2(async () => {
|
|
169
|
-
if (!bearerToken) {
|
|
170
|
-
setError("No auth token available");
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
182
|
setIsLoading(true);
|
|
174
183
|
setError(null);
|
|
175
184
|
try {
|
|
176
|
-
const resp = await
|
|
177
|
-
credentials: "omit",
|
|
178
|
-
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
179
|
-
});
|
|
185
|
+
const resp = await authedFetch(`${API_URL2}/v1/modules/available`);
|
|
180
186
|
if (!resp.ok) {
|
|
181
187
|
const body = await resp.json().catch(() => null);
|
|
182
188
|
throw new Error(body?.detail || `Failed to load modules: ${resp.status}`);
|
|
@@ -188,7 +194,7 @@ function useAvailableModules({
|
|
|
188
194
|
} finally {
|
|
189
195
|
setIsLoading(false);
|
|
190
196
|
}
|
|
191
|
-
}, [
|
|
197
|
+
}, [authedFetch]);
|
|
192
198
|
useEffect2(() => {
|
|
193
199
|
if (!enabled || !bearerToken)
|
|
194
200
|
return;
|
|
@@ -205,12 +211,9 @@ function useAvailableModules({
|
|
|
205
211
|
// src/hooks/useSession.ts
|
|
206
212
|
import { useCallback as useCallback3, useEffect as useEffect3, useRef, useState as useState3 } from "react";
|
|
207
213
|
var API_URL3 = "https://specialist.skippr.ai/api";
|
|
208
|
-
async function fetchSessionMessages(sessionId,
|
|
214
|
+
async function fetchSessionMessages(sessionId, authedFetch) {
|
|
209
215
|
try {
|
|
210
|
-
const resp = await
|
|
211
|
-
credentials: "omit",
|
|
212
|
-
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
213
|
-
});
|
|
216
|
+
const resp = await authedFetch(`${API_URL3}/v1/sessions/${sessionId}/messages`);
|
|
214
217
|
if (!resp.ok)
|
|
215
218
|
return [];
|
|
216
219
|
const { messages } = await resp.json();
|
|
@@ -225,6 +228,7 @@ async function fetchSessionMessages(sessionId, bearerToken) {
|
|
|
225
228
|
return [];
|
|
226
229
|
}
|
|
227
230
|
}
|
|
231
|
+
var REFRESH_BUFFER_MS = 180000;
|
|
228
232
|
async function requestScreenShare() {
|
|
229
233
|
try {
|
|
230
234
|
return await navigator.mediaDevices.getDisplayMedia({ video: { displaySurface: "browser" } });
|
|
@@ -250,13 +254,14 @@ async function exchangeForBearerToken(appKey, userToken) {
|
|
|
250
254
|
if (!resp.ok) {
|
|
251
255
|
throw new Error(`Token exchange failed: ${resp.status}`);
|
|
252
256
|
}
|
|
253
|
-
const { token } = await resp.json();
|
|
254
|
-
return token;
|
|
257
|
+
const { token, expiresAt } = await resp.json();
|
|
258
|
+
return { token, expiresAt: new Date(expiresAt).getTime() };
|
|
255
259
|
}
|
|
256
260
|
function useSession({
|
|
257
261
|
captureMode = "screenshare",
|
|
258
262
|
authToken,
|
|
259
263
|
appKey,
|
|
264
|
+
getUserToken,
|
|
260
265
|
userToken,
|
|
261
266
|
onStart,
|
|
262
267
|
onStartError,
|
|
@@ -273,50 +278,107 @@ function useSession({
|
|
|
273
278
|
const [pendingScreenStream, setPendingScreenStream] = useState3(null);
|
|
274
279
|
const [isPaused, setIsPaused] = useState3(false);
|
|
275
280
|
const [isPausing, setIsPausing] = useState3(false);
|
|
276
|
-
const [resumableSessions, setResumableSessions] = useState3([]);
|
|
277
281
|
const [historyMessages, setHistoryMessages] = useState3([]);
|
|
282
|
+
const [authFailed, setAuthFailed] = useState3(false);
|
|
283
|
+
const tokenRef = useRef(authToken ? { token: authToken, expiresAt: null } : null);
|
|
284
|
+
const getUserTokenRef = useRef(getUserToken);
|
|
285
|
+
getUserTokenRef.current = getUserToken ?? (userToken ? () => Promise.resolve(userToken) : undefined);
|
|
286
|
+
const failedBearerRef = useRef(null);
|
|
287
|
+
const inFlightExchangeRef = useRef(null);
|
|
288
|
+
const canExchange = useCallback3(() => !!appKey && !!getUserTokenRef.current, [appKey]);
|
|
289
|
+
const reExchange = useCallback3(async () => {
|
|
290
|
+
if (inFlightExchangeRef.current)
|
|
291
|
+
return inFlightExchangeRef.current;
|
|
292
|
+
const provider = getUserTokenRef.current;
|
|
293
|
+
if (!appKey || !provider)
|
|
294
|
+
throw new Error("No token provider available");
|
|
295
|
+
const exchange = (async () => {
|
|
296
|
+
const userToken2 = await provider();
|
|
297
|
+
const { token, expiresAt } = await exchangeForBearerToken(appKey, userToken2);
|
|
298
|
+
tokenRef.current = { token, expiresAt };
|
|
299
|
+
setBearerToken(token);
|
|
300
|
+
return token;
|
|
301
|
+
})();
|
|
302
|
+
inFlightExchangeRef.current = exchange;
|
|
303
|
+
try {
|
|
304
|
+
return await exchange;
|
|
305
|
+
} finally {
|
|
306
|
+
inFlightExchangeRef.current = null;
|
|
307
|
+
}
|
|
308
|
+
}, [appKey]);
|
|
309
|
+
const getValidBearer = useCallback3(async () => {
|
|
310
|
+
const current = tokenRef.current;
|
|
311
|
+
if (current) {
|
|
312
|
+
if (current.expiresAt === null)
|
|
313
|
+
return current.token;
|
|
314
|
+
if (Date.now() < current.expiresAt - REFRESH_BUFFER_MS)
|
|
315
|
+
return current.token;
|
|
316
|
+
}
|
|
317
|
+
if (canExchange())
|
|
318
|
+
return reExchange();
|
|
319
|
+
return current?.token ?? null;
|
|
320
|
+
}, [canExchange, reExchange]);
|
|
321
|
+
const authedFetch = useCallback3(async (input, init = {}) => {
|
|
322
|
+
const isSecretMode = canExchange();
|
|
323
|
+
const onTerminalAuthFailure = () => {
|
|
324
|
+
if (isSecretMode)
|
|
325
|
+
setAuthFailed(true);
|
|
326
|
+
else
|
|
327
|
+
window.dispatchEvent(new Event("skippr:logout"));
|
|
328
|
+
};
|
|
329
|
+
const baseHeaders = init.headers ?? {};
|
|
330
|
+
const run = (token) => fetch(input, {
|
|
331
|
+
...init,
|
|
332
|
+
credentials: "omit",
|
|
333
|
+
headers: token ? { ...baseHeaders, Authorization: `Bearer ${token}` } : baseHeaders
|
|
334
|
+
});
|
|
335
|
+
let bearer;
|
|
336
|
+
try {
|
|
337
|
+
bearer = await getValidBearer();
|
|
338
|
+
} catch (e) {
|
|
339
|
+
onTerminalAuthFailure();
|
|
340
|
+
throw e;
|
|
341
|
+
}
|
|
342
|
+
let resp = await run(bearer);
|
|
343
|
+
const canRetry = resp.status === 401 && isSecretMode && bearer !== failedBearerRef.current;
|
|
344
|
+
if (canRetry) {
|
|
345
|
+
let refreshed;
|
|
346
|
+
try {
|
|
347
|
+
refreshed = await reExchange();
|
|
348
|
+
} catch (e) {
|
|
349
|
+
onTerminalAuthFailure();
|
|
350
|
+
throw e;
|
|
351
|
+
}
|
|
352
|
+
resp = await run(refreshed);
|
|
353
|
+
failedBearerRef.current = resp.status === 401 ? refreshed : null;
|
|
354
|
+
} else if (resp.status !== 401) {
|
|
355
|
+
failedBearerRef.current = null;
|
|
356
|
+
}
|
|
357
|
+
if (resp.status === 401)
|
|
358
|
+
onTerminalAuthFailure();
|
|
359
|
+
else if (resp.ok)
|
|
360
|
+
setAuthFailed(false);
|
|
361
|
+
return resp;
|
|
362
|
+
}, [canExchange, getValidBearer, reExchange]);
|
|
278
363
|
useEffect3(() => {
|
|
279
364
|
let stale = false;
|
|
280
365
|
if (authToken) {
|
|
366
|
+
tokenRef.current = { token: authToken, expiresAt: null };
|
|
281
367
|
setBearerToken(authToken);
|
|
282
368
|
return;
|
|
283
369
|
}
|
|
284
|
-
if (
|
|
285
|
-
|
|
286
|
-
if (
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
setError(e instanceof Error ? e.message : "Token exchange failed");
|
|
370
|
+
if (canExchange()) {
|
|
371
|
+
reExchange().catch((e) => {
|
|
372
|
+
if (stale)
|
|
373
|
+
return;
|
|
374
|
+
setError(e instanceof Error ? e.message : "Token exchange failed");
|
|
375
|
+
setAuthFailed(true);
|
|
291
376
|
});
|
|
292
377
|
}
|
|
293
378
|
return () => {
|
|
294
379
|
stale = true;
|
|
295
380
|
};
|
|
296
|
-
}, [authToken,
|
|
297
|
-
const refetchResumable = useCallback3(async () => {
|
|
298
|
-
if (!bearerToken) {
|
|
299
|
-
setResumableSessions([]);
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
try {
|
|
303
|
-
const resp = await fetch(`${API_URL3}/v1/sessions/resumable`, {
|
|
304
|
-
credentials: "omit",
|
|
305
|
-
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
306
|
-
});
|
|
307
|
-
if (!resp.ok) {
|
|
308
|
-
setResumableSessions([]);
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
const { sessions } = await resp.json();
|
|
312
|
-
setResumableSessions(sessions);
|
|
313
|
-
} catch {
|
|
314
|
-
setResumableSessions([]);
|
|
315
|
-
}
|
|
316
|
-
}, [bearerToken]);
|
|
317
|
-
useEffect3(() => {
|
|
318
|
-
refetchResumable();
|
|
319
|
-
}, [refetchResumable]);
|
|
381
|
+
}, [authToken, canExchange, reExchange]);
|
|
320
382
|
const pauseOnUnloadRef = useRef(null);
|
|
321
383
|
pauseOnUnloadRef.current = connection !== null && !isPaused && sessionId && bearerToken ? { sessionId, bearerToken } : null;
|
|
322
384
|
useEffect3(() => {
|
|
@@ -334,12 +396,12 @@ function useSession({
|
|
|
334
396
|
window.addEventListener("pagehide", onPageHide);
|
|
335
397
|
return () => window.removeEventListener("pagehide", onPageHide);
|
|
336
398
|
}, []);
|
|
337
|
-
const startSession = useCallback3(async ({ agentId, agentControls }) => {
|
|
399
|
+
const startSession = useCallback3(async ({ agentId, agentControls, existingSessionId }) => {
|
|
338
400
|
if (!bearerToken) {
|
|
339
401
|
setError("No auth token available");
|
|
340
402
|
return;
|
|
341
403
|
}
|
|
342
|
-
if (!agentId) {
|
|
404
|
+
if (!agentId && !existingSessionId) {
|
|
343
405
|
setError("No agent selected");
|
|
344
406
|
return;
|
|
345
407
|
}
|
|
@@ -352,37 +414,40 @@ function useSession({
|
|
|
352
414
|
screenStream = await requestScreenShare();
|
|
353
415
|
}
|
|
354
416
|
const requestAgentControls = agentControls?.highlight === true ? { highlight: true } : undefined;
|
|
355
|
-
const headers = { Authorization: `Bearer ${bearerToken}` };
|
|
356
417
|
try {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
418
|
+
let resolvedSessionId = existingSessionId;
|
|
419
|
+
if (!resolvedSessionId) {
|
|
420
|
+
const createResp = await authedFetch(`${API_URL3}/v1/sessions`, {
|
|
421
|
+
method: "POST",
|
|
422
|
+
headers: { "Content-Type": "application/json" },
|
|
423
|
+
body: JSON.stringify({
|
|
424
|
+
agentId,
|
|
425
|
+
captureMode,
|
|
426
|
+
agentControls: requestAgentControls
|
|
427
|
+
})
|
|
428
|
+
});
|
|
429
|
+
if (!createResp.ok) {
|
|
430
|
+
const body = await createResp.json().catch(() => null);
|
|
431
|
+
setErrorCode(createResp.status);
|
|
432
|
+
throw new Error(body?.detail || `Failed to create session: ${createResp.status}`);
|
|
433
|
+
}
|
|
434
|
+
const { session: session2 } = await createResp.json();
|
|
435
|
+
resolvedSessionId = session2.id;
|
|
371
436
|
}
|
|
372
|
-
const
|
|
373
|
-
const startResp = await fetch(`${API_URL3}/v1/sessions/${session.id}/start`, {
|
|
437
|
+
const startResp = await authedFetch(`${API_URL3}/v1/sessions/${resolvedSessionId}/start`, {
|
|
374
438
|
method: "POST",
|
|
375
|
-
|
|
376
|
-
|
|
439
|
+
headers: { "Content-Type": "application/json" },
|
|
440
|
+
body: JSON.stringify({ captureMode, agentControls: requestAgentControls })
|
|
377
441
|
});
|
|
378
442
|
if (!startResp.ok) {
|
|
379
443
|
const body = await startResp.json().catch(() => null);
|
|
380
444
|
setErrorCode(startResp.status);
|
|
381
445
|
throw new Error(body?.detail || `Failed to start session: ${startResp.status}`);
|
|
382
446
|
}
|
|
383
|
-
const { connection: conn } = await startResp.json();
|
|
447
|
+
const { session, connection: conn } = await startResp.json();
|
|
448
|
+
const history2 = existingSessionId ? await fetchSessionMessages(session.id, authedFetch) : [];
|
|
384
449
|
setSessionId(session.id);
|
|
385
|
-
setHistoryMessages(
|
|
450
|
+
setHistoryMessages(history2);
|
|
386
451
|
setConnection({
|
|
387
452
|
livekitUrl: conn.livekitUrl,
|
|
388
453
|
token: conn.token
|
|
@@ -397,16 +462,14 @@ function useSession({
|
|
|
397
462
|
} finally {
|
|
398
463
|
setIsStarting(false);
|
|
399
464
|
}
|
|
400
|
-
}, [captureMode, bearerToken, onStart, onStartError]);
|
|
465
|
+
}, [captureMode, bearerToken, authedFetch, onStart, onStartError]);
|
|
401
466
|
const pauseSession = useCallback3(async () => {
|
|
402
467
|
if (!sessionId || !bearerToken)
|
|
403
468
|
return;
|
|
404
469
|
setIsPausing(true);
|
|
405
470
|
try {
|
|
406
|
-
const resp = await
|
|
407
|
-
method: "POST"
|
|
408
|
-
credentials: "omit",
|
|
409
|
-
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
471
|
+
const resp = await authedFetch(`${API_URL3}/v1/sessions/${sessionId}/pause`, {
|
|
472
|
+
method: "POST"
|
|
410
473
|
});
|
|
411
474
|
if (!resp.ok) {
|
|
412
475
|
const body = await resp.json().catch(() => null);
|
|
@@ -417,7 +480,7 @@ function useSession({
|
|
|
417
480
|
setIsPausing(false);
|
|
418
481
|
return;
|
|
419
482
|
}
|
|
420
|
-
const history2 = await fetchSessionMessages(sessionId,
|
|
483
|
+
const history2 = await fetchSessionMessages(sessionId, authedFetch);
|
|
421
484
|
stopStream(pendingScreenStream);
|
|
422
485
|
setPendingScreenStream(null);
|
|
423
486
|
setShouldConnect(false);
|
|
@@ -425,64 +488,14 @@ function useSession({
|
|
|
425
488
|
setHistoryMessages(history2);
|
|
426
489
|
setIsPaused(true);
|
|
427
490
|
setIsPausing(false);
|
|
428
|
-
|
|
429
|
-
}, [sessionId, bearerToken, pendingScreenStream, refetchResumable]);
|
|
430
|
-
const resumeSession = useCallback3(async ({
|
|
431
|
-
sessionId: resumeId,
|
|
432
|
-
agentControls
|
|
433
|
-
}) => {
|
|
434
|
-
if (!bearerToken) {
|
|
435
|
-
setError("No auth token available");
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
setIsStarting(true);
|
|
439
|
-
setError("");
|
|
440
|
-
setErrorCode(null);
|
|
441
|
-
onStart?.();
|
|
442
|
-
let screenStream = null;
|
|
443
|
-
if (captureMode === "screenshare") {
|
|
444
|
-
screenStream = await requestScreenShare();
|
|
445
|
-
}
|
|
446
|
-
const requestAgentControls = agentControls?.highlight === true ? { highlight: true } : undefined;
|
|
447
|
-
try {
|
|
448
|
-
const resp = await fetch(`${API_URL3}/v1/sessions/${resumeId}/resume`, {
|
|
449
|
-
method: "POST",
|
|
450
|
-
credentials: "omit",
|
|
451
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearerToken}` },
|
|
452
|
-
body: JSON.stringify({ captureMode, agentControls: requestAgentControls })
|
|
453
|
-
});
|
|
454
|
-
if (!resp.ok) {
|
|
455
|
-
const body = await resp.json().catch(() => null);
|
|
456
|
-
setErrorCode(resp.status);
|
|
457
|
-
throw new Error(body?.detail || `Failed to resume: ${resp.status}`);
|
|
458
|
-
}
|
|
459
|
-
const { session, connection: conn } = await resp.json();
|
|
460
|
-
const history2 = await fetchSessionMessages(session.id, bearerToken);
|
|
461
|
-
setSessionId(session.id);
|
|
462
|
-
setConnection({ livekitUrl: conn.livekitUrl, token: conn.token });
|
|
463
|
-
setPendingScreenStream(screenStream);
|
|
464
|
-
setHistoryMessages(history2);
|
|
465
|
-
setShouldConnect(true);
|
|
466
|
-
setIsPaused(false);
|
|
467
|
-
setResumableSessions((prev) => prev.filter((s) => s.id !== resumeId));
|
|
468
|
-
} catch (e) {
|
|
469
|
-
stopStream(screenStream);
|
|
470
|
-
setError(e instanceof Error ? e.message : "Failed to resume session");
|
|
471
|
-
onStartError?.();
|
|
472
|
-
} finally {
|
|
473
|
-
setIsStarting(false);
|
|
474
|
-
}
|
|
475
|
-
}, [captureMode, bearerToken, onStart, onStartError]);
|
|
491
|
+
}, [sessionId, bearerToken, authedFetch, pendingScreenStream]);
|
|
476
492
|
const disconnect = useCallback3(async () => {
|
|
477
493
|
setIsDisconnecting(true);
|
|
478
494
|
try {
|
|
479
495
|
if (sessionId && bearerToken) {
|
|
480
496
|
try {
|
|
481
|
-
await
|
|
482
|
-
method: "POST"
|
|
483
|
-
credentials: "omit",
|
|
484
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearerToken}` },
|
|
485
|
-
body: JSON.stringify({})
|
|
497
|
+
await authedFetch(`${API_URL3}/v1/sessions/${sessionId}/pause`, {
|
|
498
|
+
method: "POST"
|
|
486
499
|
});
|
|
487
500
|
} catch {}
|
|
488
501
|
}
|
|
@@ -495,11 +508,10 @@ function useSession({
|
|
|
495
508
|
setHistoryMessages([]);
|
|
496
509
|
setIsPaused(false);
|
|
497
510
|
onDisconnect?.();
|
|
498
|
-
await refetchResumable();
|
|
499
511
|
} finally {
|
|
500
512
|
setIsDisconnecting(false);
|
|
501
513
|
}
|
|
502
|
-
}, [sessionId, bearerToken, pendingScreenStream, onDisconnect
|
|
514
|
+
}, [sessionId, bearerToken, authedFetch, pendingScreenStream, onDisconnect]);
|
|
503
515
|
return {
|
|
504
516
|
connection,
|
|
505
517
|
shouldConnect,
|
|
@@ -509,15 +521,14 @@ function useSession({
|
|
|
509
521
|
errorCode,
|
|
510
522
|
startSession,
|
|
511
523
|
pauseSession,
|
|
512
|
-
resumeSession,
|
|
513
524
|
disconnect,
|
|
514
525
|
isPaused,
|
|
515
526
|
isPausing,
|
|
516
|
-
resumableSessions,
|
|
517
527
|
historyMessages,
|
|
518
|
-
refetchResumable,
|
|
519
528
|
pendingScreenStream,
|
|
520
|
-
bearerToken
|
|
529
|
+
bearerToken,
|
|
530
|
+
authedFetch,
|
|
531
|
+
authFailed
|
|
521
532
|
};
|
|
522
533
|
}
|
|
523
534
|
|
|
@@ -531,6 +542,27 @@ var DOM_EVENTS_TOPIC = "skippr.dom-events";
|
|
|
531
542
|
var HIGHLIGHT_TOPIC = "skippr.highlight";
|
|
532
543
|
var NAME_MAX_CHARS = 80;
|
|
533
544
|
|
|
545
|
+
// src/lib/session.ts
|
|
546
|
+
function getResumableSessionId(currentSession, mode) {
|
|
547
|
+
if (!currentSession)
|
|
548
|
+
return;
|
|
549
|
+
const { id, status } = currentSession;
|
|
550
|
+
if (status === "paused" || status === "active")
|
|
551
|
+
return id;
|
|
552
|
+
if (status === "expired" && mode === "always_on")
|
|
553
|
+
return id;
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
function canResumeSession(currentSession, mode) {
|
|
557
|
+
return getResumableSessionId(currentSession, mode) !== undefined;
|
|
558
|
+
}
|
|
559
|
+
function getResumableSession(module) {
|
|
560
|
+
if (!module)
|
|
561
|
+
return null;
|
|
562
|
+
const id = getResumableSessionId(module.currentSession, module.mode);
|
|
563
|
+
return id ? { id, agentId: module.id } : null;
|
|
564
|
+
}
|
|
565
|
+
|
|
534
566
|
// src/components/AutoStartMedia.tsx
|
|
535
567
|
import { useConnectionState, useLocalParticipant } from "@livekit/components-react/hooks";
|
|
536
568
|
import { ConnectionState, Track } from "livekit-client";
|
|
@@ -1499,17 +1531,24 @@ var createLucideIcon = (iconName, iconNode) => {
|
|
|
1499
1531
|
return Component;
|
|
1500
1532
|
};
|
|
1501
1533
|
|
|
1502
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle-
|
|
1534
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle-alert.js
|
|
1503
1535
|
var __iconNode = [
|
|
1536
|
+
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
1537
|
+
["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
|
|
1538
|
+
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
1539
|
+
];
|
|
1540
|
+
var CircleAlert = createLucideIcon("circle-alert", __iconNode);
|
|
1541
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle-check.js
|
|
1542
|
+
var __iconNode2 = [
|
|
1504
1543
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
1505
1544
|
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
1506
1545
|
];
|
|
1507
|
-
var CircleCheck = createLucideIcon("circle-check",
|
|
1546
|
+
var CircleCheck = createLucideIcon("circle-check", __iconNode2);
|
|
1508
1547
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/loader-circle.js
|
|
1509
|
-
var
|
|
1510
|
-
var LoaderCircle = createLucideIcon("loader-circle",
|
|
1548
|
+
var __iconNode3 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
1549
|
+
var LoaderCircle = createLucideIcon("loader-circle", __iconNode3);
|
|
1511
1550
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/sparkles.js
|
|
1512
|
-
var
|
|
1551
|
+
var __iconNode4 = [
|
|
1513
1552
|
[
|
|
1514
1553
|
"path",
|
|
1515
1554
|
{
|
|
@@ -1521,9 +1560,9 @@ var __iconNode3 = [
|
|
|
1521
1560
|
["path", { d: "M22 4h-4", key: "gwowj6" }],
|
|
1522
1561
|
["circle", { cx: "4", cy: "20", r: "2", key: "6kqj1y" }]
|
|
1523
1562
|
];
|
|
1524
|
-
var Sparkles = createLucideIcon("sparkles",
|
|
1563
|
+
var Sparkles = createLucideIcon("sparkles", __iconNode4);
|
|
1525
1564
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/bot.js
|
|
1526
|
-
var
|
|
1565
|
+
var __iconNode5 = [
|
|
1527
1566
|
["path", { d: "M12 8V4H8", key: "hb8ula" }],
|
|
1528
1567
|
["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
|
|
1529
1568
|
["path", { d: "M2 14h2", key: "vft8re" }],
|
|
@@ -1531,23 +1570,23 @@ var __iconNode4 = [
|
|
|
1531
1570
|
["path", { d: "M15 13v2", key: "1xurst" }],
|
|
1532
1571
|
["path", { d: "M9 13v2", key: "rq6x2g" }]
|
|
1533
1572
|
];
|
|
1534
|
-
var Bot = createLucideIcon("bot",
|
|
1573
|
+
var Bot = createLucideIcon("bot", __iconNode5);
|
|
1535
1574
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/calendar.js
|
|
1536
|
-
var
|
|
1575
|
+
var __iconNode6 = [
|
|
1537
1576
|
["path", { d: "M8 2v4", key: "1cmpym" }],
|
|
1538
1577
|
["path", { d: "M16 2v4", key: "4m81vk" }],
|
|
1539
1578
|
["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
|
|
1540
1579
|
["path", { d: "M3 10h18", key: "8toen8" }]
|
|
1541
1580
|
];
|
|
1542
|
-
var Calendar = createLucideIcon("calendar",
|
|
1581
|
+
var Calendar = createLucideIcon("calendar", __iconNode6);
|
|
1543
1582
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/chevron-down.js
|
|
1544
|
-
var
|
|
1545
|
-
var ChevronDown = createLucideIcon("chevron-down",
|
|
1583
|
+
var __iconNode7 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
1584
|
+
var ChevronDown = createLucideIcon("chevron-down", __iconNode7);
|
|
1546
1585
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle.js
|
|
1547
|
-
var
|
|
1548
|
-
var Circle = createLucideIcon("circle",
|
|
1586
|
+
var __iconNode8 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
|
|
1587
|
+
var Circle = createLucideIcon("circle", __iconNode8);
|
|
1549
1588
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/graduation-cap.js
|
|
1550
|
-
var
|
|
1589
|
+
var __iconNode9 = [
|
|
1551
1590
|
[
|
|
1552
1591
|
"path",
|
|
1553
1592
|
{
|
|
@@ -1558,9 +1597,9 @@ var __iconNode8 = [
|
|
|
1558
1597
|
["path", { d: "M22 10v6", key: "1lu8f3" }],
|
|
1559
1598
|
["path", { d: "M6 12.5V16a6 3 0 0 0 12 0v-3.5", key: "1r8lef" }]
|
|
1560
1599
|
];
|
|
1561
|
-
var GraduationCap = createLucideIcon("graduation-cap",
|
|
1600
|
+
var GraduationCap = createLucideIcon("graduation-cap", __iconNode9);
|
|
1562
1601
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/headset.js
|
|
1563
|
-
var
|
|
1602
|
+
var __iconNode10 = [
|
|
1564
1603
|
[
|
|
1565
1604
|
"path",
|
|
1566
1605
|
{
|
|
@@ -1570,15 +1609,15 @@ var __iconNode9 = [
|
|
|
1570
1609
|
],
|
|
1571
1610
|
["path", { d: "M21 16v2a4 4 0 0 1-4 4h-5", key: "1x7m43" }]
|
|
1572
1611
|
];
|
|
1573
|
-
var Headset = createLucideIcon("headset",
|
|
1612
|
+
var Headset = createLucideIcon("headset", __iconNode10);
|
|
1574
1613
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mail.js
|
|
1575
|
-
var
|
|
1614
|
+
var __iconNode11 = [
|
|
1576
1615
|
["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
|
|
1577
1616
|
["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
|
|
1578
1617
|
];
|
|
1579
|
-
var Mail = createLucideIcon("mail",
|
|
1618
|
+
var Mail = createLucideIcon("mail", __iconNode11);
|
|
1580
1619
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/message-circle.js
|
|
1581
|
-
var
|
|
1620
|
+
var __iconNode12 = [
|
|
1582
1621
|
[
|
|
1583
1622
|
"path",
|
|
1584
1623
|
{
|
|
@@ -1587,9 +1626,9 @@ var __iconNode11 = [
|
|
|
1587
1626
|
}
|
|
1588
1627
|
]
|
|
1589
1628
|
];
|
|
1590
|
-
var MessageCircle = createLucideIcon("message-circle",
|
|
1629
|
+
var MessageCircle = createLucideIcon("message-circle", __iconNode12);
|
|
1591
1630
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/message-square.js
|
|
1592
|
-
var
|
|
1631
|
+
var __iconNode13 = [
|
|
1593
1632
|
[
|
|
1594
1633
|
"path",
|
|
1595
1634
|
{
|
|
@@ -1598,9 +1637,9 @@ var __iconNode12 = [
|
|
|
1598
1637
|
}
|
|
1599
1638
|
]
|
|
1600
1639
|
];
|
|
1601
|
-
var MessageSquare = createLucideIcon("message-square",
|
|
1640
|
+
var MessageSquare = createLucideIcon("message-square", __iconNode13);
|
|
1602
1641
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic-off.js
|
|
1603
|
-
var
|
|
1642
|
+
var __iconNode14 = [
|
|
1604
1643
|
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
1605
1644
|
["path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33", key: "1gzdoj" }],
|
|
1606
1645
|
["path", { d: "M16.95 16.95A7 7 0 0 1 5 12v-2", key: "cqa7eg" }],
|
|
@@ -1608,40 +1647,40 @@ var __iconNode13 = [
|
|
|
1608
1647
|
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
1609
1648
|
["path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12", key: "r2i35w" }]
|
|
1610
1649
|
];
|
|
1611
|
-
var MicOff = createLucideIcon("mic-off",
|
|
1650
|
+
var MicOff = createLucideIcon("mic-off", __iconNode14);
|
|
1612
1651
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic.js
|
|
1613
|
-
var
|
|
1652
|
+
var __iconNode15 = [
|
|
1614
1653
|
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
1615
1654
|
["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
|
|
1616
1655
|
["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
|
|
1617
1656
|
];
|
|
1618
|
-
var Mic = createLucideIcon("mic",
|
|
1657
|
+
var Mic = createLucideIcon("mic", __iconNode15);
|
|
1619
1658
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/minimize-2.js
|
|
1620
|
-
var
|
|
1659
|
+
var __iconNode16 = [
|
|
1621
1660
|
["path", { d: "m14 10 7-7", key: "oa77jy" }],
|
|
1622
1661
|
["path", { d: "M20 10h-6V4", key: "mjg0md" }],
|
|
1623
1662
|
["path", { d: "m3 21 7-7", key: "tjx5ai" }],
|
|
1624
1663
|
["path", { d: "M4 14h6v6", key: "rmj7iw" }]
|
|
1625
1664
|
];
|
|
1626
|
-
var Minimize2 = createLucideIcon("minimize-2",
|
|
1665
|
+
var Minimize2 = createLucideIcon("minimize-2", __iconNode16);
|
|
1627
1666
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor-off.js
|
|
1628
|
-
var
|
|
1667
|
+
var __iconNode17 = [
|
|
1629
1668
|
["path", { d: "M12 17v4", key: "1riwvh" }],
|
|
1630
1669
|
["path", { d: "M17 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 1.184-1.826", key: "cv7jms" }],
|
|
1631
1670
|
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
1632
1671
|
["path", { d: "M8 21h8", key: "1ev6f3" }],
|
|
1633
1672
|
["path", { d: "M8.656 3H20a2 2 0 0 1 2 2v10a2 2 0 0 1-.293 1.042", key: "z8ni2w" }]
|
|
1634
1673
|
];
|
|
1635
|
-
var MonitorOff = createLucideIcon("monitor-off",
|
|
1674
|
+
var MonitorOff = createLucideIcon("monitor-off", __iconNode17);
|
|
1636
1675
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor.js
|
|
1637
|
-
var
|
|
1676
|
+
var __iconNode18 = [
|
|
1638
1677
|
["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
|
|
1639
1678
|
["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
|
|
1640
1679
|
["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
|
|
1641
1680
|
];
|
|
1642
|
-
var Monitor = createLucideIcon("monitor",
|
|
1681
|
+
var Monitor = createLucideIcon("monitor", __iconNode18);
|
|
1643
1682
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mouse-pointer-2.js
|
|
1644
|
-
var
|
|
1683
|
+
var __iconNode19 = [
|
|
1645
1684
|
[
|
|
1646
1685
|
"path",
|
|
1647
1686
|
{
|
|
@@ -1650,15 +1689,15 @@ var __iconNode18 = [
|
|
|
1650
1689
|
}
|
|
1651
1690
|
]
|
|
1652
1691
|
];
|
|
1653
|
-
var MousePointer2 = createLucideIcon("mouse-pointer-2",
|
|
1692
|
+
var MousePointer2 = createLucideIcon("mouse-pointer-2", __iconNode19);
|
|
1654
1693
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/pause.js
|
|
1655
|
-
var
|
|
1694
|
+
var __iconNode20 = [
|
|
1656
1695
|
["rect", { x: "14", y: "3", width: "5", height: "18", rx: "1", key: "kaeet6" }],
|
|
1657
1696
|
["rect", { x: "5", y: "3", width: "5", height: "18", rx: "1", key: "1wsw3u" }]
|
|
1658
1697
|
];
|
|
1659
|
-
var Pause = createLucideIcon("pause",
|
|
1698
|
+
var Pause = createLucideIcon("pause", __iconNode20);
|
|
1660
1699
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/phone-off.js
|
|
1661
|
-
var
|
|
1700
|
+
var __iconNode21 = [
|
|
1662
1701
|
[
|
|
1663
1702
|
"path",
|
|
1664
1703
|
{
|
|
@@ -1675,9 +1714,9 @@ var __iconNode20 = [
|
|
|
1675
1714
|
}
|
|
1676
1715
|
]
|
|
1677
1716
|
];
|
|
1678
|
-
var PhoneOff = createLucideIcon("phone-off",
|
|
1717
|
+
var PhoneOff = createLucideIcon("phone-off", __iconNode21);
|
|
1679
1718
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/play.js
|
|
1680
|
-
var
|
|
1719
|
+
var __iconNode22 = [
|
|
1681
1720
|
[
|
|
1682
1721
|
"path",
|
|
1683
1722
|
{
|
|
@@ -1686,9 +1725,9 @@ var __iconNode21 = [
|
|
|
1686
1725
|
}
|
|
1687
1726
|
]
|
|
1688
1727
|
];
|
|
1689
|
-
var Play = createLucideIcon("play",
|
|
1728
|
+
var Play = createLucideIcon("play", __iconNode22);
|
|
1690
1729
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/rocket.js
|
|
1691
|
-
var
|
|
1730
|
+
var __iconNode23 = [
|
|
1692
1731
|
["path", { d: "M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5", key: "qeys4" }],
|
|
1693
1732
|
[
|
|
1694
1733
|
"path",
|
|
@@ -1706,9 +1745,9 @@ var __iconNode22 = [
|
|
|
1706
1745
|
],
|
|
1707
1746
|
["path", { d: "M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05", key: "92ym6u" }]
|
|
1708
1747
|
];
|
|
1709
|
-
var Rocket = createLucideIcon("rocket",
|
|
1748
|
+
var Rocket = createLucideIcon("rocket", __iconNode23);
|
|
1710
1749
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/send.js
|
|
1711
|
-
var
|
|
1750
|
+
var __iconNode24 = [
|
|
1712
1751
|
[
|
|
1713
1752
|
"path",
|
|
1714
1753
|
{
|
|
@@ -1718,15 +1757,15 @@ var __iconNode23 = [
|
|
|
1718
1757
|
],
|
|
1719
1758
|
["path", { d: "m21.854 2.147-10.94 10.939", key: "12cjpa" }]
|
|
1720
1759
|
];
|
|
1721
|
-
var Send = createLucideIcon("send",
|
|
1760
|
+
var Send = createLucideIcon("send", __iconNode24);
|
|
1722
1761
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/user-plus.js
|
|
1723
|
-
var
|
|
1762
|
+
var __iconNode25 = [
|
|
1724
1763
|
["path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2", key: "1yyitq" }],
|
|
1725
1764
|
["circle", { cx: "9", cy: "7", r: "4", key: "nufk8" }],
|
|
1726
1765
|
["line", { x1: "19", x2: "19", y1: "8", y2: "14", key: "1bvyxn" }],
|
|
1727
1766
|
["line", { x1: "22", x2: "16", y1: "11", y2: "11", key: "1shjgl" }]
|
|
1728
1767
|
];
|
|
1729
|
-
var UserPlus = createLucideIcon("user-plus",
|
|
1768
|
+
var UserPlus = createLucideIcon("user-plus", __iconNode25);
|
|
1730
1769
|
// src/components/HighlightOverlay.tsx
|
|
1731
1770
|
import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef4, useState as useState4 } from "react";
|
|
1732
1771
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1975,6 +2014,8 @@ function useLiveAgent() {
|
|
|
1975
2014
|
throw new Error("useLiveAgent must be used within a <LiveAgent> provider");
|
|
1976
2015
|
}
|
|
1977
2016
|
const {
|
|
2017
|
+
usesHostAuth,
|
|
2018
|
+
authFailed,
|
|
1978
2019
|
connection,
|
|
1979
2020
|
shouldConnect,
|
|
1980
2021
|
historyMessages,
|
|
@@ -3279,7 +3320,7 @@ function MessageList({
|
|
|
3279
3320
|
}
|
|
3280
3321
|
|
|
3281
3322
|
// src/components/ModuleSelector.tsx
|
|
3282
|
-
import { useEffect as useEffect15,
|
|
3323
|
+
import { useEffect as useEffect15, useRef as useRef9, useState as useState10 } from "react";
|
|
3283
3324
|
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3284
3325
|
var AGENT_TYPE_ICONS = {
|
|
3285
3326
|
onboarding: UserPlus,
|
|
@@ -3299,11 +3340,9 @@ function ModuleSelector() {
|
|
|
3299
3340
|
selectModule,
|
|
3300
3341
|
isStarting,
|
|
3301
3342
|
isDisconnecting,
|
|
3302
|
-
error
|
|
3303
|
-
resumableSessions
|
|
3343
|
+
error
|
|
3304
3344
|
} = useLiveAgent();
|
|
3305
3345
|
const isBusy = isStarting || isDisconnecting;
|
|
3306
|
-
const resumableAgentIds = useMemo5(() => new Set(resumableSessions.map((s) => s.agentId)), [resumableSessions]);
|
|
3307
3346
|
const scrollRef = useRef9(null);
|
|
3308
3347
|
const [showScrollHint, setShowScrollHint] = useState10(false);
|
|
3309
3348
|
const [isScrolled, setIsScrolled] = useState10(false);
|
|
@@ -3391,7 +3430,7 @@ function ModuleSelector() {
|
|
|
3391
3430
|
const isFeatured = index2 === 0;
|
|
3392
3431
|
const isWide = index2 === availableModules.length - 1 && availableModules.length % 2 === 1;
|
|
3393
3432
|
const Icon2 = getAgentIcon(module.type);
|
|
3394
|
-
const canResume =
|
|
3433
|
+
const canResume = canResumeSession(module.currentSession, module.mode);
|
|
3395
3434
|
const base = "skippr:group skippr:flex skippr:cursor-pointer skippr:gap-3 skippr:rounded-xl skippr:text-left skippr:transition-colors skippr:disabled:cursor-not-allowed skippr:disabled:opacity-50";
|
|
3396
3435
|
const layout = isWide ? "skippr:items-center skippr:p-3.5 skippr:pb-5" : "skippr:flex-col skippr:items-start skippr:p-3.5";
|
|
3397
3436
|
const variant = isFeatured ? "skippr:bg-primary skippr:text-primary-foreground skippr:hover:bg-primary/90" : "skippr:bg-background skippr:ring-1 skippr:ring-foreground/10 skippr:hover:bg-muted/50";
|
|
@@ -3597,8 +3636,13 @@ function Sidebar({
|
|
|
3597
3636
|
captureMode,
|
|
3598
3637
|
hasModuleSelector,
|
|
3599
3638
|
agentId,
|
|
3639
|
+
agentMode,
|
|
3600
3640
|
agentControls
|
|
3601
3641
|
} = useLiveAgent();
|
|
3642
|
+
const internalCtx = useContextValue(LiveAgentContext);
|
|
3643
|
+
const usesHostAuth = internalCtx?.usesHostAuth ?? false;
|
|
3644
|
+
const authFailed = internalCtx?.authFailed ?? false;
|
|
3645
|
+
const showAgenda = agentMode !== "always_on";
|
|
3602
3646
|
const isFloating = variant === "floating";
|
|
3603
3647
|
const isSidebar = variant === "sidebar";
|
|
3604
3648
|
useEffect16(() => {
|
|
@@ -3620,17 +3664,7 @@ function Sidebar({
|
|
|
3620
3664
|
style: { width: isPanelOpen ? SIDEBAR_WIDTH : undefined },
|
|
3621
3665
|
children: [
|
|
3622
3666
|
!hideHeader && /* @__PURE__ */ jsx18(ChatHeader, {}),
|
|
3623
|
-
|
|
3624
|
-
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
3625
|
-
children: /* @__PURE__ */ jsx18(LoadingDots, {
|
|
3626
|
-
label: "Loading..."
|
|
3627
|
-
})
|
|
3628
|
-
}) : !isAuthenticated ? /* @__PURE__ */ jsx18(LoginFlow, {
|
|
3629
|
-
requestOtp,
|
|
3630
|
-
verifyOtp,
|
|
3631
|
-
error: authError,
|
|
3632
|
-
isSubmitting: isAuthSubmitting
|
|
3633
|
-
}) : /* @__PURE__ */ jsx18(AuthenticatedContent, {
|
|
3667
|
+
authFailed ? /* @__PURE__ */ jsx18(AuthError, {}) : isAuthenticated ? /* @__PURE__ */ jsx18(AuthenticatedContent, {
|
|
3634
3668
|
isConnected,
|
|
3635
3669
|
isPaused,
|
|
3636
3670
|
isPausing,
|
|
@@ -3650,7 +3684,18 @@ function Sidebar({
|
|
|
3650
3684
|
showScreenShareToggle: captureMode === "screenshare",
|
|
3651
3685
|
hasModuleSelector,
|
|
3652
3686
|
agentId,
|
|
3653
|
-
agentControls
|
|
3687
|
+
agentControls,
|
|
3688
|
+
showAgenda
|
|
3689
|
+
}) : usesHostAuth || isValidating ? /* @__PURE__ */ jsx18("div", {
|
|
3690
|
+
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
3691
|
+
children: /* @__PURE__ */ jsx18(LoadingDots, {
|
|
3692
|
+
label: "Loading..."
|
|
3693
|
+
})
|
|
3694
|
+
}) : /* @__PURE__ */ jsx18(LoginFlow, {
|
|
3695
|
+
requestOtp,
|
|
3696
|
+
verifyOtp,
|
|
3697
|
+
error: authError,
|
|
3698
|
+
isSubmitting: isAuthSubmitting
|
|
3654
3699
|
})
|
|
3655
3700
|
]
|
|
3656
3701
|
});
|
|
@@ -3675,11 +3720,13 @@ function AuthenticatedContent({
|
|
|
3675
3720
|
showScreenShareToggle,
|
|
3676
3721
|
hasModuleSelector,
|
|
3677
3722
|
agentId,
|
|
3678
|
-
agentControls
|
|
3723
|
+
agentControls,
|
|
3724
|
+
showAgenda
|
|
3679
3725
|
}) {
|
|
3680
3726
|
const inSession = isConnected || isStarting || isPaused || isPausing;
|
|
3681
3727
|
const showSelectorAsPrompt = hasModuleSelector && !inSession && !isDisconnecting;
|
|
3682
3728
|
const showTabBar = !showSelectorAsPrompt;
|
|
3729
|
+
const effectiveTab = showAgenda ? activeTab : "chat";
|
|
3683
3730
|
let transitionLabel = null;
|
|
3684
3731
|
if (isPausing) {
|
|
3685
3732
|
transitionLabel = "Pausing...";
|
|
@@ -3708,7 +3755,7 @@ function AuthenticatedContent({
|
|
|
3708
3755
|
})
|
|
3709
3756
|
]
|
|
3710
3757
|
}),
|
|
3711
|
-
/* @__PURE__ */ jsxs16("button", {
|
|
3758
|
+
showAgenda && /* @__PURE__ */ jsxs16("button", {
|
|
3712
3759
|
type: "button",
|
|
3713
3760
|
className: cn("skippr:relative skippr:inline-flex skippr:cursor-pointer skippr:items-center skippr:gap-1.5 skippr:rounded-lg skippr:px-3 skippr:py-2 skippr:text-sm skippr:font-medium skippr:transition-all", activeTab === "agenda" ? "skippr:text-foreground" : "skippr:text-muted-foreground skippr:hover:text-foreground"),
|
|
3714
3761
|
onClick: () => onTabChange("agenda"),
|
|
@@ -3738,7 +3785,7 @@ function AuthenticatedContent({
|
|
|
3738
3785
|
children: transitionLabel
|
|
3739
3786
|
}),
|
|
3740
3787
|
/* @__PURE__ */ jsx18(ConnectedBody, {
|
|
3741
|
-
activeTab,
|
|
3788
|
+
activeTab: effectiveTab,
|
|
3742
3789
|
autoFocusChat
|
|
3743
3790
|
})
|
|
3744
3791
|
]
|
|
@@ -3767,6 +3814,24 @@ function AuthenticatedContent({
|
|
|
3767
3814
|
]
|
|
3768
3815
|
});
|
|
3769
3816
|
}
|
|
3817
|
+
function AuthError() {
|
|
3818
|
+
return /* @__PURE__ */ jsxs16("div", {
|
|
3819
|
+
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:justify-center skippr:px-6 skippr:py-4 skippr:text-center",
|
|
3820
|
+
children: [
|
|
3821
|
+
/* @__PURE__ */ jsx18(CircleAlert, {
|
|
3822
|
+
className: "skippr:mb-3 skippr:size-7 skippr:text-destructive"
|
|
3823
|
+
}),
|
|
3824
|
+
/* @__PURE__ */ jsx18("p", {
|
|
3825
|
+
className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
|
|
3826
|
+
children: "We couldn't verify your session"
|
|
3827
|
+
}),
|
|
3828
|
+
/* @__PURE__ */ jsx18("p", {
|
|
3829
|
+
className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
|
|
3830
|
+
children: "Please contact administrator."
|
|
3831
|
+
})
|
|
3832
|
+
]
|
|
3833
|
+
});
|
|
3834
|
+
}
|
|
3770
3835
|
function ConnectedBanner() {
|
|
3771
3836
|
const remaining = useSessionRemaining();
|
|
3772
3837
|
return /* @__PURE__ */ jsx18(SessionWarningBanner, {
|
|
@@ -3828,6 +3893,7 @@ function LiveAgent(props) {
|
|
|
3828
3893
|
agentId: hostAgentId,
|
|
3829
3894
|
authToken: authTokenProp,
|
|
3830
3895
|
appKey,
|
|
3896
|
+
getUserToken,
|
|
3831
3897
|
userToken,
|
|
3832
3898
|
position = "right",
|
|
3833
3899
|
variant = "floating",
|
|
@@ -3850,7 +3916,8 @@ function LiveAgent(props) {
|
|
|
3850
3916
|
}
|
|
3851
3917
|
}
|
|
3852
3918
|
const auth = useAuth({ appKey });
|
|
3853
|
-
const
|
|
3919
|
+
const usesHostAuth = !!getUserToken || !!userToken || !!authTokenProp;
|
|
3920
|
+
const effectiveAuthToken = usesHostAuth ? authTokenProp : auth.authToken ?? undefined;
|
|
3854
3921
|
const hasModuleSelector = !hostAgentId;
|
|
3855
3922
|
const [activeModule, setActiveModule] = useState11(null);
|
|
3856
3923
|
const agentId = hasModuleSelector ? activeModule?.id ?? null : hostAgentId;
|
|
@@ -3884,17 +3951,18 @@ function LiveAgent(props) {
|
|
|
3884
3951
|
errorCode,
|
|
3885
3952
|
startSession,
|
|
3886
3953
|
pauseSession,
|
|
3887
|
-
resumeSession: resumeSessionById,
|
|
3888
3954
|
disconnect,
|
|
3889
3955
|
isPaused,
|
|
3890
|
-
resumableSessions,
|
|
3891
3956
|
historyMessages,
|
|
3892
3957
|
pendingScreenStream,
|
|
3893
|
-
bearerToken
|
|
3958
|
+
bearerToken,
|
|
3959
|
+
authedFetch,
|
|
3960
|
+
authFailed
|
|
3894
3961
|
} = useSession({
|
|
3895
3962
|
captureMode,
|
|
3896
3963
|
authToken: effectiveAuthToken,
|
|
3897
3964
|
appKey,
|
|
3965
|
+
getUserToken,
|
|
3898
3966
|
userToken,
|
|
3899
3967
|
onStart: minimizeOnSessionStart,
|
|
3900
3968
|
onStartError: expandOnSessionStartError,
|
|
@@ -3907,12 +3975,6 @@ function LiveAgent(props) {
|
|
|
3907
3975
|
return;
|
|
3908
3976
|
disconnect();
|
|
3909
3977
|
}, [disconnect]);
|
|
3910
|
-
const resumableSession = resumableSessions.find((s) => s.agentId === agentId) ?? null;
|
|
3911
|
-
const resumeSession = useCallback8(async () => {
|
|
3912
|
-
if (!resumableSession)
|
|
3913
|
-
return;
|
|
3914
|
-
await resumeSessionById({ sessionId: resumableSession.id, agentControls });
|
|
3915
|
-
}, [resumableSession, resumeSessionById, agentControls]);
|
|
3916
3978
|
const [isPanelOpen, setIsPanelOpen] = useState11(defaultOpen);
|
|
3917
3979
|
const [isMinimized, setIsMinimized] = useState11(minimizable && !defaultOpen);
|
|
3918
3980
|
const [sidebarTab, setSidebarTab] = useState11("agenda");
|
|
@@ -3924,20 +3986,38 @@ function LiveAgent(props) {
|
|
|
3924
3986
|
refetch: refetchModules
|
|
3925
3987
|
} = useAvailableModules({
|
|
3926
3988
|
enabled: hasModuleSelector && isPanelOpen,
|
|
3927
|
-
bearerToken
|
|
3989
|
+
bearerToken,
|
|
3990
|
+
authedFetch
|
|
3928
3991
|
});
|
|
3992
|
+
const activeModuleForAgent = useMemo5(() => {
|
|
3993
|
+
if (activeModule)
|
|
3994
|
+
return activeModule;
|
|
3995
|
+
if (!hostAgentId)
|
|
3996
|
+
return null;
|
|
3997
|
+
return availableModules.find((m) => m.id === hostAgentId) ?? null;
|
|
3998
|
+
}, [activeModule, hostAgentId, availableModules]);
|
|
3999
|
+
const agentMode = activeModuleForAgent?.mode ?? null;
|
|
4000
|
+
const resumableSession = useMemo5(() => getResumableSession(activeModuleForAgent), [activeModuleForAgent]);
|
|
4001
|
+
const resumeSession = useCallback8(async () => {
|
|
4002
|
+
if (!resumableSession)
|
|
4003
|
+
return;
|
|
4004
|
+
await startSession({
|
|
4005
|
+
agentId: resumableSession.agentId,
|
|
4006
|
+
agentControls,
|
|
4007
|
+
existingSessionId: resumableSession.id
|
|
4008
|
+
});
|
|
4009
|
+
}, [resumableSession, startSession, agentControls]);
|
|
3929
4010
|
const selectModule = useCallback8((moduleId) => {
|
|
3930
4011
|
const found = availableModules.find((m) => m.id === moduleId);
|
|
3931
4012
|
if (!found)
|
|
3932
4013
|
return;
|
|
3933
4014
|
setActiveModule(found);
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
}, [availableModules, resumableSessions, startSession, resumeSessionById]);
|
|
4015
|
+
startSession({
|
|
4016
|
+
agentId: found.id,
|
|
4017
|
+
agentControls: found.controls,
|
|
4018
|
+
existingSessionId: getResumableSessionId(found.currentSession, found.mode)
|
|
4019
|
+
});
|
|
4020
|
+
}, [availableModules, startSession]);
|
|
3941
4021
|
const [welcomeDismissed, setWelcomeDismissed] = useState11(false);
|
|
3942
4022
|
const dismissWelcome = useCallback8(() => setWelcomeDismissed(true), []);
|
|
3943
4023
|
const [currentPosition, setCurrentPosition] = useState11(() => {
|
|
@@ -3968,8 +4048,8 @@ function LiveAgent(props) {
|
|
|
3968
4048
|
setIsPanelOpen(false);
|
|
3969
4049
|
}, [minimizable]);
|
|
3970
4050
|
const isConnected = connection !== null;
|
|
3971
|
-
const isAuthenticated =
|
|
3972
|
-
const ctx =
|
|
4051
|
+
const isAuthenticated = bearerToken !== null || auth.isAuthenticated;
|
|
4052
|
+
const ctx = useMemo5(() => ({
|
|
3973
4053
|
connection,
|
|
3974
4054
|
shouldConnect,
|
|
3975
4055
|
isConnected,
|
|
@@ -3984,7 +4064,6 @@ function LiveAgent(props) {
|
|
|
3984
4064
|
disconnect,
|
|
3985
4065
|
isPaused,
|
|
3986
4066
|
resumableSession,
|
|
3987
|
-
resumableSessions,
|
|
3988
4067
|
historyMessages,
|
|
3989
4068
|
phasesSnapshot,
|
|
3990
4069
|
setPhasesSnapshot,
|
|
@@ -4000,6 +4079,8 @@ function LiveAgent(props) {
|
|
|
4000
4079
|
expandPanel,
|
|
4001
4080
|
minimizePanel,
|
|
4002
4081
|
isAuthenticated,
|
|
4082
|
+
usesHostAuth,
|
|
4083
|
+
authFailed,
|
|
4003
4084
|
isValidating: auth.isValidating,
|
|
4004
4085
|
authError: auth.error,
|
|
4005
4086
|
requestOtp: auth.requestOtp,
|
|
@@ -4011,6 +4092,7 @@ function LiveAgent(props) {
|
|
|
4011
4092
|
autoFocusChat,
|
|
4012
4093
|
captureMode,
|
|
4013
4094
|
agentId,
|
|
4095
|
+
agentMode,
|
|
4014
4096
|
agentControls,
|
|
4015
4097
|
hasModuleSelector,
|
|
4016
4098
|
availableModules,
|
|
@@ -4034,7 +4116,6 @@ function LiveAgent(props) {
|
|
|
4034
4116
|
disconnect,
|
|
4035
4117
|
isPaused,
|
|
4036
4118
|
resumableSession,
|
|
4037
|
-
resumableSessions,
|
|
4038
4119
|
historyMessages,
|
|
4039
4120
|
phasesSnapshot,
|
|
4040
4121
|
isPanelOpen,
|
|
@@ -4049,6 +4130,8 @@ function LiveAgent(props) {
|
|
|
4049
4130
|
expandPanel,
|
|
4050
4131
|
minimizePanel,
|
|
4051
4132
|
isAuthenticated,
|
|
4133
|
+
usesHostAuth,
|
|
4134
|
+
authFailed,
|
|
4052
4135
|
auth.isValidating,
|
|
4053
4136
|
auth.error,
|
|
4054
4137
|
auth.requestOtp,
|
|
@@ -4059,6 +4142,7 @@ function LiveAgent(props) {
|
|
|
4059
4142
|
autoFocusChat,
|
|
4060
4143
|
captureMode,
|
|
4061
4144
|
agentId,
|
|
4145
|
+
agentMode,
|
|
4062
4146
|
agentControls,
|
|
4063
4147
|
hasModuleSelector,
|
|
4064
4148
|
availableModules,
|