@burdenoff/website-sdk 2026.828.7 → 2026.829.2
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/components/explore.js +567 -200
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +569 -202
- package/dist/components/explore.mjs.map +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +139 -69
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +139 -69
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +567 -200
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +567 -200
- package/dist/index.mjs.map +1 -1
- package/dist/{use-explore-chat-DhvZhH8f.d.mts → use-explore-chat-8eL7WdLc.d.mts} +16 -2
- package/dist/{use-explore-chat-DhvZhH8f.d.ts → use-explore-chat-8eL7WdLc.d.ts} +16 -2
- package/package.json +1 -1
package/dist/hooks/index.mjs
CHANGED
|
@@ -242,6 +242,7 @@ var EXPLORE_MESSAGE_FIELDS = (
|
|
|
242
242
|
description
|
|
243
243
|
product
|
|
244
244
|
imageUrl
|
|
245
|
+
index
|
|
245
246
|
}
|
|
246
247
|
ctas {
|
|
247
248
|
kind
|
|
@@ -249,6 +250,8 @@ var EXPLORE_MESSAGE_FIELDS = (
|
|
|
249
250
|
url
|
|
250
251
|
product
|
|
251
252
|
}
|
|
253
|
+
followUps
|
|
254
|
+
answered
|
|
252
255
|
errorCode
|
|
253
256
|
createdAt
|
|
254
257
|
completedAt
|
|
@@ -314,6 +317,16 @@ var SEND_EXPLORE_MESSAGE_MUTATION = (
|
|
|
314
317
|
}
|
|
315
318
|
`
|
|
316
319
|
);
|
|
320
|
+
var RECORD_EXPLORE_CLICK_MUTATION = (
|
|
321
|
+
/* GraphQL */
|
|
322
|
+
`
|
|
323
|
+
mutation RecordExploreClick($input: RecordExploreClickInput!) {
|
|
324
|
+
recordExploreClick(input: $input) {
|
|
325
|
+
recorded
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
`
|
|
329
|
+
);
|
|
317
330
|
|
|
318
331
|
// src/data/products.ts
|
|
319
332
|
var ECOSYSTEM_PRODUCTS = [
|
|
@@ -1246,6 +1259,20 @@ function useExploreChat(options = {}) {
|
|
|
1246
1259
|
return null;
|
|
1247
1260
|
}, [messages]);
|
|
1248
1261
|
const canSend = (phase === "ready" || phase === "error") && catalog.enabled && turnCount < catalog.limits.maxTurnsPerConversation;
|
|
1262
|
+
const recordClick = useCallback(
|
|
1263
|
+
(messageId, kind, url) => {
|
|
1264
|
+
const token = conversationTokenRef.current;
|
|
1265
|
+
if (!token) return;
|
|
1266
|
+
try {
|
|
1267
|
+
void client.mutate(RECORD_EXPLORE_CLICK_MUTATION, {
|
|
1268
|
+
input: { conversationToken: token, messageId, kind, url }
|
|
1269
|
+
}).catch(() => {
|
|
1270
|
+
});
|
|
1271
|
+
} catch {
|
|
1272
|
+
}
|
|
1273
|
+
},
|
|
1274
|
+
[client]
|
|
1275
|
+
);
|
|
1249
1276
|
return {
|
|
1250
1277
|
phase,
|
|
1251
1278
|
catalog,
|
|
@@ -1263,7 +1290,8 @@ function useExploreChat(options = {}) {
|
|
|
1263
1290
|
history: archive,
|
|
1264
1291
|
openConversation,
|
|
1265
1292
|
deleteConversation,
|
|
1266
|
-
clearHistory
|
|
1293
|
+
clearHistory,
|
|
1294
|
+
recordClick
|
|
1267
1295
|
};
|
|
1268
1296
|
}
|
|
1269
1297
|
var optimisticCounter = 0;
|
|
@@ -1276,21 +1304,37 @@ function getRecognitionCtor() {
|
|
|
1276
1304
|
const w = window;
|
|
1277
1305
|
return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;
|
|
1278
1306
|
}
|
|
1307
|
+
function isTouchDevice() {
|
|
1308
|
+
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
1309
|
+
try {
|
|
1310
|
+
return window.matchMedia("(pointer: coarse)").matches;
|
|
1311
|
+
} catch {
|
|
1312
|
+
return false;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1279
1315
|
var MIC_DENIED_MESSAGE = "Microphone access was blocked. Allow it in your browser's site settings to dictate.";
|
|
1316
|
+
var MIC_UNAVAILABLE_MESSAGE = "Dictation isn't available in this browser. You can type instead.";
|
|
1317
|
+
var RELEASE_SETTLE_MS = 250;
|
|
1318
|
+
var RETRY_DELAY_MS = 350;
|
|
1319
|
+
var sleep = (ms) => new Promise((resolve) => {
|
|
1320
|
+
setTimeout(resolve, ms);
|
|
1321
|
+
});
|
|
1280
1322
|
async function ensureMicrophoneAccess() {
|
|
1281
1323
|
const media = typeof navigator === "undefined" ? void 0 : navigator.mediaDevices;
|
|
1282
|
-
if (!media?.getUserMedia)
|
|
1324
|
+
if (!media?.getUserMedia)
|
|
1325
|
+
return { ok: true, confirmed: false, primed: false };
|
|
1283
1326
|
try {
|
|
1284
1327
|
const status = await navigator.permissions?.query({
|
|
1285
1328
|
name: "microphone"
|
|
1286
1329
|
});
|
|
1287
|
-
if (status?.state === "granted")
|
|
1330
|
+
if (status?.state === "granted")
|
|
1331
|
+
return { ok: true, confirmed: true, primed: false };
|
|
1288
1332
|
} catch {
|
|
1289
1333
|
}
|
|
1290
1334
|
try {
|
|
1291
1335
|
const stream = await media.getUserMedia({ audio: true });
|
|
1292
1336
|
for (const track of stream.getTracks()) track.stop();
|
|
1293
|
-
return { ok: true, confirmed: true };
|
|
1337
|
+
return { ok: true, confirmed: true, primed: true };
|
|
1294
1338
|
} catch (error) {
|
|
1295
1339
|
const name = typeof error === "object" && error !== null && "name" in error ? String(error.name) : "";
|
|
1296
1340
|
if (name === "NotAllowedError" || name === "SecurityError") {
|
|
@@ -1334,19 +1378,17 @@ function useSpeechInput({
|
|
|
1334
1378
|
const recognitionRef = useRef(null);
|
|
1335
1379
|
const startTokenRef = useRef(0);
|
|
1336
1380
|
const micConfirmedRef = useRef(false);
|
|
1337
|
-
const
|
|
1338
|
-
const
|
|
1339
|
-
(Ctor, token) => {
|
|
1340
|
-
beginRecognitionRef.current?.(Ctor, token);
|
|
1341
|
-
},
|
|
1342
|
-
[]
|
|
1343
|
-
);
|
|
1381
|
+
const wantsListeningRef = useRef(false);
|
|
1382
|
+
const retriedRef = useRef(false);
|
|
1344
1383
|
const finalRef = useRef(onFinalTranscript);
|
|
1345
1384
|
const errorRef = useRef(onError);
|
|
1346
1385
|
finalRef.current = onFinalTranscript;
|
|
1347
1386
|
errorRef.current = onError;
|
|
1387
|
+
const langRef = useRef(lang);
|
|
1388
|
+
langRef.current = lang;
|
|
1348
1389
|
const stop = useCallback(() => {
|
|
1349
1390
|
startTokenRef.current += 1;
|
|
1391
|
+
wantsListeningRef.current = false;
|
|
1350
1392
|
setListening(false);
|
|
1351
1393
|
setInterim("");
|
|
1352
1394
|
const recognition = recognitionRef.current;
|
|
@@ -1355,83 +1397,111 @@ function useSpeechInput({
|
|
|
1355
1397
|
recognition.stop();
|
|
1356
1398
|
} catch {
|
|
1357
1399
|
}
|
|
1358
|
-
setListening(false);
|
|
1359
|
-
setInterim("");
|
|
1360
1400
|
}, []);
|
|
1361
|
-
const
|
|
1401
|
+
const openSession = useCallback((token) => {
|
|
1362
1402
|
const Ctor = getRecognitionCtor();
|
|
1363
|
-
if (!Ctor) return;
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1403
|
+
if (!Ctor || token !== startTokenRef.current) return;
|
|
1404
|
+
const recognition = new Ctor();
|
|
1405
|
+
recognition.lang = langRef.current ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
|
|
1406
|
+
recognition.continuous = !isTouchDevice();
|
|
1407
|
+
recognition.interimResults = true;
|
|
1408
|
+
recognition.maxAlternatives = 1;
|
|
1409
|
+
recognition.onstart = () => {
|
|
1410
|
+
if (token !== startTokenRef.current) return;
|
|
1411
|
+
setError(null);
|
|
1412
|
+
setListening(true);
|
|
1413
|
+
};
|
|
1414
|
+
recognition.onresult = (event) => {
|
|
1415
|
+
if (token !== startTokenRef.current) return;
|
|
1416
|
+
let settled = "";
|
|
1417
|
+
let pending = "";
|
|
1418
|
+
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
1419
|
+
const result = event.results[i];
|
|
1420
|
+
if (!result) continue;
|
|
1421
|
+
const text = result[0]?.transcript ?? "";
|
|
1422
|
+
if (result.isFinal) settled += text;
|
|
1423
|
+
else pending += text;
|
|
1424
|
+
}
|
|
1425
|
+
setInterim(pending);
|
|
1426
|
+
if (settled.trim() !== "") finalRef.current(settled);
|
|
1427
|
+
};
|
|
1428
|
+
recognition.onerror = (event) => {
|
|
1429
|
+
if (token !== startTokenRef.current) return;
|
|
1430
|
+
if ((event.error === "not-allowed" || event.error === "service-not-allowed") && micConfirmedRef.current && !retriedRef.current) {
|
|
1431
|
+
retriedRef.current = true;
|
|
1432
|
+
void sleep(RETRY_DELAY_MS).then(() => {
|
|
1433
|
+
if (token !== startTokenRef.current || !wantsListeningRef.current)
|
|
1434
|
+
return;
|
|
1435
|
+
openSessionRef.current?.(token);
|
|
1436
|
+
});
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
const message = micConfirmedRef.current && (event.error === "not-allowed" || event.error === "service-not-allowed") ? MIC_UNAVAILABLE_MESSAGE : describeError(event.error);
|
|
1440
|
+
wantsListeningRef.current = false;
|
|
1441
|
+
setListening(false);
|
|
1442
|
+
setInterim("");
|
|
1443
|
+
if (message !== "") {
|
|
1444
|
+
setError(message);
|
|
1445
|
+
errorRef.current?.(message);
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
recognition.onend = () => {
|
|
1449
|
+
if (token !== startTokenRef.current) return;
|
|
1450
|
+
setInterim("");
|
|
1451
|
+
if (wantsListeningRef.current && isTouchDevice()) {
|
|
1452
|
+
void sleep(120).then(() => {
|
|
1453
|
+
if (token !== startTokenRef.current || !wantsListeningRef.current)
|
|
1454
|
+
return;
|
|
1455
|
+
openSessionRef.current?.(token);
|
|
1456
|
+
});
|
|
1457
|
+
return;
|
|
1458
|
+
}
|
|
1459
|
+
setListening(false);
|
|
1460
|
+
};
|
|
1461
|
+
recognitionRef.current = recognition;
|
|
1462
|
+
try {
|
|
1463
|
+
recognition.start();
|
|
1464
|
+
} catch {
|
|
1465
|
+
wantsListeningRef.current = false;
|
|
1466
|
+
setListening(false);
|
|
1467
|
+
}
|
|
1468
|
+
}, []);
|
|
1469
|
+
const openSessionRef = useRef(null);
|
|
1470
|
+
openSessionRef.current = openSession;
|
|
1471
|
+
const start = useCallback(() => {
|
|
1472
|
+
if (!getRecognitionCtor()) return;
|
|
1367
1473
|
startTokenRef.current += 1;
|
|
1368
1474
|
const token = startTokenRef.current;
|
|
1369
|
-
|
|
1475
|
+
wantsListeningRef.current = true;
|
|
1476
|
+
retriedRef.current = false;
|
|
1477
|
+
micConfirmedRef.current = false;
|
|
1478
|
+
setError(null);
|
|
1479
|
+
setListening(true);
|
|
1480
|
+
void ensureMicrophoneAccess().then(async (access) => {
|
|
1370
1481
|
if (token !== startTokenRef.current) return;
|
|
1371
|
-
micConfirmedRef.current = access.ok && access.confirmed;
|
|
1372
1482
|
if (!access.ok) {
|
|
1483
|
+
wantsListeningRef.current = false;
|
|
1373
1484
|
setListening(false);
|
|
1374
1485
|
setError(access.message);
|
|
1375
1486
|
errorRef.current?.(access.message);
|
|
1376
1487
|
return;
|
|
1377
1488
|
}
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
const beginRecognitionImpl = useCallback(
|
|
1382
|
-
(Ctor, token) => {
|
|
1383
|
-
const recognition = new Ctor();
|
|
1384
|
-
recognition.lang = lang ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
|
|
1385
|
-
recognition.continuous = true;
|
|
1386
|
-
recognition.interimResults = true;
|
|
1387
|
-
recognition.maxAlternatives = 1;
|
|
1388
|
-
recognition.onstart = () => {
|
|
1489
|
+
micConfirmedRef.current = access.confirmed;
|
|
1490
|
+
if (access.primed) {
|
|
1491
|
+
await sleep(RELEASE_SETTLE_MS);
|
|
1389
1492
|
if (token !== startTokenRef.current) return;
|
|
1390
|
-
setError(null);
|
|
1391
|
-
setListening(true);
|
|
1392
|
-
};
|
|
1393
|
-
recognition.onresult = (event) => {
|
|
1394
|
-
let settled = "";
|
|
1395
|
-
let pending = "";
|
|
1396
|
-
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
1397
|
-
const result = event.results[i];
|
|
1398
|
-
if (!result) continue;
|
|
1399
|
-
const text = result[0]?.transcript ?? "";
|
|
1400
|
-
if (result.isFinal) settled += text;
|
|
1401
|
-
else pending += text;
|
|
1402
|
-
}
|
|
1403
|
-
setInterim(pending);
|
|
1404
|
-
if (settled.trim() !== "") finalRef.current(settled);
|
|
1405
|
-
};
|
|
1406
|
-
recognition.onerror = (event) => {
|
|
1407
|
-
const message = micConfirmedRef.current && (event.error === "not-allowed" || event.error === "service-not-allowed") ? "Dictation isn't available in this browser. You can type instead." : describeError(event.error);
|
|
1408
|
-
setListening(false);
|
|
1409
|
-
setInterim("");
|
|
1410
|
-
if (message !== "") {
|
|
1411
|
-
setError(message);
|
|
1412
|
-
errorRef.current?.(message);
|
|
1413
|
-
}
|
|
1414
|
-
};
|
|
1415
|
-
recognition.onend = () => {
|
|
1416
|
-
setListening(false);
|
|
1417
|
-
setInterim("");
|
|
1418
|
-
};
|
|
1419
|
-
recognitionRef.current = recognition;
|
|
1420
|
-
try {
|
|
1421
|
-
recognition.start();
|
|
1422
|
-
} catch {
|
|
1423
|
-
setListening(false);
|
|
1424
1493
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
);
|
|
1428
|
-
beginRecognitionRef.current = beginRecognitionImpl;
|
|
1494
|
+
openSessionRef.current?.(token);
|
|
1495
|
+
});
|
|
1496
|
+
}, []);
|
|
1429
1497
|
const toggle = useCallback(() => {
|
|
1430
1498
|
if (listening) stop();
|
|
1431
1499
|
else start();
|
|
1432
1500
|
}, [listening, start, stop]);
|
|
1433
1501
|
useEffect(
|
|
1434
1502
|
() => () => {
|
|
1503
|
+
startTokenRef.current += 1;
|
|
1504
|
+
wantsListeningRef.current = false;
|
|
1435
1505
|
const recognition = recognitionRef.current;
|
|
1436
1506
|
if (!recognition) return;
|
|
1437
1507
|
recognition.onresult = null;
|