@burdenoff/website-sdk 2026.922.5 → 2026.923.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.d.mts +4 -180
- package/dist/components/explore.d.ts +4 -180
- package/dist/components/explore.js +1458 -927
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +1225 -694
- package/dist/components/explore.mjs.map +1 -1
- package/dist/explore-D25zoXy9.d.mts +240 -0
- package/dist/explore-I4QnY4J9.d.ts +240 -0
- package/dist/{explore-types-DvQPiL1t.d.mts → explore-types-B5sdOC5M.d.mts} +75 -2
- package/dist/{explore-types-DvQPiL1t.d.ts → explore-types-B5sdOC5M.d.ts} +75 -2
- package/dist/hooks/index.d.mts +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +125 -8
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +125 -8
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +418 -26
- package/dist/index.d.ts +418 -26
- package/dist/index.js +2522 -748
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2499 -750
- package/dist/index.mjs.map +1 -1
- package/dist/{use-progressive-reveal-Ha3gYPfs.d.mts → use-progressive-reveal-Cmy8bA7L.d.mts} +54 -7
- package/dist/{use-progressive-reveal-BfU_IHip.d.ts → use-progressive-reveal-DHPGGxZu.d.ts} +54 -7
- package/dist/utils/index.d.mts +55 -1
- package/dist/utils/index.d.ts +55 -1
- package/dist/utils/index.js +17 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +14 -1
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/hooks/index.mjs
CHANGED
|
@@ -224,6 +224,10 @@ function useWebSDK() {
|
|
|
224
224
|
}
|
|
225
225
|
return client;
|
|
226
226
|
}
|
|
227
|
+
function useWebSDKConfig() {
|
|
228
|
+
const client = useWebSDK();
|
|
229
|
+
return client.getConfig();
|
|
230
|
+
}
|
|
227
231
|
|
|
228
232
|
// src/components/explore-types.ts
|
|
229
233
|
var EXPLORE_MESSAGE_FIELDS = (
|
|
@@ -383,6 +387,22 @@ var SUBMIT_EXPLORE_FEEDBACK_MUTATION = (
|
|
|
383
387
|
}
|
|
384
388
|
`
|
|
385
389
|
);
|
|
390
|
+
var ESCALATE_EXPLORE_CONVERSATION_MUTATION = (
|
|
391
|
+
/* GraphQL */
|
|
392
|
+
`
|
|
393
|
+
mutation EscalateExploreConversation(
|
|
394
|
+
$input: EscalateExploreConversationInput!
|
|
395
|
+
) {
|
|
396
|
+
escalateExploreConversation(input: $input) {
|
|
397
|
+
created
|
|
398
|
+
escalation {
|
|
399
|
+
email
|
|
400
|
+
createdAt
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
`
|
|
405
|
+
);
|
|
386
406
|
var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
|
|
387
407
|
/* GraphQL */
|
|
388
408
|
`
|
|
@@ -749,6 +769,25 @@ var VALIDATION_CODES = /* @__PURE__ */ new Set([
|
|
|
749
769
|
"CONVERSATION_LIMIT",
|
|
750
770
|
"INVALID_INPUT"
|
|
751
771
|
]);
|
|
772
|
+
function escalateOutcomeForCode(code) {
|
|
773
|
+
switch (code) {
|
|
774
|
+
case "INVALID_EMAIL":
|
|
775
|
+
return "invalid-email";
|
|
776
|
+
case "RATE_LIMITED":
|
|
777
|
+
case "HTTP_429":
|
|
778
|
+
return "rate-limited";
|
|
779
|
+
case "CAPTCHA_REQUIRED":
|
|
780
|
+
case "CAPTCHA_FAILED":
|
|
781
|
+
return "captcha";
|
|
782
|
+
// The token owns nothing, or owns a different conversation. The server answers NOT_FOUND
|
|
783
|
+
// rather than FORBIDDEN so the endpoint is not an oracle for whether a thread exists;
|
|
784
|
+
// either way there is nothing this visitor can do about it, so it reads as a failure.
|
|
785
|
+
case "NOT_FOUND":
|
|
786
|
+
return "failed";
|
|
787
|
+
default:
|
|
788
|
+
return "failed";
|
|
789
|
+
}
|
|
790
|
+
}
|
|
752
791
|
function classifyExploreError(code, serverMessage) {
|
|
753
792
|
const c = code ?? "UNKNOWN";
|
|
754
793
|
if (RATE_LIMIT_CODES.has(c)) {
|
|
@@ -915,6 +954,7 @@ function useExploreChat(options = {}) {
|
|
|
915
954
|
onSend
|
|
916
955
|
} = options;
|
|
917
956
|
const client = useWebSDK();
|
|
957
|
+
const { productId } = useWebSDKConfig();
|
|
918
958
|
const promptKey = JSON.stringify(examplePrompts ?? []);
|
|
919
959
|
const welcomeKey = JSON.stringify(fallbackWelcome ?? null);
|
|
920
960
|
const fallbackCatalog = useMemo(
|
|
@@ -938,6 +978,7 @@ function useExploreChat(options = {}) {
|
|
|
938
978
|
const pollGenerationRef = useRef(0);
|
|
939
979
|
const pollTimerRef = useRef(null);
|
|
940
980
|
const conversationTokenRef = useRef(null);
|
|
981
|
+
const [hasConversation, setHasConversation] = useState(false);
|
|
941
982
|
const shareTokenRef = useRef(void 0);
|
|
942
983
|
if (shareTokenRef.current === void 0) {
|
|
943
984
|
shareTokenRef.current = readShareToken();
|
|
@@ -952,6 +993,10 @@ function useExploreChat(options = {}) {
|
|
|
952
993
|
);
|
|
953
994
|
const inFlightRef = useRef(false);
|
|
954
995
|
catalogRef.current = catalog;
|
|
996
|
+
const rememberConversationToken = useCallback((token) => {
|
|
997
|
+
conversationTokenRef.current = token;
|
|
998
|
+
setHasConversation(token !== null);
|
|
999
|
+
}, []);
|
|
955
1000
|
const clearPollTimer = useCallback(() => {
|
|
956
1001
|
if (pollTimerRef.current !== null) {
|
|
957
1002
|
clearTimeout(pollTimerRef.current);
|
|
@@ -1018,7 +1063,7 @@ function useExploreChat(options = {}) {
|
|
|
1018
1063
|
setArchive(readArchive(storageKey));
|
|
1019
1064
|
const stored = readPersisted(storageKey);
|
|
1020
1065
|
if (stored) {
|
|
1021
|
-
|
|
1066
|
+
rememberConversationToken(stored.conversationToken);
|
|
1022
1067
|
focusProductRef.current = stored.focusProduct;
|
|
1023
1068
|
const settled = stored.messages.flatMap((m) => {
|
|
1024
1069
|
if (m.role !== "ASSISTANT") return [m];
|
|
@@ -1034,7 +1079,7 @@ function useExploreChat(options = {}) {
|
|
|
1034
1079
|
setTurnCount(turns);
|
|
1035
1080
|
}
|
|
1036
1081
|
setHydrated(true);
|
|
1037
|
-
}, [persist, storageKey]);
|
|
1082
|
+
}, [persist, rememberConversationToken, storageKey]);
|
|
1038
1083
|
useEffect(() => {
|
|
1039
1084
|
if (!persist || !hydrated || typeof window === "undefined") return;
|
|
1040
1085
|
try {
|
|
@@ -1227,7 +1272,7 @@ function useExploreChat(options = {}) {
|
|
|
1227
1272
|
setPhase(classified.kind === "rate-limit" ? "limited" : "error");
|
|
1228
1273
|
return;
|
|
1229
1274
|
}
|
|
1230
|
-
|
|
1275
|
+
rememberConversationToken(result.conversation.token);
|
|
1231
1276
|
turnCountRef.current = result.conversation.turnCount;
|
|
1232
1277
|
setTurnCount(result.conversation.turnCount);
|
|
1233
1278
|
setRemainingToday(result.remainingToday ?? null);
|
|
@@ -1253,7 +1298,14 @@ function useExploreChat(options = {}) {
|
|
|
1253
1298
|
setPhase("streaming");
|
|
1254
1299
|
startPolling(result.conversation.token, assistantMessage.id);
|
|
1255
1300
|
},
|
|
1256
|
-
[
|
|
1301
|
+
[
|
|
1302
|
+
client,
|
|
1303
|
+
locale,
|
|
1304
|
+
pageUrl,
|
|
1305
|
+
productSlug,
|
|
1306
|
+
rememberConversationToken,
|
|
1307
|
+
startPolling
|
|
1308
|
+
]
|
|
1257
1309
|
);
|
|
1258
1310
|
const send = useCallback(
|
|
1259
1311
|
async (message, attachments = []) => {
|
|
@@ -1370,7 +1422,7 @@ function useExploreChat(options = {}) {
|
|
|
1370
1422
|
);
|
|
1371
1423
|
cancelPolling();
|
|
1372
1424
|
inFlightRef.current = false;
|
|
1373
|
-
|
|
1425
|
+
rememberConversationToken(null);
|
|
1374
1426
|
lastSentTextRef.current = null;
|
|
1375
1427
|
lastSentAttachmentsRef.current = [];
|
|
1376
1428
|
turnCountRef.current = 0;
|
|
@@ -1385,7 +1437,7 @@ function useExploreChat(options = {}) {
|
|
|
1385
1437
|
} catch {
|
|
1386
1438
|
}
|
|
1387
1439
|
}
|
|
1388
|
-
}, [cancelPolling, storageKey]);
|
|
1440
|
+
}, [cancelPolling, rememberConversationToken, storageKey]);
|
|
1389
1441
|
const openConversation = useCallback(
|
|
1390
1442
|
(token) => {
|
|
1391
1443
|
const entry = readArchive(storageKey).find((e) => e.token === token);
|
|
@@ -1397,7 +1449,7 @@ function useExploreChat(options = {}) {
|
|
|
1397
1449
|
});
|
|
1398
1450
|
cancelPolling();
|
|
1399
1451
|
inFlightRef.current = false;
|
|
1400
|
-
|
|
1452
|
+
rememberConversationToken(entry.token);
|
|
1401
1453
|
turnCountRef.current = entry.messages.filter(
|
|
1402
1454
|
(m) => m.role === "USER"
|
|
1403
1455
|
).length;
|
|
@@ -1409,7 +1461,7 @@ function useExploreChat(options = {}) {
|
|
|
1409
1461
|
setPhase(catalogRef.current.enabled ? "ready" : "disabled");
|
|
1410
1462
|
setArchive(readArchive(storageKey));
|
|
1411
1463
|
},
|
|
1412
|
-
[cancelPolling, storageKey]
|
|
1464
|
+
[cancelPolling, rememberConversationToken, storageKey]
|
|
1413
1465
|
);
|
|
1414
1466
|
const deleteConversation = useCallback(
|
|
1415
1467
|
(token) => {
|
|
@@ -1498,6 +1550,69 @@ function useExploreChat(options = {}) {
|
|
|
1498
1550
|
},
|
|
1499
1551
|
[client]
|
|
1500
1552
|
);
|
|
1553
|
+
const escalate = useCallback(
|
|
1554
|
+
async (email, note) => {
|
|
1555
|
+
const token = conversationTokenRef.current;
|
|
1556
|
+
if (!token) {
|
|
1557
|
+
return { outcome: "no-conversation", email: null, createdAt: null };
|
|
1558
|
+
}
|
|
1559
|
+
const attempt = async (captchaAttempt) => {
|
|
1560
|
+
const activeCatalog = catalogRef.current;
|
|
1561
|
+
let recaptchaToken;
|
|
1562
|
+
if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {
|
|
1563
|
+
try {
|
|
1564
|
+
recaptchaToken = await getRecaptchaV3Token(
|
|
1565
|
+
activeCatalog.recaptchaSiteKey
|
|
1566
|
+
);
|
|
1567
|
+
} catch (err) {
|
|
1568
|
+
console.warn(
|
|
1569
|
+
"[WebSDK] reCAPTCHA v3 token could not be minted",
|
|
1570
|
+
err
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
const input = {
|
|
1575
|
+
conversationToken: token,
|
|
1576
|
+
email: email.trim(),
|
|
1577
|
+
note: note?.trim() ? note.trim() : null,
|
|
1578
|
+
...recaptchaToken ? { recaptchaToken } : {},
|
|
1579
|
+
...productId ? { productId } : {}
|
|
1580
|
+
};
|
|
1581
|
+
try {
|
|
1582
|
+
const res = await client.mutate(
|
|
1583
|
+
ESCALATE_EXPLORE_CONVERSATION_MUTATION,
|
|
1584
|
+
{ input }
|
|
1585
|
+
);
|
|
1586
|
+
const first = res?.errors?.[0];
|
|
1587
|
+
const result = res?.data?.escalateExploreConversation;
|
|
1588
|
+
if (first || !result) {
|
|
1589
|
+
const code = typeof first?.extensions?.code === "string" ? first.extensions.code : "ESCALATION_FAILED";
|
|
1590
|
+
if (code === "CAPTCHA_FAILED" && captchaAttempt === 0) {
|
|
1591
|
+
return attempt(1);
|
|
1592
|
+
}
|
|
1593
|
+
return {
|
|
1594
|
+
outcome: escalateOutcomeForCode(code),
|
|
1595
|
+
email: null,
|
|
1596
|
+
createdAt: null
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
return {
|
|
1600
|
+
// `created: false` is the double-click, the retry, the reload. The handover
|
|
1601
|
+
// exists, so this is a success — and the address comes from the SERVER, because
|
|
1602
|
+
// on a repeat submit the reply goes to whatever the FIRST handover used.
|
|
1603
|
+
outcome: result.created ? "sent" : "already-handed-over",
|
|
1604
|
+
email: result.escalation?.email ?? null,
|
|
1605
|
+
createdAt: result.escalation?.createdAt ?? null
|
|
1606
|
+
};
|
|
1607
|
+
} catch {
|
|
1608
|
+
return { outcome: "failed", email: null, createdAt: null };
|
|
1609
|
+
}
|
|
1610
|
+
};
|
|
1611
|
+
return attempt(0);
|
|
1612
|
+
},
|
|
1613
|
+
[client, productId]
|
|
1614
|
+
);
|
|
1615
|
+
const canEscalate = hasConversation && !isSharedView;
|
|
1501
1616
|
return {
|
|
1502
1617
|
phase,
|
|
1503
1618
|
catalog,
|
|
@@ -1518,6 +1633,8 @@ function useExploreChat(options = {}) {
|
|
|
1518
1633
|
clearHistory,
|
|
1519
1634
|
recordClick,
|
|
1520
1635
|
submitFeedback,
|
|
1636
|
+
escalate,
|
|
1637
|
+
canEscalate,
|
|
1521
1638
|
createShareLink,
|
|
1522
1639
|
isSharedView
|
|
1523
1640
|
};
|