@sensiblestats/widget-react 0.19.0 → 0.20.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/CHANGELOG.md +11 -0
- package/dist/index.cjs +43 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +43 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @sensiblestats/widget-react
|
|
2
2
|
|
|
3
|
+
## 0.20.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Club-dashboard taps (FixtureHero CTA, MatchPreview/TeamDna facts) now send the backend's opaque `actionRef` instead of a prose command, and `useChatStream` gains a client-side fallback timeout so the panel can no longer hang forever waiting for a `turn_complete`/`error` that never arrives.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
- @sensiblestats/widget-sdk@0.17.0
|
|
13
|
+
|
|
3
14
|
## 0.19.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -625,21 +625,42 @@ function reducer(state, action) {
|
|
|
625
625
|
}
|
|
626
626
|
|
|
627
627
|
// src/useChatStream.ts
|
|
628
|
+
var STREAM_FALLBACK_TIMEOUT_MS = 3e4;
|
|
628
629
|
function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
629
630
|
const seed = (0, import_react.useMemo)(() => initialState(starterTexts.map(chipFromText)), []);
|
|
630
631
|
const [state, dispatch] = (0, import_react.useReducer)(reducer, seed);
|
|
631
632
|
const idRef = (0, import_react.useRef)(0);
|
|
632
633
|
const handleRef = (0, import_react.useRef)(null);
|
|
634
|
+
const fallbackTimerRef = (0, import_react.useRef)(null);
|
|
633
635
|
const stateRef = (0, import_react.useRef)(state);
|
|
634
636
|
stateRef.current = state;
|
|
635
637
|
const greetedRef = (0, import_react.useRef)(false);
|
|
636
638
|
const nextId = () => `m${idRef.current++}`;
|
|
639
|
+
const clearFallbackTimer = (0, import_react.useCallback)(() => {
|
|
640
|
+
if (fallbackTimerRef.current != null) {
|
|
641
|
+
clearTimeout(fallbackTimerRef.current);
|
|
642
|
+
fallbackTimerRef.current = null;
|
|
643
|
+
}
|
|
644
|
+
}, []);
|
|
645
|
+
const armFallbackTimer = (0, import_react.useCallback)((onFire) => {
|
|
646
|
+
clearFallbackTimer();
|
|
647
|
+
fallbackTimerRef.current = setTimeout(() => {
|
|
648
|
+
fallbackTimerRef.current = null;
|
|
649
|
+
handleRef.current?.cancel();
|
|
650
|
+
handleRef.current = null;
|
|
651
|
+
onFire();
|
|
652
|
+
}, STREAM_FALLBACK_TIMEOUT_MS);
|
|
653
|
+
}, [clearFallbackTimer]);
|
|
637
654
|
const consume = (0, import_react.useCallback)((handle, onError) => {
|
|
638
655
|
;
|
|
639
656
|
(async () => {
|
|
640
657
|
try {
|
|
641
|
-
for await (const event of handle)
|
|
658
|
+
for await (const event of handle) {
|
|
659
|
+
dispatch({ kind: "EVENT", event });
|
|
660
|
+
if (event.type === "turn_complete" || event.type === "error") clearFallbackTimer();
|
|
661
|
+
}
|
|
642
662
|
} catch (err) {
|
|
663
|
+
if (handleRef.current === handle) clearFallbackTimer();
|
|
643
664
|
if (err instanceof import_widget_sdk3.WidgetSdkError) onError(err);
|
|
644
665
|
else if (err?.name === "AbortError") {
|
|
645
666
|
} else throw err;
|
|
@@ -647,18 +668,23 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
|
647
668
|
if (handleRef.current === handle) handleRef.current = null;
|
|
648
669
|
}
|
|
649
670
|
})();
|
|
650
|
-
}, []);
|
|
671
|
+
}, [clearFallbackTimer]);
|
|
651
672
|
const run = (0, import_react.useCallback)((input, displayText) => {
|
|
652
673
|
handleRef.current?.cancel();
|
|
674
|
+
clearFallbackTimer();
|
|
653
675
|
dispatch({ kind: "USER_SENT", input, userId: nextId(), assistantId: nextId(), displayText });
|
|
654
676
|
const handle = conversation.send(input);
|
|
655
677
|
handleRef.current = handle;
|
|
678
|
+
armFallbackTimer(() => {
|
|
679
|
+
dispatch({ kind: "STOP" });
|
|
680
|
+
dispatch({ kind: "STREAM_ERROR", error: new import_widget_sdk3.WidgetSdkError("No response received in time", "timeout") });
|
|
681
|
+
});
|
|
656
682
|
consume(handle, (err) => dispatch({ kind: "STREAM_ERROR", error: err }));
|
|
657
|
-
}, [conversation, consume]);
|
|
683
|
+
}, [conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
658
684
|
const send = (0, import_react.useCallback)((text, opts) => {
|
|
659
685
|
const trimmed = text.trim();
|
|
660
686
|
if (!trimmed) return;
|
|
661
|
-
run({ message: trimmed, actionId: opts?.actionId,
|
|
687
|
+
run({ message: trimmed, actionId: opts?.actionId, actionRef: opts?.actionRef }, opts?.displayText);
|
|
662
688
|
}, [run]);
|
|
663
689
|
const retry = (0, import_react.useCallback)(() => {
|
|
664
690
|
const last = stateRef.current.lastUserInput;
|
|
@@ -670,25 +696,29 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
|
670
696
|
greetedRef.current = true;
|
|
671
697
|
try {
|
|
672
698
|
handleRef.current?.cancel();
|
|
699
|
+
clearFallbackTimer();
|
|
673
700
|
dispatch({ kind: "GREETING_SENT", assistantId: nextId() });
|
|
674
701
|
const handle = conversation.send({ message });
|
|
675
702
|
handleRef.current = handle;
|
|
703
|
+
armFallbackTimer(() => dispatch({ kind: "STOP" }));
|
|
676
704
|
consume(handle, () => dispatch({ kind: "STOP" }));
|
|
677
705
|
} catch {
|
|
678
706
|
dispatch({ kind: "STOP" });
|
|
679
707
|
}
|
|
680
|
-
}, [greetingMessage, conversation, consume]);
|
|
708
|
+
}, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
681
709
|
const open = (0, import_react.useCallback)(() => dispatch({ kind: "OPEN" }), []);
|
|
682
710
|
const close = (0, import_react.useCallback)(() => {
|
|
683
711
|
handleRef.current?.cancel();
|
|
684
712
|
handleRef.current = null;
|
|
713
|
+
clearFallbackTimer();
|
|
685
714
|
dispatch({ kind: "CLOSE" });
|
|
686
|
-
}, []);
|
|
715
|
+
}, [clearFallbackTimer]);
|
|
687
716
|
const stop = (0, import_react.useCallback)(() => {
|
|
688
717
|
handleRef.current?.cancel();
|
|
689
718
|
handleRef.current = null;
|
|
719
|
+
clearFallbackTimer();
|
|
690
720
|
dispatch({ kind: "STOP" });
|
|
691
|
-
}, []);
|
|
721
|
+
}, [clearFallbackTimer]);
|
|
692
722
|
const toggle = (0, import_react.useCallback)(() => {
|
|
693
723
|
if (stateRef.current.isOpen) close();
|
|
694
724
|
else open();
|
|
@@ -1353,7 +1383,7 @@ function FixtureHeroBlock({
|
|
|
1353
1383
|
block.venue ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-venue", children: block.venue }) : null,
|
|
1354
1384
|
block.competition ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-comp", children: block.competition }) : null
|
|
1355
1385
|
] }),
|
|
1356
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.
|
|
1386
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.ctaLabel, { actionRef: block.ctaActionRef }), children: block.ctaLabel })
|
|
1357
1387
|
] });
|
|
1358
1388
|
}
|
|
1359
1389
|
|
|
@@ -1382,12 +1412,12 @@ function MatchPreviewBlock({
|
|
|
1382
1412
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-cdash-lines", children: [
|
|
1383
1413
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1384
1414
|
block.facts.map(
|
|
1385
|
-
(f, i) => f.
|
|
1415
|
+
(f, i) => f.actionRef ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1386
1416
|
"button",
|
|
1387
1417
|
{
|
|
1388
1418
|
type: "button",
|
|
1389
1419
|
className: "ss-w-cdash-fact",
|
|
1390
|
-
onClick: () => onAction(f.
|
|
1420
|
+
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1391
1421
|
children: [
|
|
1392
1422
|
f.sentence,
|
|
1393
1423
|
f.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "ss-w-cdash-fact-label", children: [
|
|
@@ -1414,12 +1444,12 @@ function TeamDnaBlock({
|
|
|
1414
1444
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-cdash-lines", children: [
|
|
1415
1445
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1416
1446
|
block.facts.map(
|
|
1417
|
-
(f, i) => f.
|
|
1447
|
+
(f, i) => f.actionRef ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1418
1448
|
"button",
|
|
1419
1449
|
{
|
|
1420
1450
|
type: "button",
|
|
1421
1451
|
className: "ss-w-cdash-fact",
|
|
1422
|
-
onClick: () => onAction(f.
|
|
1452
|
+
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1423
1453
|
children: [
|
|
1424
1454
|
f.sentence,
|
|
1425
1455
|
f.label ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "ss-w-cdash-fact-label", children: [
|
|
@@ -1565,7 +1595,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1565
1595
|
send(tile.actionValue, { displayText: tile.title });
|
|
1566
1596
|
if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
|
|
1567
1597
|
},
|
|
1568
|
-
onClubAction: (
|
|
1598
|
+
onClubAction: (label, opts) => send(label, { actionRef: opts.actionRef }),
|
|
1569
1599
|
ui,
|
|
1570
1600
|
slip
|
|
1571
1601
|
},
|