@mushi-mushi/react-native 0.19.1 → 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 +32 -0
- package/CONTRIBUTING.md +14 -2
- package/README.md +0 -1
- package/SECURITY.md +1 -1
- package/dist/index.cjs +394 -122
- package/dist/index.d.cts +56 -3
- package/dist/index.d.ts +56 -3
- package/dist/index.js +360 -84
- package/package.json +9 -4
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
AsyncStorageQueue: () => AsyncStorageQueue,
|
|
34
|
+
MUSHI_BANNER_DEFAULT_HEIGHT: () => MUSHI_BANNER_DEFAULT_HEIGHT,
|
|
35
|
+
MushiBanner: () => MushiBanner,
|
|
34
36
|
MushiBottomSheet: () => MushiBottomSheet,
|
|
35
37
|
MushiFloatingButton: () => MushiFloatingButton,
|
|
36
38
|
MushiProvider: () => MushiProvider,
|
|
@@ -46,8 +48,8 @@ __export(index_exports, {
|
|
|
46
48
|
module.exports = __toCommonJS(index_exports);
|
|
47
49
|
|
|
48
50
|
// src/provider.tsx
|
|
49
|
-
var
|
|
50
|
-
var
|
|
51
|
+
var import_react4 = require("react");
|
|
52
|
+
var import_core6 = require("@mushi-mushi/core");
|
|
51
53
|
|
|
52
54
|
// src/capture/console-capture.ts
|
|
53
55
|
var import_core = require("@mushi-mushi/core");
|
|
@@ -263,9 +265,8 @@ async function encryptQueueBlob(plaintext, secureStorage) {
|
|
|
263
265
|
combined.set(new Uint8Array(cipher), iv.length);
|
|
264
266
|
return ENCRYPTED_PREFIX + bytesToBase64(combined);
|
|
265
267
|
}
|
|
266
|
-
async function decryptQueueBlob(stored,
|
|
268
|
+
async function decryptQueueBlob(stored, _secureStorage) {
|
|
267
269
|
if (!stored.startsWith(ENCRYPTED_PREFIX)) return stored;
|
|
268
|
-
if (!secureStorage) return stored;
|
|
269
270
|
const secure = await loadSecureStore();
|
|
270
271
|
if (!secure || !hasWebCrypto()) return stored;
|
|
271
272
|
const key = await getOrCreateQueueKey(secure);
|
|
@@ -477,32 +478,64 @@ function sleep(ms) {
|
|
|
477
478
|
var import_react = require("react");
|
|
478
479
|
var import_react_native2 = require("react-native");
|
|
479
480
|
var import_core3 = require("@mushi-mushi/core");
|
|
481
|
+
var import_i18n = require("@mushi-mushi/web/i18n");
|
|
482
|
+
|
|
483
|
+
// src/reporter-status.ts
|
|
484
|
+
function reporterStatusShort(status) {
|
|
485
|
+
switch (status) {
|
|
486
|
+
case "new":
|
|
487
|
+
case "queued":
|
|
488
|
+
case "pending":
|
|
489
|
+
case "submitted":
|
|
490
|
+
return "Received";
|
|
491
|
+
case "classified":
|
|
492
|
+
case "triaged":
|
|
493
|
+
case "grouped":
|
|
494
|
+
case "dispatched":
|
|
495
|
+
return "In review";
|
|
496
|
+
case "fixing":
|
|
497
|
+
return "Fixing";
|
|
498
|
+
case "fixed":
|
|
499
|
+
case "resolved":
|
|
500
|
+
case "completed":
|
|
501
|
+
return "Fixed";
|
|
502
|
+
case "dismissed":
|
|
503
|
+
return "Closed";
|
|
504
|
+
default:
|
|
505
|
+
return status.replace(/_/g, " ").slice(0, 16);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/components/MushiBottomSheet.tsx
|
|
480
510
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
481
511
|
var { height: SCREEN_HEIGHT } = import_react_native2.Dimensions.get("window");
|
|
482
512
|
var SHEET_HEIGHT = SCREEN_HEIGHT * 0.55;
|
|
483
513
|
var DISMISS_THRESHOLD = 80;
|
|
484
|
-
var
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
514
|
+
var CATEGORY_KEYS = ["bug", "slow", "visual", "confusing", "other"];
|
|
515
|
+
var CATEGORY_EMOJI = {
|
|
516
|
+
bug: "\u{1F41B}",
|
|
517
|
+
slow: "\u{1F422}",
|
|
518
|
+
visual: "\u{1F3A8}",
|
|
519
|
+
confusing: "\u{1F615}",
|
|
520
|
+
other: "\u{1F4AC}"
|
|
489
521
|
};
|
|
490
|
-
var CATEGORIES = [
|
|
491
|
-
{ key: "bug", emoji: "\u{1F41B}", label: "Bug" },
|
|
492
|
-
{ key: "slow", emoji: "\u{1F422}", label: "Slow" },
|
|
493
|
-
{ key: "visual", emoji: "\u{1F3A8}", label: "Visual" },
|
|
494
|
-
{ key: "confusing", emoji: "\u{1F615}", label: "Confusing" },
|
|
495
|
-
{ key: "other", emoji: "\u{1F4AC}", label: "Other" }
|
|
496
|
-
];
|
|
497
522
|
var VERIFIABLE_STATUSES = /* @__PURE__ */ new Set(["fixed", "resolved", "verified"]);
|
|
498
523
|
var MushiBottomSheet = ({
|
|
499
524
|
visible,
|
|
500
525
|
onClose,
|
|
526
|
+
preferredTab = "report",
|
|
501
527
|
screenshotDataUrl,
|
|
502
528
|
onClearScreenshot,
|
|
503
|
-
screenshotSensitiveHint
|
|
529
|
+
screenshotSensitiveHint,
|
|
530
|
+
assistantEnabled = false,
|
|
531
|
+
assistantLabel = import_core3.MUSHI_COPY.assistantTab,
|
|
532
|
+
assistantGreeting,
|
|
533
|
+
assistantSuggestions = [],
|
|
534
|
+
inboxPollIntervalMs = 0
|
|
504
535
|
}) => {
|
|
505
536
|
const mushi = useMushiContext();
|
|
537
|
+
const t = (0, import_i18n.getLocale)();
|
|
538
|
+
const greeting = assistantGreeting ?? t.assistant.defaultGreeting;
|
|
506
539
|
const scheme = (0, import_react_native2.useColorScheme)();
|
|
507
540
|
const dark = scheme === "dark";
|
|
508
541
|
const translateY = (0, import_react.useRef)(new import_react_native2.Animated.Value(SHEET_HEIGHT)).current;
|
|
@@ -516,6 +549,11 @@ var MushiBottomSheet = ({
|
|
|
516
549
|
const [selectedReportId, setSelectedReportId] = (0, import_react.useState)(null);
|
|
517
550
|
const [threadComments, setThreadComments] = (0, import_react.useState)([]);
|
|
518
551
|
const [replyText, setReplyText] = (0, import_react.useState)("");
|
|
552
|
+
const [assistantInput, setAssistantInput] = (0, import_react.useState)("");
|
|
553
|
+
const [assistantThreadId, setAssistantThreadId] = (0, import_react.useState)(null);
|
|
554
|
+
const [assistantSending, setAssistantSending] = (0, import_react.useState)(false);
|
|
555
|
+
const [assistantError, setAssistantError] = (0, import_react.useState)(null);
|
|
556
|
+
const [assistantTurns, setAssistantTurns] = (0, import_react.useState)([]);
|
|
519
557
|
const [screenshotAttached, setScreenshotAttached] = (0, import_react.useState)(true);
|
|
520
558
|
const loadInbox = (0, import_react.useCallback)(async () => {
|
|
521
559
|
if (!mushi?.listMyReports) return;
|
|
@@ -530,9 +568,17 @@ var MushiBottomSheet = ({
|
|
|
530
568
|
(0, import_react.useEffect)(() => {
|
|
531
569
|
if (visible) {
|
|
532
570
|
setScreenshotAttached(true);
|
|
533
|
-
|
|
571
|
+
setSheetTab(preferredTab);
|
|
572
|
+
if (preferredTab === "inbox") void loadInbox();
|
|
534
573
|
}
|
|
535
|
-
}, [visible,
|
|
574
|
+
}, [visible, preferredTab, loadInbox]);
|
|
575
|
+
(0, import_react.useEffect)(() => {
|
|
576
|
+
if (!visible || sheetTab !== "inbox" || inboxPollIntervalMs <= 0) return;
|
|
577
|
+
const timer = setInterval(() => {
|
|
578
|
+
void loadInbox();
|
|
579
|
+
}, inboxPollIntervalMs);
|
|
580
|
+
return () => clearInterval(timer);
|
|
581
|
+
}, [visible, sheetTab, inboxPollIntervalMs, loadInbox]);
|
|
536
582
|
const openThread = (0, import_react.useCallback)(async (reportId) => {
|
|
537
583
|
setSelectedReportId(reportId);
|
|
538
584
|
if (!mushi?.listMyComments) return;
|
|
@@ -551,6 +597,29 @@ var MushiBottomSheet = ({
|
|
|
551
597
|
await loadInbox();
|
|
552
598
|
await openThread(selectedReportId);
|
|
553
599
|
}, [mushi, selectedReportId, loadInbox, openThread]);
|
|
600
|
+
const sendAssistant = (0, import_react.useCallback)(async (message) => {
|
|
601
|
+
if (!mushi?.askAssistant || !message.trim() || assistantSending) return;
|
|
602
|
+
const trimmed = message.trim();
|
|
603
|
+
setAssistantInput("");
|
|
604
|
+
setAssistantError(null);
|
|
605
|
+
setAssistantTurns((prev) => [...prev, { role: "user", text: trimmed }]);
|
|
606
|
+
setAssistantSending(true);
|
|
607
|
+
try {
|
|
608
|
+
const reply = await mushi.askAssistant(trimmed, assistantThreadId);
|
|
609
|
+
if (!reply) {
|
|
610
|
+
setAssistantError("Could not reach the assistant. Try again.");
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
if (reply.threadId) setAssistantThreadId(reply.threadId);
|
|
614
|
+
const botText = reply.kind === "clarify" ? reply.question ?? reply.text ?? "" : reply.text ?? "";
|
|
615
|
+
setAssistantTurns((prev) => [
|
|
616
|
+
...prev,
|
|
617
|
+
{ role: "bot", text: botText, options: reply.options }
|
|
618
|
+
]);
|
|
619
|
+
} finally {
|
|
620
|
+
setAssistantSending(false);
|
|
621
|
+
}
|
|
622
|
+
}, [mushi, assistantSending, assistantThreadId]);
|
|
554
623
|
const resetForm = (0, import_react.useCallback)(() => {
|
|
555
624
|
setCategory(null);
|
|
556
625
|
setDescription("");
|
|
@@ -635,7 +704,8 @@ var MushiBottomSheet = ({
|
|
|
635
704
|
};
|
|
636
705
|
const activeScreenshot = screenshotDataUrl && screenshotAttached ? screenshotDataUrl : null;
|
|
637
706
|
const pal = (0, import_core3.mushiPalette)(dark ? "dark" : "light");
|
|
638
|
-
const colors = dark ? { bg: pal.paper, text: pal.ink, sub: pal.inkMuted, card: pal.paperRaised, accent:
|
|
707
|
+
const colors = dark ? { bg: pal.paper, text: pal.ink, sub: pal.inkMuted, card: pal.paperRaised, accent: import_core3.MUSHI_BANNER_NEON.bg, accentInk: import_core3.MUSHI_BANNER_NEON.fg, border: pal.ruleStrong, backdrop: "rgba(0,0,0,0.6)", disabled: "#3a3a3c", disabledText: pal.inkFaint } : { bg: pal.paperRaised, text: pal.ink, sub: pal.inkMuted, card: pal.paper, accent: import_core3.MUSHI_BANNER_NEON.bg, accentInk: import_core3.MUSHI_BANNER_NEON.fg, border: pal.ruleStrong, backdrop: "rgba(0,0,0,0.35)", disabled: "#d1d1d6", disabledText: pal.inkFaint };
|
|
708
|
+
const sheetTabs = ["report", "inbox", ...assistantEnabled ? ["assistant"] : []];
|
|
639
709
|
const canSubmit = !!category && description.trim().length > 0 && phase === "form";
|
|
640
710
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Modal, { visible, transparent: true, animationType: "none", statusBarTranslucent: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
641
711
|
import_react_native2.KeyboardAvoidingView,
|
|
@@ -660,11 +730,11 @@ var MushiBottomSheet = ({
|
|
|
660
730
|
],
|
|
661
731
|
children: [
|
|
662
732
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { ...panResponder.panHandlers, style: s.handleArea, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [s.handle, { backgroundColor: colors.sub }] }) }),
|
|
663
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: [s.brandHeader, { backgroundColor:
|
|
664
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.brandEyebrow, { color:
|
|
665
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.brandTitle, { color:
|
|
733
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: [s.brandHeader, { backgroundColor: import_core3.MUSHI_BANNER_NEON.bg, borderBottomColor: import_core3.MUSHI_BANNER_NEON.border }], children: [
|
|
734
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.brandEyebrow, { color: import_core3.MUSHI_BANNER_NEON.fg }], children: "MUSHI \xB7 BETA" }),
|
|
735
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.brandTitle, { color: import_core3.MUSHI_BANNER_NEON.fg }], children: sheetTab === "assistant" ? assistantLabel : sheetTab === "inbox" ? t.flows.reports.title : t.widget.title })
|
|
666
736
|
] }),
|
|
667
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: s.tabRow, children:
|
|
737
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: s.tabRow, children: sheetTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
668
738
|
import_react_native2.TouchableOpacity,
|
|
669
739
|
{
|
|
670
740
|
onPress: () => {
|
|
@@ -673,12 +743,68 @@ var MushiBottomSheet = ({
|
|
|
673
743
|
else setSelectedReportId(null);
|
|
674
744
|
},
|
|
675
745
|
style: [s.tabBtn, sheetTab === tab && { borderBottomColor: colors.accent }],
|
|
676
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.tabLabel, { color: sheetTab === tab ? colors.text : colors.sub }], children: tab === "report" ?
|
|
746
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.tabLabel, { color: sheetTab === tab ? colors.text : colors.sub }], children: tab === "report" ? t.widget.trigger : tab === "inbox" ? t.flows.reports.title : assistantLabel })
|
|
677
747
|
},
|
|
678
748
|
tab
|
|
679
749
|
)) }),
|
|
680
|
-
sheetTab === "
|
|
681
|
-
|
|
750
|
+
sheetTab === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.ScrollView, { style: s.body, keyboardShouldPersistTaps: "handled", children: [
|
|
751
|
+
assistantTurns.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
752
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, marginBottom: 12, lineHeight: 20 }, children: greeting }),
|
|
753
|
+
assistantSuggestions.map((chip) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
754
|
+
import_react_native2.TouchableOpacity,
|
|
755
|
+
{
|
|
756
|
+
style: [s.assistantChip, { borderColor: colors.border, backgroundColor: colors.card }],
|
|
757
|
+
onPress: () => void sendAssistant(chip),
|
|
758
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.text, fontSize: 13 }, children: chip })
|
|
759
|
+
},
|
|
760
|
+
chip
|
|
761
|
+
))
|
|
762
|
+
] }) : assistantTurns.map((turn, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
763
|
+
import_react_native2.View,
|
|
764
|
+
{
|
|
765
|
+
style: [
|
|
766
|
+
s.assistantBubble,
|
|
767
|
+
{
|
|
768
|
+
alignSelf: turn.role === "user" ? "flex-end" : "flex-start",
|
|
769
|
+
backgroundColor: turn.role === "user" ? colors.accent : colors.card
|
|
770
|
+
}
|
|
771
|
+
],
|
|
772
|
+
children: [
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: turn.role === "user" ? colors.accentInk : colors.text }, children: turn.text }),
|
|
774
|
+
turn.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { onPress: () => void sendAssistant(opt), style: { marginTop: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.accent, fontSize: 12 }, children: opt }) }, opt))
|
|
775
|
+
]
|
|
776
|
+
},
|
|
777
|
+
`${turn.role}-${idx}`
|
|
778
|
+
)),
|
|
779
|
+
assistantSending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, marginTop: 8 }, accessibilityLiveRegion: "polite", children: t.assistant.thinking }) : null,
|
|
780
|
+
assistantError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: pal.danger, marginTop: 8 }, accessibilityRole: "alert", children: assistantError }) : null,
|
|
781
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.assistantComposer, children: [
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
783
|
+
import_react_native2.TextInput,
|
|
784
|
+
{
|
|
785
|
+
style: [s.input, { flex: 1, minHeight: 44, backgroundColor: colors.card, color: colors.text, borderColor: colors.border }],
|
|
786
|
+
placeholder: t.assistant.inputPlaceholder,
|
|
787
|
+
placeholderTextColor: colors.sub,
|
|
788
|
+
value: assistantInput,
|
|
789
|
+
onChangeText: setAssistantInput,
|
|
790
|
+
editable: !assistantSending
|
|
791
|
+
}
|
|
792
|
+
),
|
|
793
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
794
|
+
import_react_native2.TouchableOpacity,
|
|
795
|
+
{
|
|
796
|
+
style: [s.submitBtn, { backgroundColor: colors.accent, paddingHorizontal: 16 }],
|
|
797
|
+
onPress: () => void sendAssistant(assistantInput),
|
|
798
|
+
disabled: !assistantInput.trim() || assistantSending,
|
|
799
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: colors.accentInk }], children: "\u2191" })
|
|
800
|
+
}
|
|
801
|
+
)
|
|
802
|
+
] })
|
|
803
|
+
] }) : sheetTab === "inbox" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.ScrollView, { style: s.body, keyboardShouldPersistTaps: "handled", children: inboxLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub }, children: t.flows.reports.loading }) : selectedReportId ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
804
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { onPress: () => setSelectedReportId(null), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.Text, { style: { color: colors.accent, marginBottom: 8 }, children: [
|
|
805
|
+
"\u2190 ",
|
|
806
|
+
t.widget.back
|
|
807
|
+
] }) }),
|
|
682
808
|
threadComments.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: [s.threadBubble, { backgroundColor: colors.card }], children: [
|
|
683
809
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 11 }, children: c.author_kind }),
|
|
684
810
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.text }, children: c.body })
|
|
@@ -686,42 +812,26 @@ var MushiBottomSheet = ({
|
|
|
686
812
|
VERIFIABLE_STATUSES.has(
|
|
687
813
|
inboxReports.find((r) => r.id === selectedReportId)?.status ?? ""
|
|
688
814
|
) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.verifyRow, children: [
|
|
689
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.accent }], onPress: () => submitFeedback("confirms"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: colors.accentInk }], children:
|
|
690
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.border }], onPress: () => submitFeedback("not_fixed"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: colors.text }], children:
|
|
815
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.accent }], onPress: () => submitFeedback("confirms"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: colors.accentInk }], children: t.flows.thread.confirmFixed }) }),
|
|
816
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.border }], onPress: () => submitFeedback("not_fixed"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: colors.text }], children: t.flows.thread.notFixed }) })
|
|
691
817
|
] }),
|
|
692
818
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
693
819
|
import_react_native2.TextInput,
|
|
694
820
|
{
|
|
695
821
|
style: [s.input, { backgroundColor: colors.card, color: colors.text, borderColor: colors.border, minHeight: 48 }],
|
|
696
|
-
placeholder:
|
|
822
|
+
placeholder: t.flows.thread.replyPlaceholder,
|
|
697
823
|
placeholderTextColor: colors.sub,
|
|
698
824
|
value: replyText,
|
|
699
825
|
onChangeText: setReplyText
|
|
700
826
|
}
|
|
701
827
|
),
|
|
702
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.submitBtn, { backgroundColor: colors.accent }], onPress: sendReply, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: colors.accentInk }], children:
|
|
828
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.submitBtn, { backgroundColor: colors.accent }], onPress: sendReply, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: colors.accentInk }], children: t.flows.thread.send }) })
|
|
703
829
|
] }) : inboxReports.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.TouchableOpacity, { style: [s.inboxRow, { borderColor: colors.border }], onPress: () => openThread(r.id), children: [
|
|
704
830
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.text, fontWeight: "600" }, numberOfLines: 1, children: (r.summary ?? r.description ?? "Report").slice(0, 60) }),
|
|
705
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 11 }, children: r.status })
|
|
706
|
-
] }, r.id)) }) :
|
|
707
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 13, marginBottom: 16, lineHeight: 18 }, children: "Sign in to track your reports across apps and see the global leaderboard. No password needed." }),
|
|
708
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
709
|
-
import_react_native2.TextInput,
|
|
710
|
-
{
|
|
711
|
-
style: [s.input, { backgroundColor: colors.card, color: colors.text, borderColor: colors.border, minHeight: 48 }],
|
|
712
|
-
placeholder: "you@example.com",
|
|
713
|
-
placeholderTextColor: colors.sub,
|
|
714
|
-
keyboardType: "email-address",
|
|
715
|
-
autoCapitalize: "none",
|
|
716
|
-
autoCorrect: false,
|
|
717
|
-
textContentType: "emailAddress"
|
|
718
|
-
}
|
|
719
|
-
),
|
|
720
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { style: [s.submitBtn, { backgroundColor: colors.accent }], children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: colors.accentInk }], children: "Send sign-in link \u2192" }) }),
|
|
721
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 11, textAlign: "center", marginTop: 12 }, children: "We'll email you a one-tap sign-in link. No password, ever." })
|
|
722
|
-
] }) : phase === "sent" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.sentWrap, children: [
|
|
831
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 11 }, children: reporterStatusShort(r.status) })
|
|
832
|
+
] }, r.id)) }) : phase === "sent" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.sentWrap, children: [
|
|
723
833
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.sentEmoji], children: "\u2705" }),
|
|
724
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.sentText, { color: colors.text }], children:
|
|
834
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.sentText, { color: colors.text }], children: t.widget.submitted })
|
|
725
835
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
726
836
|
import_react_native2.ScrollView,
|
|
727
837
|
{
|
|
@@ -729,13 +839,13 @@ var MushiBottomSheet = ({
|
|
|
729
839
|
keyboardShouldPersistTaps: "handled",
|
|
730
840
|
contentContainerStyle: { paddingBottom: 24 },
|
|
731
841
|
children: [
|
|
732
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.stepLabel, { color: colors.sub }], children:
|
|
733
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: s.catRow, children:
|
|
734
|
-
const active = category ===
|
|
842
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.stepLabel, { color: colors.sub }], children: t.step1.heading }),
|
|
843
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: s.catRow, children: CATEGORY_KEYS.map((key) => {
|
|
844
|
+
const active = category === key;
|
|
735
845
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
736
846
|
import_react_native2.TouchableOpacity,
|
|
737
847
|
{
|
|
738
|
-
onPress: () => setCategory(
|
|
848
|
+
onPress: () => setCategory(key),
|
|
739
849
|
activeOpacity: 0.7,
|
|
740
850
|
style: [
|
|
741
851
|
s.catBtn,
|
|
@@ -745,7 +855,7 @@ var MushiBottomSheet = ({
|
|
|
745
855
|
}
|
|
746
856
|
],
|
|
747
857
|
children: [
|
|
748
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: s.catEmoji, children:
|
|
858
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: s.catEmoji, children: CATEGORY_EMOJI[key] }),
|
|
749
859
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
750
860
|
import_react_native2.Text,
|
|
751
861
|
{
|
|
@@ -753,12 +863,12 @@ var MushiBottomSheet = ({
|
|
|
753
863
|
s.catLabel,
|
|
754
864
|
{ color: active ? colors.accentInk : colors.text }
|
|
755
865
|
],
|
|
756
|
-
children:
|
|
866
|
+
children: t.step1.categories[key]
|
|
757
867
|
}
|
|
758
868
|
)
|
|
759
869
|
]
|
|
760
870
|
},
|
|
761
|
-
|
|
871
|
+
key
|
|
762
872
|
);
|
|
763
873
|
}) }),
|
|
764
874
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -772,7 +882,7 @@ var MushiBottomSheet = ({
|
|
|
772
882
|
borderColor: colors.border
|
|
773
883
|
}
|
|
774
884
|
],
|
|
775
|
-
placeholder:
|
|
885
|
+
placeholder: t.step3.descriptionPlaceholder,
|
|
776
886
|
placeholderTextColor: colors.sub,
|
|
777
887
|
multiline: true,
|
|
778
888
|
textAlignVertical: "top",
|
|
@@ -787,12 +897,12 @@ var MushiBottomSheet = ({
|
|
|
787
897
|
{
|
|
788
898
|
source: { uri: activeScreenshot },
|
|
789
899
|
style: s.screenshotThumb,
|
|
790
|
-
accessibilityLabel:
|
|
900
|
+
accessibilityLabel: t.step3.screenshotPreviewAlt
|
|
791
901
|
}
|
|
792
902
|
),
|
|
793
903
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.screenshotMeta, children: [
|
|
794
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotLabel, { color: colors.text }], children: "
|
|
795
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotSub, { color: colors.sub }], children: screenshotSensitiveHint && screenshotSensitiveHint.trim() ? `\u26A0 ${screenshotSensitiveHint}` : "
|
|
904
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotLabel, { color: colors.text }], children: t.step3.screenshotAttached.replace(" \u2713", "") }),
|
|
905
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotSub, { color: colors.sub }], children: screenshotSensitiveHint && screenshotSensitiveHint.trim() ? `\u26A0 ${screenshotSensitiveHint}` : t.step3.screenshotSensitiveHint.split("\u2014")[0]?.trim() ?? t.step3.screenshotSensitiveHint })
|
|
796
906
|
] }),
|
|
797
907
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
798
908
|
import_react_native2.TouchableOpacity,
|
|
@@ -802,7 +912,7 @@ var MushiBottomSheet = ({
|
|
|
802
912
|
onClearScreenshot?.();
|
|
803
913
|
},
|
|
804
914
|
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
805
|
-
accessibilityLabel:
|
|
915
|
+
accessibilityLabel: t.widget.close,
|
|
806
916
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotRemove, { color: colors.sub }], children: "\u2715" })
|
|
807
917
|
}
|
|
808
918
|
)
|
|
@@ -817,7 +927,7 @@ var MushiBottomSheet = ({
|
|
|
817
927
|
s.submitBtn,
|
|
818
928
|
{ backgroundColor: canSubmit ? colors.accent : colors.disabled }
|
|
819
929
|
],
|
|
820
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: canSubmit ? colors.accentInk : colors.disabledText }], children: phase === "sending" ?
|
|
930
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.submitText, { color: canSubmit ? colors.accentInk : colors.disabledText }], children: phase === "sending" ? t.widget.submitting : t.widget.submit })
|
|
821
931
|
}
|
|
822
932
|
)
|
|
823
933
|
]
|
|
@@ -1023,6 +1133,27 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1023
1133
|
borderRadius: 10,
|
|
1024
1134
|
paddingVertical: 10,
|
|
1025
1135
|
alignItems: "center"
|
|
1136
|
+
},
|
|
1137
|
+
assistantBubble: {
|
|
1138
|
+
maxWidth: "88%",
|
|
1139
|
+
borderRadius: 12,
|
|
1140
|
+
padding: 12,
|
|
1141
|
+
marginBottom: 10
|
|
1142
|
+
},
|
|
1143
|
+
assistantChip: {
|
|
1144
|
+
borderWidth: 1,
|
|
1145
|
+
borderRadius: 999,
|
|
1146
|
+
paddingHorizontal: 12,
|
|
1147
|
+
paddingVertical: 8,
|
|
1148
|
+
marginBottom: 8,
|
|
1149
|
+
alignSelf: "flex-start"
|
|
1150
|
+
},
|
|
1151
|
+
assistantComposer: {
|
|
1152
|
+
flexDirection: "row",
|
|
1153
|
+
alignItems: "flex-end",
|
|
1154
|
+
gap: 8,
|
|
1155
|
+
marginTop: 12,
|
|
1156
|
+
paddingBottom: 8
|
|
1026
1157
|
}
|
|
1027
1158
|
});
|
|
1028
1159
|
|
|
@@ -1031,7 +1162,7 @@ var import_react2 = require("react");
|
|
|
1031
1162
|
var import_react_native3 = require("react-native");
|
|
1032
1163
|
var import_core4 = require("@mushi-mushi/core");
|
|
1033
1164
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1034
|
-
var FAB_SIZE =
|
|
1165
|
+
var FAB_SIZE = import_core4.MUSHI_GEOMETRY.fabSize;
|
|
1035
1166
|
var EDGE_PADDING = 12;
|
|
1036
1167
|
function getScreenBounds() {
|
|
1037
1168
|
const { width, height } = import_react_native3.Dimensions.get("window");
|
|
@@ -1214,13 +1345,114 @@ var s2 = import_react_native3.StyleSheet.create({
|
|
|
1214
1345
|
}
|
|
1215
1346
|
});
|
|
1216
1347
|
|
|
1348
|
+
// src/components/MushiBanner.tsx
|
|
1349
|
+
var import_react3 = require("react");
|
|
1350
|
+
var import_react_native4 = require("react-native");
|
|
1351
|
+
var import_core5 = require("@mushi-mushi/core");
|
|
1352
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1353
|
+
var MUSHI_BANNER_DEFAULT_HEIGHT = import_core5.MUSHI_GEOMETRY.bannerHeight;
|
|
1354
|
+
var MushiBanner = ({
|
|
1355
|
+
onPress,
|
|
1356
|
+
onDismiss,
|
|
1357
|
+
message = import_core5.MUSHI_COPY.bannerMessage,
|
|
1358
|
+
label = import_core5.MUSHI_COPY.bannerLabel,
|
|
1359
|
+
onLayoutHeight
|
|
1360
|
+
}) => {
|
|
1361
|
+
const handleLayout = (0, import_react3.useCallback)(
|
|
1362
|
+
(e) => {
|
|
1363
|
+
onLayoutHeight?.(e.nativeEvent.layout.height);
|
|
1364
|
+
},
|
|
1365
|
+
[onLayoutHeight]
|
|
1366
|
+
);
|
|
1367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1368
|
+
import_react_native4.View,
|
|
1369
|
+
{
|
|
1370
|
+
style: s3.wrap,
|
|
1371
|
+
onLayout: handleLayout,
|
|
1372
|
+
accessibilityRole: "header",
|
|
1373
|
+
accessibilityLabel: "Mushi feedback banner",
|
|
1374
|
+
children: [
|
|
1375
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.TouchableOpacity, { style: s3.main, onPress, activeOpacity: 0.85, children: [
|
|
1376
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: s3.eyebrow, children: label.toUpperCase() }),
|
|
1377
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: s3.message, numberOfLines: 2, children: message }),
|
|
1378
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: s3.cta, children: import_core5.MUSHI_COPY.bugCta })
|
|
1379
|
+
] }),
|
|
1380
|
+
onDismiss ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1381
|
+
import_react_native4.TouchableOpacity,
|
|
1382
|
+
{
|
|
1383
|
+
style: s3.dismiss,
|
|
1384
|
+
onPress: onDismiss,
|
|
1385
|
+
accessibilityRole: "button",
|
|
1386
|
+
accessibilityLabel: "Dismiss banner",
|
|
1387
|
+
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
1388
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: s3.dismissText, children: "\xD7" })
|
|
1389
|
+
}
|
|
1390
|
+
) : null
|
|
1391
|
+
]
|
|
1392
|
+
}
|
|
1393
|
+
);
|
|
1394
|
+
};
|
|
1395
|
+
var s3 = import_react_native4.StyleSheet.create({
|
|
1396
|
+
wrap: {
|
|
1397
|
+
position: "absolute",
|
|
1398
|
+
left: 0,
|
|
1399
|
+
right: 0,
|
|
1400
|
+
bottom: 0,
|
|
1401
|
+
minHeight: import_core5.MUSHI_GEOMETRY.bannerHeight,
|
|
1402
|
+
flexDirection: "row",
|
|
1403
|
+
alignItems: "stretch",
|
|
1404
|
+
backgroundColor: import_core5.MUSHI_BANNER_NEON.bg,
|
|
1405
|
+
borderTopWidth: 1,
|
|
1406
|
+
borderTopColor: import_core5.MUSHI_BANNER_NEON.border,
|
|
1407
|
+
zIndex: 99998,
|
|
1408
|
+
elevation: 8,
|
|
1409
|
+
paddingBottom: import_react_native4.Platform.OS === "ios" ? 0 : 0
|
|
1410
|
+
},
|
|
1411
|
+
main: {
|
|
1412
|
+
flex: 1,
|
|
1413
|
+
flexDirection: "row",
|
|
1414
|
+
alignItems: "center",
|
|
1415
|
+
gap: 8,
|
|
1416
|
+
paddingHorizontal: 12,
|
|
1417
|
+
paddingVertical: 8
|
|
1418
|
+
},
|
|
1419
|
+
eyebrow: {
|
|
1420
|
+
fontSize: 10,
|
|
1421
|
+
fontWeight: "700",
|
|
1422
|
+
letterSpacing: 1.2,
|
|
1423
|
+
color: import_core5.MUSHI_BANNER_NEON.fg
|
|
1424
|
+
},
|
|
1425
|
+
message: {
|
|
1426
|
+
flex: 1,
|
|
1427
|
+
fontSize: 12,
|
|
1428
|
+
fontWeight: "500",
|
|
1429
|
+
color: import_core5.MUSHI_BANNER_NEON.fg
|
|
1430
|
+
},
|
|
1431
|
+
cta: {
|
|
1432
|
+
fontSize: 12,
|
|
1433
|
+
fontWeight: "700",
|
|
1434
|
+
color: import_core5.MUSHI_BANNER_NEON.fg,
|
|
1435
|
+
textDecorationLine: "underline"
|
|
1436
|
+
},
|
|
1437
|
+
dismiss: {
|
|
1438
|
+
justifyContent: "center",
|
|
1439
|
+
paddingHorizontal: 12
|
|
1440
|
+
},
|
|
1441
|
+
dismissText: {
|
|
1442
|
+
fontSize: 20,
|
|
1443
|
+
lineHeight: 22,
|
|
1444
|
+
color: import_core5.MUSHI_BANNER_NEON.fg,
|
|
1445
|
+
opacity: 0.7
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1448
|
+
|
|
1217
1449
|
// src/version.ts
|
|
1218
1450
|
var MUSHI_SDK_PACKAGE = "@mushi-mushi/react-native";
|
|
1219
|
-
var MUSHI_SDK_VERSION = "0.
|
|
1451
|
+
var MUSHI_SDK_VERSION = "0.20.0" ? "0.20.0" : "0.17.0";
|
|
1220
1452
|
|
|
1221
1453
|
// src/provider.tsx
|
|
1222
|
-
var
|
|
1223
|
-
var MushiContext = (0,
|
|
1454
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1455
|
+
var MushiContext = (0, import_react4.createContext)(null);
|
|
1224
1456
|
var DEFAULT_SCREENSHOT_HINT = "Check the preview \u2014 remove it if any private info (balances, personal details) is visible.";
|
|
1225
1457
|
function resolveScreenshotHint(v) {
|
|
1226
1458
|
if (v === false) return null;
|
|
@@ -1259,26 +1491,28 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1259
1491
|
);
|
|
1260
1492
|
}
|
|
1261
1493
|
}
|
|
1262
|
-
const consoleRef = (0,
|
|
1263
|
-
const networkRef = (0,
|
|
1264
|
-
const queueRef = (0,
|
|
1265
|
-
const apiClientRef = (0,
|
|
1266
|
-
const sessionIdRef = (0,
|
|
1267
|
-
const breadcrumbsRef = (0,
|
|
1268
|
-
(0,
|
|
1494
|
+
const consoleRef = (0, import_react4.useRef)(null);
|
|
1495
|
+
const networkRef = (0, import_react4.useRef)(null);
|
|
1496
|
+
const queueRef = (0, import_react4.useRef)(null);
|
|
1497
|
+
const apiClientRef = (0, import_react4.useRef)(null);
|
|
1498
|
+
const sessionIdRef = (0, import_react4.useRef)(`sess_${(0, import_core6.newUuid)()}`);
|
|
1499
|
+
const breadcrumbsRef = (0, import_react4.useRef)(
|
|
1500
|
+
(0, import_core6.createBreadcrumbBuffer)({ max: config.capture?.maxBreadcrumbs ?? 50 })
|
|
1269
1501
|
);
|
|
1270
|
-
const [sheetVisible, setSheetVisible] = (0,
|
|
1271
|
-
const [
|
|
1272
|
-
const
|
|
1502
|
+
const [sheetVisible, setSheetVisible] = (0, import_react4.useState)(false);
|
|
1503
|
+
const [sheetPreferredTab, setSheetPreferredTab] = (0, import_react4.useState)("report");
|
|
1504
|
+
const [bannerDismissed, setBannerDismissed] = (0, import_react4.useState)(false);
|
|
1505
|
+
const [sheetScreenshot, setSheetScreenshot] = (0, import_react4.useState)(null);
|
|
1506
|
+
const reporterTokenRef = (0, import_react4.useRef)(`rn-${config.projectId}-anon`);
|
|
1273
1507
|
let resolveReporterTokenReady = () => {
|
|
1274
1508
|
};
|
|
1275
|
-
const reporterTokenReadyRef = (0,
|
|
1509
|
+
const reporterTokenReadyRef = (0, import_react4.useRef)(
|
|
1276
1510
|
new Promise((resolve) => {
|
|
1277
1511
|
resolveReporterTokenReady = resolve;
|
|
1278
1512
|
})
|
|
1279
1513
|
);
|
|
1280
|
-
const userTokenRef = (0,
|
|
1281
|
-
const pageContextRef = (0,
|
|
1514
|
+
const userTokenRef = (0, import_react4.useRef)(null);
|
|
1515
|
+
const pageContextRef = (0, import_react4.useRef)(null);
|
|
1282
1516
|
const rawEndpoint = config.apiEndpoint ?? config.endpoint;
|
|
1283
1517
|
if (rawEndpoint !== void 0 && rawEndpoint.trim() === "") {
|
|
1284
1518
|
throw new Error(
|
|
@@ -1288,15 +1522,15 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1288
1522
|
if (config.endpoint && !config.apiEndpoint && __DEV__) {
|
|
1289
1523
|
console.warn("[MushiProvider] `endpoint` is deprecated \u2014 use `apiEndpoint` instead.");
|
|
1290
1524
|
}
|
|
1291
|
-
const apiEndpoint = rawEndpoint ??
|
|
1292
|
-
(0,
|
|
1525
|
+
const apiEndpoint = rawEndpoint ?? import_core6.DEFAULT_API_ENDPOINT;
|
|
1526
|
+
(0, import_react4.useEffect)(() => {
|
|
1293
1527
|
if (config.capture?.console !== false) {
|
|
1294
1528
|
consoleRef.current = setupConsoleCapture(config.capture?.maxConsoleEntries);
|
|
1295
1529
|
}
|
|
1296
1530
|
if (config.capture?.network !== false) {
|
|
1297
1531
|
networkRef.current = setupNetworkCapture(config.capture?.maxNetworkEntries, apiEndpoint);
|
|
1298
1532
|
}
|
|
1299
|
-
apiClientRef.current = (0,
|
|
1533
|
+
apiClientRef.current = (0, import_core6.createApiClient)({
|
|
1300
1534
|
projectId: config.projectId,
|
|
1301
1535
|
apiKey: config.apiKey,
|
|
1302
1536
|
apiEndpoint,
|
|
@@ -1333,14 +1567,14 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1333
1567
|
if (existing && existing.startsWith("mushi_")) {
|
|
1334
1568
|
reporterTokenRef.current = existing;
|
|
1335
1569
|
} else {
|
|
1336
|
-
const fresh = `mushi_${(0,
|
|
1570
|
+
const fresh = `mushi_${(0, import_core6.newUuid)()}`;
|
|
1337
1571
|
reporterTokenRef.current = fresh;
|
|
1338
1572
|
await saveReporterToken(fresh, secureStorage);
|
|
1339
1573
|
}
|
|
1340
1574
|
resolveReporterTokenReady();
|
|
1341
1575
|
} catch {
|
|
1342
1576
|
if (reporterTokenRef.current === `rn-${config.projectId}-anon`) {
|
|
1343
|
-
reporterTokenRef.current = `mushi_${(0,
|
|
1577
|
+
reporterTokenRef.current = `mushi_${(0, import_core6.newUuid)()}`;
|
|
1344
1578
|
}
|
|
1345
1579
|
resolveReporterTokenReady();
|
|
1346
1580
|
}
|
|
@@ -1351,7 +1585,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1351
1585
|
networkRef.current?.restore();
|
|
1352
1586
|
};
|
|
1353
1587
|
}, []);
|
|
1354
|
-
(0,
|
|
1588
|
+
(0, import_react4.useEffect)(() => {
|
|
1355
1589
|
let unsubscribe;
|
|
1356
1590
|
try {
|
|
1357
1591
|
const NetInfo = require("@react-native-community/netinfo").default;
|
|
@@ -1365,7 +1599,8 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1365
1599
|
}
|
|
1366
1600
|
return () => unsubscribe?.();
|
|
1367
1601
|
}, []);
|
|
1368
|
-
const open = (0,
|
|
1602
|
+
const open = (0, import_react4.useCallback)(() => {
|
|
1603
|
+
setSheetPreferredTab("report");
|
|
1369
1604
|
breadcrumbsRef.current.add({
|
|
1370
1605
|
category: "lifecycle",
|
|
1371
1606
|
level: "info",
|
|
@@ -1395,9 +1630,15 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1395
1630
|
setSheetVisible(true);
|
|
1396
1631
|
});
|
|
1397
1632
|
}, [config.capture?.screenshot]);
|
|
1398
|
-
const
|
|
1399
|
-
|
|
1400
|
-
|
|
1633
|
+
const openAssistant = (0, import_react4.useCallback)(() => {
|
|
1634
|
+
if (!config.assistant?.enabled) return;
|
|
1635
|
+
setSheetPreferredTab("assistant");
|
|
1636
|
+
setSheetScreenshot(null);
|
|
1637
|
+
setSheetVisible(true);
|
|
1638
|
+
}, [config.assistant?.enabled]);
|
|
1639
|
+
const close = (0, import_react4.useCallback)(() => setSheetVisible(false), []);
|
|
1640
|
+
const attachTo = (0, import_react4.useCallback)(() => ({ onPress: open }), [open]);
|
|
1641
|
+
(0, import_react4.useEffect)(() => {
|
|
1401
1642
|
const trigger2 = config.widget?.trigger ?? "button";
|
|
1402
1643
|
if (trigger2 !== "shake" && trigger2 !== "both") return;
|
|
1403
1644
|
let disposed = false;
|
|
@@ -1425,8 +1666,9 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1425
1666
|
cleanup?.();
|
|
1426
1667
|
};
|
|
1427
1668
|
}, [config.widget?.trigger, config.widget?.shakeThreshold, open]);
|
|
1428
|
-
const submitReport = (0,
|
|
1669
|
+
const submitReport = (0, import_react4.useCallback)(
|
|
1429
1670
|
async (data) => {
|
|
1671
|
+
await reporterTokenReadyRef.current;
|
|
1430
1672
|
const deviceInfo = getDeviceInfo();
|
|
1431
1673
|
breadcrumbsRef.current.add({
|
|
1432
1674
|
category: "lifecycle",
|
|
@@ -1452,7 +1694,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1452
1694
|
const merged = Object.keys(metadataRef.current).length > 0 ? { ...contextMeta, ...metadataRef.current } : Object.keys(contextMeta).length > 0 ? contextMeta : void 0;
|
|
1453
1695
|
const breadcrumbs = breadcrumbsRef.current.getAll().map((c) => ({
|
|
1454
1696
|
...c,
|
|
1455
|
-
message: (0,
|
|
1697
|
+
message: (0, import_core6.scrubPii)(c.message)
|
|
1456
1698
|
}));
|
|
1457
1699
|
const timeline = breadcrumbs.map((c) => ({
|
|
1458
1700
|
ts: c.timestamp,
|
|
@@ -1461,10 +1703,10 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1461
1703
|
}));
|
|
1462
1704
|
const fingerprintHash = getDeviceFingerprintHash(deviceInfo);
|
|
1463
1705
|
const report = {
|
|
1464
|
-
id: (0,
|
|
1706
|
+
id: (0, import_core6.newUuid)(),
|
|
1465
1707
|
projectId: config.projectId,
|
|
1466
1708
|
category: data.category,
|
|
1467
|
-
description: (0,
|
|
1709
|
+
description: (0, import_core6.scrubPii)(data.description),
|
|
1468
1710
|
environment: {
|
|
1469
1711
|
userAgent: deviceInfo.systemName ?? "ReactNative",
|
|
1470
1712
|
platform: deviceInfo.platform ?? "mobile",
|
|
@@ -1477,7 +1719,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1477
1719
|
},
|
|
1478
1720
|
consoleLogs: (consoleRef.current?.getEntries() ?? []).map((entry) => ({
|
|
1479
1721
|
...entry,
|
|
1480
|
-
message: (0,
|
|
1722
|
+
message: (0, import_core6.scrubPii)(entry.message)
|
|
1481
1723
|
})),
|
|
1482
1724
|
networkLogs: networkRef.current?.getEntries().map((entry) => ({
|
|
1483
1725
|
...entry,
|
|
@@ -1501,8 +1743,9 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1501
1743
|
if (!result.ok) {
|
|
1502
1744
|
const isCredentialError = result.error?.code === "HTTP_401" || result.error?.code === "HTTP_403" || result.error?.code?.includes("UNAUTHORIZED") || result.error?.code?.includes("FORBIDDEN");
|
|
1503
1745
|
if (isCredentialError) {
|
|
1746
|
+
const where = apiEndpoint.replace(/\/$/, "") === import_core6.DEFAULT_API_ENDPOINT ? "Get the correct values at: https://kensaur.us/mushi-mushi/admin/projects" : "Get the correct values from your Mushi console's Projects page.";
|
|
1504
1747
|
console.error(
|
|
1505
|
-
'[Mushi] Credentials rejected. Check your projectId and apiKey (must have "report:write" scope).
|
|
1748
|
+
'[Mushi] Credentials rejected. Check your projectId and apiKey (must have "report:write" scope). ' + where
|
|
1506
1749
|
);
|
|
1507
1750
|
return;
|
|
1508
1751
|
}
|
|
@@ -1514,12 +1757,12 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1514
1757
|
},
|
|
1515
1758
|
[config.projectId, config.callbacks, apiEndpoint]
|
|
1516
1759
|
);
|
|
1517
|
-
const userRef = (0,
|
|
1518
|
-
const metadataRef = (0,
|
|
1519
|
-
const screenRef = (0,
|
|
1520
|
-
const activityQueueRef = (0,
|
|
1521
|
-
const rewardsFlushRef = (0,
|
|
1522
|
-
(0,
|
|
1760
|
+
const userRef = (0, import_react4.useRef)(null);
|
|
1761
|
+
const metadataRef = (0, import_react4.useRef)({});
|
|
1762
|
+
const screenRef = (0, import_react4.useRef)(null);
|
|
1763
|
+
const activityQueueRef = (0, import_react4.useRef)([]);
|
|
1764
|
+
const rewardsFlushRef = (0, import_react4.useRef)(null);
|
|
1765
|
+
(0, import_react4.useEffect)(() => {
|
|
1523
1766
|
const rewards = config.rewards;
|
|
1524
1767
|
if (!rewards?.enabled || !rewards.trackActivity) return;
|
|
1525
1768
|
const flushMs = Math.max(3e4, rewards.flushIntervalMs ?? 3e5);
|
|
@@ -1539,7 +1782,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1539
1782
|
if (rewardsFlushRef.current) clearInterval(rewardsFlushRef.current);
|
|
1540
1783
|
};
|
|
1541
1784
|
}, [config.rewards?.enabled, config.rewards?.trackActivity, config.rewards?.flushIntervalMs]);
|
|
1542
|
-
const instance = (0,
|
|
1785
|
+
const instance = (0, import_react4.useMemo)(
|
|
1543
1786
|
() => ({
|
|
1544
1787
|
open,
|
|
1545
1788
|
close,
|
|
@@ -1568,7 +1811,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1568
1811
|
identifyWithToken(token) {
|
|
1569
1812
|
userTokenRef.current = token && typeof token === "string" ? token : null;
|
|
1570
1813
|
if (userTokenRef.current) {
|
|
1571
|
-
const claims = (0,
|
|
1814
|
+
const claims = (0, import_core6.parseIdentityToken)(userTokenRef.current);
|
|
1572
1815
|
if (claims?.sub) {
|
|
1573
1816
|
userRef.current = {
|
|
1574
1817
|
id: claims.sub,
|
|
@@ -1669,15 +1912,36 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1669
1912
|
confirmedBugs: 0,
|
|
1670
1913
|
totalReports: 0
|
|
1671
1914
|
};
|
|
1915
|
+
},
|
|
1916
|
+
openAssistant,
|
|
1917
|
+
async askAssistant(message, threadId) {
|
|
1918
|
+
const client = apiClientRef.current;
|
|
1919
|
+
if (!client || !config.assistant?.enabled) return null;
|
|
1920
|
+
const res = await client.askAssistant({
|
|
1921
|
+
message,
|
|
1922
|
+
threadId: threadId ?? null,
|
|
1923
|
+
context: pageContextRef.current
|
|
1924
|
+
});
|
|
1925
|
+
return res.ok ? res.data : null;
|
|
1672
1926
|
}
|
|
1673
1927
|
}),
|
|
1674
|
-
[open, close, attachTo, submitReport, config.rewards?.enabled]
|
|
1928
|
+
[open, close, attachTo, submitReport, openAssistant, config.rewards?.enabled, config.assistant?.enabled]
|
|
1675
1929
|
);
|
|
1676
1930
|
const trigger = config.widget?.trigger ?? "button";
|
|
1677
|
-
const
|
|
1678
|
-
|
|
1931
|
+
const showBanner = trigger === "banner" && !bannerDismissed;
|
|
1932
|
+
const showFab = !showBanner && (trigger === "button" || trigger === "both" || trigger === "auto" || trigger === "edge-tab");
|
|
1933
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(MushiContext.Provider, { value: instance, children: [
|
|
1679
1934
|
children,
|
|
1680
|
-
|
|
1935
|
+
showBanner ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1936
|
+
MushiBanner,
|
|
1937
|
+
{
|
|
1938
|
+
onPress: open,
|
|
1939
|
+
onDismiss: () => setBannerDismissed(true),
|
|
1940
|
+
message: config.widget?.banner?.message,
|
|
1941
|
+
label: config.widget?.banner?.label
|
|
1942
|
+
}
|
|
1943
|
+
) : null,
|
|
1944
|
+
showFab && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1681
1945
|
MushiFloatingButton,
|
|
1682
1946
|
{
|
|
1683
1947
|
onPress: open,
|
|
@@ -1685,20 +1949,26 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1685
1949
|
inset: config.widget?.inset
|
|
1686
1950
|
}
|
|
1687
1951
|
),
|
|
1688
|
-
/* @__PURE__ */ (0,
|
|
1952
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1689
1953
|
MushiBottomSheet,
|
|
1690
1954
|
{
|
|
1691
1955
|
visible: sheetVisible,
|
|
1692
1956
|
onClose: close,
|
|
1957
|
+
preferredTab: sheetPreferredTab,
|
|
1693
1958
|
screenshotDataUrl: sheetScreenshot ?? void 0,
|
|
1694
1959
|
onClearScreenshot: () => setSheetScreenshot(null),
|
|
1695
|
-
screenshotSensitiveHint: resolveScreenshotHint(config.widget?.screenshotSensitiveHint)
|
|
1960
|
+
screenshotSensitiveHint: resolveScreenshotHint(config.widget?.screenshotSensitiveHint),
|
|
1961
|
+
assistantEnabled: Boolean(config.assistant?.enabled),
|
|
1962
|
+
assistantLabel: config.assistant?.label,
|
|
1963
|
+
assistantGreeting: config.assistant?.greeting,
|
|
1964
|
+
assistantSuggestions: config.assistant?.suggestions,
|
|
1965
|
+
inboxPollIntervalMs: config.widget?.inboxPollIntervalMs ?? 0
|
|
1696
1966
|
}
|
|
1697
1967
|
)
|
|
1698
1968
|
] });
|
|
1699
1969
|
}
|
|
1700
1970
|
function useMushiContext() {
|
|
1701
|
-
return (0,
|
|
1971
|
+
return (0, import_react4.useContext)(MushiContext);
|
|
1702
1972
|
}
|
|
1703
1973
|
|
|
1704
1974
|
// src/hooks/useMushi.ts
|
|
@@ -1707,10 +1977,10 @@ function useMushi() {
|
|
|
1707
1977
|
}
|
|
1708
1978
|
|
|
1709
1979
|
// src/hooks/useMushiReport.ts
|
|
1710
|
-
var
|
|
1980
|
+
var import_react5 = require("react");
|
|
1711
1981
|
function useMushiReport() {
|
|
1712
1982
|
const mushi = useMushiContext();
|
|
1713
|
-
const submitReport = (0,
|
|
1983
|
+
const submitReport = (0, import_react5.useCallback)(
|
|
1714
1984
|
async (data) => {
|
|
1715
1985
|
if (!mushi) throw new Error("MushiProvider not found");
|
|
1716
1986
|
await mushi.submitReport(data);
|
|
@@ -1721,22 +1991,22 @@ function useMushiReport() {
|
|
|
1721
1991
|
}
|
|
1722
1992
|
|
|
1723
1993
|
// src/hooks/useMushiWidget.ts
|
|
1724
|
-
var
|
|
1994
|
+
var import_react6 = require("react");
|
|
1725
1995
|
function useMushiWidget() {
|
|
1726
1996
|
const mushi = useMushiContext();
|
|
1727
1997
|
return {
|
|
1728
|
-
open: (0,
|
|
1729
|
-
close: (0,
|
|
1998
|
+
open: (0, import_react6.useCallback)(() => mushi?.open(), [mushi]),
|
|
1999
|
+
close: (0, import_react6.useCallback)(() => mushi?.close(), [mushi])
|
|
1730
2000
|
};
|
|
1731
2001
|
}
|
|
1732
2002
|
|
|
1733
2003
|
// src/components/MushiTrigger.tsx
|
|
1734
|
-
var
|
|
2004
|
+
var import_react7 = require("react");
|
|
1735
2005
|
function MushiTrigger({ children }) {
|
|
1736
2006
|
const mushi = useMushiContext();
|
|
1737
|
-
if (!(0,
|
|
2007
|
+
if (!(0, import_react7.isValidElement)(children)) return children;
|
|
1738
2008
|
const originalOnPress = children.props.onPress;
|
|
1739
|
-
return (0,
|
|
2009
|
+
return (0, import_react7.cloneElement)(children, {
|
|
1740
2010
|
onPress: () => {
|
|
1741
2011
|
originalOnPress?.();
|
|
1742
2012
|
mushi?.open();
|
|
@@ -1745,10 +2015,10 @@ function MushiTrigger({ children }) {
|
|
|
1745
2015
|
}
|
|
1746
2016
|
|
|
1747
2017
|
// src/capture/navigation-capture.ts
|
|
1748
|
-
var
|
|
2018
|
+
var import_react8 = require("react");
|
|
1749
2019
|
function useNavigationCapture(navigationRef) {
|
|
1750
|
-
const historyRef = (0,
|
|
1751
|
-
(0,
|
|
2020
|
+
const historyRef = (0, import_react8.useRef)([]);
|
|
2021
|
+
(0, import_react8.useEffect)(() => {
|
|
1752
2022
|
if (!navigationRef?.addListener || !navigationRef?.getCurrentRoute) return;
|
|
1753
2023
|
const unsubscribe = navigationRef.addListener("state", () => {
|
|
1754
2024
|
const route = navigationRef.getCurrentRoute?.();
|
|
@@ -1764,6 +2034,8 @@ function useNavigationCapture(navigationRef) {
|
|
|
1764
2034
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1765
2035
|
0 && (module.exports = {
|
|
1766
2036
|
AsyncStorageQueue,
|
|
2037
|
+
MUSHI_BANNER_DEFAULT_HEIGHT,
|
|
2038
|
+
MushiBanner,
|
|
1767
2039
|
MushiBottomSheet,
|
|
1768
2040
|
MushiFloatingButton,
|
|
1769
2041
|
MushiProvider,
|