@mushi-mushi/web 1.7.2 → 1.7.6
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 +61 -1
- package/dist/index.cjs +279 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +280 -127
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createLogger, noopLogger, createApiClient, createPreFilter, createOfflineQueue, createRateLimiter, createPiiScrubber, createBreadcrumbBuffer, getReporterToken, getDeviceFingerprintHash, getSessionId, captureEnvironment, DEFAULT_API_ENDPOINT, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INTERNAL_HEADER, normaliseThrown } from '@mushi-mushi/core';
|
|
1
|
+
import { createLogger, noopLogger, createApiClient, createPreFilter, createOfflineQueue, createRateLimiter, createPiiScrubber, createBreadcrumbBuffer, getReporterToken, getDeviceFingerprintHash, getSessionId, captureEnvironment, newUuid, DEFAULT_API_ENDPOINT, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INTERNAL_HEADER, normaliseThrown } from '@mushi-mushi/core';
|
|
2
2
|
|
|
3
3
|
// src/mushi.ts
|
|
4
4
|
|
|
@@ -263,9 +263,9 @@ function getWidgetStyles(theme) {
|
|
|
263
263
|
const inkFaint = isDark ? "#5A5650" : "#9A9489";
|
|
264
264
|
const rule = isDark ? "rgba(242,235,221,0.10)" : "rgba(14,13,11,0.10)";
|
|
265
265
|
const ruleStrong = isDark ? "rgba(242,235,221,0.18)" : "rgba(14,13,11,0.16)";
|
|
266
|
-
const
|
|
267
|
-
const
|
|
268
|
-
const
|
|
266
|
+
const widgetAccent = isDark ? "#FF5A47" : "#E03C2C";
|
|
267
|
+
const widgetAccentWash = isDark ? "rgba(255,90,71,0.12)" : "rgba(224,60,44,0.08)";
|
|
268
|
+
const widgetAccentInk = isDark ? "#FFE5E0" : "#7A1F15";
|
|
269
269
|
const fontDisplay = `'Iowan Old Style', 'Palatino Linotype', 'Palatino', 'Book Antiqua', 'Cambria', Georgia, 'Times New Roman', serif`;
|
|
270
270
|
const fontBody = `system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI Variable Display', 'Segoe UI', sans-serif`;
|
|
271
271
|
const fontMono = `ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, 'Liberation Mono', monospace`;
|
|
@@ -281,6 +281,17 @@ function getWidgetStyles(theme) {
|
|
|
281
281
|
-moz-osx-font-smoothing: grayscale;
|
|
282
282
|
font-feature-settings: 'ss01', 'cv11'; /* nicer system-ui glyphs where supported */
|
|
283
283
|
--mushi-ok: ${isDark ? "#4ade80" : "#16a34a"};
|
|
284
|
+
/* SDK contract: the host element is always pass-through. Only the
|
|
285
|
+
interactive surfaces (.mushi-trigger, .mushi-banner, .mushi-panel)
|
|
286
|
+
opt back into pointer events so the widget never creates an
|
|
287
|
+
invisible touch blocker over host-app UI. */
|
|
288
|
+
pointer-events: none;
|
|
289
|
+
}
|
|
290
|
+
/* Only actual widget controls receive touch/mouse events. */
|
|
291
|
+
.mushi-trigger,
|
|
292
|
+
.mushi-banner,
|
|
293
|
+
.mushi-panel {
|
|
294
|
+
pointer-events: auto;
|
|
284
295
|
}
|
|
285
296
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
286
297
|
button { font-family: inherit; }
|
|
@@ -303,7 +314,7 @@ function getWidgetStyles(theme) {
|
|
|
303
314
|
box-shadow:
|
|
304
315
|
0 1px 0 ${rule},
|
|
305
316
|
0 6px 14px -8px rgba(14,13,11,0.35),
|
|
306
|
-
inset 0 -3px 0 ${
|
|
317
|
+
inset 0 -3px 0 ${widgetAccent};
|
|
307
318
|
transition: transform 200ms ${easeStamp}, box-shadow 200ms ${easeStamp};
|
|
308
319
|
overflow: visible;
|
|
309
320
|
isolation: isolate;
|
|
@@ -316,8 +327,8 @@ function getWidgetStyles(theme) {
|
|
|
316
327
|
width: 6px;
|
|
317
328
|
height: 6px;
|
|
318
329
|
border-radius: 50%;
|
|
319
|
-
background: ${
|
|
320
|
-
box-shadow: 0 0 0 0 ${
|
|
330
|
+
background: ${widgetAccent};
|
|
331
|
+
box-shadow: 0 0 0 0 ${widgetAccent};
|
|
321
332
|
animation: mushi-pulse 2.4s ${easeStamp} infinite;
|
|
322
333
|
}
|
|
323
334
|
.mushi-trigger:hover {
|
|
@@ -325,17 +336,17 @@ function getWidgetStyles(theme) {
|
|
|
325
336
|
box-shadow:
|
|
326
337
|
0 1px 0 ${rule},
|
|
327
338
|
0 14px 24px -10px rgba(14,13,11,0.45),
|
|
328
|
-
inset 0 -3px 0 ${
|
|
339
|
+
inset 0 -3px 0 ${widgetAccent};
|
|
329
340
|
}
|
|
330
341
|
.mushi-trigger:active {
|
|
331
342
|
transform: translateY(0) rotate(0);
|
|
332
343
|
box-shadow:
|
|
333
344
|
0 1px 0 ${rule},
|
|
334
345
|
0 2px 4px -2px rgba(14,13,11,0.35),
|
|
335
|
-
inset 0 -2px 0 ${
|
|
346
|
+
inset 0 -2px 0 ${widgetAccent};
|
|
336
347
|
}
|
|
337
348
|
.mushi-trigger:focus-visible {
|
|
338
|
-
outline: 2px solid ${
|
|
349
|
+
outline: 2px solid ${widgetAccent};
|
|
339
350
|
outline-offset: 3px;
|
|
340
351
|
}
|
|
341
352
|
/* First-session welcome pulse. Three soft halos at 800ms each, then
|
|
@@ -379,7 +390,7 @@ function getWidgetStyles(theme) {
|
|
|
379
390
|
box-shadow:
|
|
380
391
|
0 1px 0 ${rule},
|
|
381
392
|
0 10px 24px -14px rgba(14,13,11,0.45),
|
|
382
|
-
inset -3px 0 0 ${
|
|
393
|
+
inset -3px 0 0 ${widgetAccent};
|
|
383
394
|
}
|
|
384
395
|
.mushi-trigger.edge-tab.bottom-right,
|
|
385
396
|
.mushi-trigger.edge-tab.top-right {
|
|
@@ -392,7 +403,7 @@ function getWidgetStyles(theme) {
|
|
|
392
403
|
box-shadow:
|
|
393
404
|
0 1px 0 ${rule},
|
|
394
405
|
0 10px 24px -14px rgba(14,13,11,0.45),
|
|
395
|
-
inset 3px 0 0 ${
|
|
406
|
+
inset 3px 0 0 ${widgetAccent};
|
|
396
407
|
}
|
|
397
408
|
.mushi-trigger.shrunk {
|
|
398
409
|
width: 36px;
|
|
@@ -402,7 +413,7 @@ function getWidgetStyles(theme) {
|
|
|
402
413
|
}
|
|
403
414
|
|
|
404
415
|
@keyframes mushi-pulse {
|
|
405
|
-
0% { box-shadow: 0 0 0 0 ${
|
|
416
|
+
0% { box-shadow: 0 0 0 0 ${widgetAccent}; opacity: 1; }
|
|
406
417
|
70% { box-shadow: 0 0 0 8px rgba(224,60,44,0); opacity: 0.5; }
|
|
407
418
|
100% { box-shadow: 0 0 0 0 rgba(224,60,44,0); opacity: 1; }
|
|
408
419
|
}
|
|
@@ -449,9 +460,9 @@ function getWidgetStyles(theme) {
|
|
|
449
460
|
.mushi-outdated {
|
|
450
461
|
margin: 12px 14px 0;
|
|
451
462
|
padding: 10px 12px;
|
|
452
|
-
border: 1px solid ${
|
|
453
|
-
background: ${
|
|
454
|
-
color: ${
|
|
463
|
+
border: 1px solid ${widgetAccentWash};
|
|
464
|
+
background: ${widgetAccentWash};
|
|
465
|
+
color: ${widgetAccentInk};
|
|
455
466
|
font-family: ${fontBody};
|
|
456
467
|
font-size: 12px;
|
|
457
468
|
line-height: 1.4;
|
|
@@ -491,7 +502,7 @@ function getWidgetStyles(theme) {
|
|
|
491
502
|
width: 22px;
|
|
492
503
|
height: 22px;
|
|
493
504
|
border-radius: 3px;
|
|
494
|
-
background: ${
|
|
505
|
+
background: ${widgetAccent};
|
|
495
506
|
color: #FAF7F0;
|
|
496
507
|
font-family: ${fontDisplay};
|
|
497
508
|
font-size: 14px;
|
|
@@ -552,9 +563,9 @@ function getWidgetStyles(theme) {
|
|
|
552
563
|
border-radius: 3px;
|
|
553
564
|
transition: color 150ms ${easeStamp};
|
|
554
565
|
}
|
|
555
|
-
.mushi-close:hover, .mushi-back:hover { color: ${
|
|
566
|
+
.mushi-close:hover, .mushi-back:hover { color: ${widgetAccent}; }
|
|
556
567
|
.mushi-close:focus-visible, .mushi-back:focus-visible {
|
|
557
|
-
outline: 1.5px solid ${
|
|
568
|
+
outline: 1.5px solid ${widgetAccent};
|
|
558
569
|
outline-offset: 2px;
|
|
559
570
|
}
|
|
560
571
|
|
|
@@ -589,12 +600,12 @@ function getWidgetStyles(theme) {
|
|
|
589
600
|
position: relative;
|
|
590
601
|
}
|
|
591
602
|
.mushi-option-btn:last-child { border-bottom: none; }
|
|
592
|
-
.mushi-option-btn:hover { padding-left: 6px; color: ${
|
|
593
|
-
.mushi-option-btn:hover .mushi-option-arrow { opacity: 1; transform: translateX(0); color: ${
|
|
603
|
+
.mushi-option-btn:hover { padding-left: 6px; color: ${widgetAccent}; }
|
|
604
|
+
.mushi-option-btn:hover .mushi-option-arrow { opacity: 1; transform: translateX(0); color: ${widgetAccent}; }
|
|
594
605
|
.mushi-option-btn:focus-visible {
|
|
595
606
|
outline: none;
|
|
596
607
|
padding-left: 6px;
|
|
597
|
-
box-shadow: inset 2px 0 0 ${
|
|
608
|
+
box-shadow: inset 2px 0 0 ${widgetAccent};
|
|
598
609
|
}
|
|
599
610
|
.mushi-option-icon {
|
|
600
611
|
font-size: 18px;
|
|
@@ -636,7 +647,7 @@ function getWidgetStyles(theme) {
|
|
|
636
647
|
}
|
|
637
648
|
.mushi-feature-entry:hover,
|
|
638
649
|
.mushi-reports-entry:hover {
|
|
639
|
-
border-left-color: ${
|
|
650
|
+
border-left-color: ${widgetAccent};
|
|
640
651
|
padding-left: 14px;
|
|
641
652
|
}
|
|
642
653
|
.mushi-feature-entry .mushi-option-icon {
|
|
@@ -659,7 +670,7 @@ function getWidgetStyles(theme) {
|
|
|
659
670
|
.mushi-report-status {
|
|
660
671
|
font-family: ${fontMono};
|
|
661
672
|
font-size: 10px;
|
|
662
|
-
color: ${
|
|
673
|
+
color: ${widgetAccent};
|
|
663
674
|
text-transform: uppercase;
|
|
664
675
|
}
|
|
665
676
|
.mushi-report-title {
|
|
@@ -676,7 +687,7 @@ function getWidgetStyles(theme) {
|
|
|
676
687
|
.mushi-thread-summary span {
|
|
677
688
|
font-family: ${fontMono};
|
|
678
689
|
font-size: 10px;
|
|
679
|
-
color: ${
|
|
690
|
+
color: ${widgetAccent};
|
|
680
691
|
text-transform: uppercase;
|
|
681
692
|
}
|
|
682
693
|
.mushi-thread {
|
|
@@ -692,8 +703,8 @@ function getWidgetStyles(theme) {
|
|
|
692
703
|
background: ${isDark ? "rgba(242,235,221,0.04)" : "rgba(14,13,11,0.03)"};
|
|
693
704
|
}
|
|
694
705
|
.mushi-thread-comment.reporter {
|
|
695
|
-
border-color: ${
|
|
696
|
-
background: ${
|
|
706
|
+
border-color: ${widgetAccentWash};
|
|
707
|
+
background: ${widgetAccentWash};
|
|
697
708
|
}
|
|
698
709
|
.mushi-thread-comment strong {
|
|
699
710
|
display: block;
|
|
@@ -710,16 +721,16 @@ function getWidgetStyles(theme) {
|
|
|
710
721
|
color: ${inkMuted};
|
|
711
722
|
line-height: 1.45;
|
|
712
723
|
}
|
|
713
|
-
.mushi-error-inline { color: ${
|
|
724
|
+
.mushi-error-inline { color: ${widgetAccent}; }
|
|
714
725
|
|
|
715
726
|
.mushi-selected-category {
|
|
716
727
|
display: inline-flex;
|
|
717
728
|
align-items: center;
|
|
718
729
|
gap: 8px;
|
|
719
730
|
padding: 6px 10px 6px 12px;
|
|
720
|
-
border-left: 2px solid ${
|
|
721
|
-
background: ${
|
|
722
|
-
color: ${
|
|
731
|
+
border-left: 2px solid ${widgetAccent};
|
|
732
|
+
background: ${widgetAccentWash};
|
|
733
|
+
color: ${widgetAccentInk};
|
|
723
734
|
font-family: ${fontMono};
|
|
724
735
|
font-size: 11px;
|
|
725
736
|
letter-spacing: 0.12em;
|
|
@@ -759,12 +770,12 @@ function getWidgetStyles(theme) {
|
|
|
759
770
|
transition: opacity 220ms ${easeStamp}, transform 220ms ${easeStamp};
|
|
760
771
|
}
|
|
761
772
|
.mushi-intent-btn:last-child { border-bottom: none; }
|
|
762
|
-
.mushi-intent-btn:hover { padding-left: 6px; color: ${
|
|
763
|
-
.mushi-intent-btn:hover::after { opacity: 1; transform: translateX(0); color: ${
|
|
773
|
+
.mushi-intent-btn:hover { padding-left: 6px; color: ${widgetAccent}; }
|
|
774
|
+
.mushi-intent-btn:hover::after { opacity: 1; transform: translateX(0); color: ${widgetAccent}; }
|
|
764
775
|
.mushi-intent-btn:focus-visible {
|
|
765
776
|
outline: none;
|
|
766
777
|
padding-left: 6px;
|
|
767
|
-
box-shadow: inset 2px 0 0 ${
|
|
778
|
+
box-shadow: inset 2px 0 0 ${widgetAccent};
|
|
768
779
|
}
|
|
769
780
|
|
|
770
781
|
/* Example starter chips \u2014 reduce first-report activation energy */
|
|
@@ -792,7 +803,7 @@ function getWidgetStyles(theme) {
|
|
|
792
803
|
background: ${isDark ? "rgba(242,235,221,0.06)" : "rgba(14,13,11,0.04)"};
|
|
793
804
|
}
|
|
794
805
|
.mushi-example-chip:focus-visible {
|
|
795
|
-
outline: 2px solid ${
|
|
806
|
+
outline: 2px solid ${widgetAccent};
|
|
796
807
|
outline-offset: 2px;
|
|
797
808
|
}
|
|
798
809
|
|
|
@@ -831,7 +842,7 @@ function getWidgetStyles(theme) {
|
|
|
831
842
|
color: ${inkFaint};
|
|
832
843
|
font-style: italic;
|
|
833
844
|
}
|
|
834
|
-
.mushi-textarea:focus { border-bottom-color: ${
|
|
845
|
+
.mushi-textarea:focus { border-bottom-color: ${widgetAccent}; }
|
|
835
846
|
|
|
836
847
|
.mushi-attachments {
|
|
837
848
|
display: flex;
|
|
@@ -860,30 +871,30 @@ function getWidgetStyles(theme) {
|
|
|
860
871
|
border-color: ${ink};
|
|
861
872
|
}
|
|
862
873
|
.mushi-attach-btn.active {
|
|
863
|
-
color: ${
|
|
864
|
-
border-color: ${
|
|
865
|
-
background: ${
|
|
874
|
+
color: ${widgetAccent};
|
|
875
|
+
border-color: ${widgetAccent};
|
|
876
|
+
background: ${widgetAccentWash};
|
|
866
877
|
}
|
|
867
878
|
.mushi-attach-btn.danger {
|
|
868
|
-
color: ${
|
|
869
|
-
border-color: ${
|
|
879
|
+
color: ${widgetAccentInk};
|
|
880
|
+
border-color: ${widgetAccentWash};
|
|
870
881
|
background: transparent;
|
|
871
882
|
}
|
|
872
883
|
.mushi-attach-btn.danger:hover {
|
|
873
|
-
color: ${
|
|
874
|
-
border-color: ${
|
|
875
|
-
background: ${
|
|
884
|
+
color: ${widgetAccent};
|
|
885
|
+
border-color: ${widgetAccent};
|
|
886
|
+
background: ${widgetAccentWash};
|
|
876
887
|
}
|
|
877
888
|
.mushi-attach-btn.loading {
|
|
878
889
|
opacity: 0.7;
|
|
879
890
|
cursor: wait;
|
|
880
891
|
}
|
|
881
892
|
.mushi-attach-btn.error {
|
|
882
|
-
color: ${
|
|
883
|
-
border-color: ${
|
|
893
|
+
color: ${widgetAccent};
|
|
894
|
+
border-color: ${widgetAccentWash};
|
|
884
895
|
}
|
|
885
896
|
.mushi-attach-btn:focus-visible {
|
|
886
|
-
outline: 2px solid ${
|
|
897
|
+
outline: 2px solid ${widgetAccent};
|
|
887
898
|
outline-offset: 2px;
|
|
888
899
|
}
|
|
889
900
|
@keyframes mushi-spin {
|
|
@@ -924,9 +935,9 @@ function getWidgetStyles(theme) {
|
|
|
924
935
|
align-items: center;
|
|
925
936
|
gap: 8px;
|
|
926
937
|
padding: 10px 18px;
|
|
927
|
-
border: 1px solid ${
|
|
938
|
+
border: 1px solid ${widgetAccent};
|
|
928
939
|
border-radius: 3px;
|
|
929
|
-
background: ${
|
|
940
|
+
background: ${widgetAccent};
|
|
930
941
|
color: #FAF7F0;
|
|
931
942
|
font-family: ${fontMono};
|
|
932
943
|
font-size: 11px;
|
|
@@ -958,7 +969,7 @@ function getWidgetStyles(theme) {
|
|
|
958
969
|
opacity: 0.7;
|
|
959
970
|
}
|
|
960
971
|
.mushi-submit:focus-visible {
|
|
961
|
-
outline: 2px solid ${
|
|
972
|
+
outline: 2px solid ${widgetAccent};
|
|
962
973
|
outline-offset: 3px;
|
|
963
974
|
}
|
|
964
975
|
.mushi-submit-arrow {
|
|
@@ -997,7 +1008,7 @@ function getWidgetStyles(theme) {
|
|
|
997
1008
|
}
|
|
998
1009
|
.mushi-step-num.done { color: ${inkMuted}; text-decoration: line-through; text-decoration-color: ${inkFaint}; }
|
|
999
1010
|
.mushi-step-num.active {
|
|
1000
|
-
color: ${
|
|
1011
|
+
color: ${widgetAccent};
|
|
1001
1012
|
font-family: ${fontDisplay};
|
|
1002
1013
|
font-size: 14px;
|
|
1003
1014
|
font-weight: 600;
|
|
@@ -1026,7 +1037,7 @@ function getWidgetStyles(theme) {
|
|
|
1026
1037
|
}
|
|
1027
1038
|
.mushi-success-stamp circle {
|
|
1028
1039
|
fill: none;
|
|
1029
|
-
stroke: ${
|
|
1040
|
+
stroke: ${widgetAccent};
|
|
1030
1041
|
stroke-width: 3;
|
|
1031
1042
|
stroke-dasharray: 280;
|
|
1032
1043
|
stroke-dashoffset: 280;
|
|
@@ -1038,7 +1049,7 @@ function getWidgetStyles(theme) {
|
|
|
1038
1049
|
font-family: ${fontDisplay};
|
|
1039
1050
|
font-size: 18px;
|
|
1040
1051
|
font-weight: 600;
|
|
1041
|
-
color: ${
|
|
1052
|
+
color: ${widgetAccent};
|
|
1042
1053
|
letter-spacing: 0.04em;
|
|
1043
1054
|
transform: rotate(-6deg);
|
|
1044
1055
|
opacity: 0;
|
|
@@ -1106,8 +1117,8 @@ function getWidgetStyles(theme) {
|
|
|
1106
1117
|
.mushi-success-receipt-id:hover,
|
|
1107
1118
|
.mushi-success-receipt-id:focus-visible {
|
|
1108
1119
|
background: rgba(217, 65, 47, 0.06);
|
|
1109
|
-
border-color: ${
|
|
1110
|
-
color: ${
|
|
1120
|
+
border-color: ${widgetAccent};
|
|
1121
|
+
color: ${widgetAccent};
|
|
1111
1122
|
outline: none;
|
|
1112
1123
|
}
|
|
1113
1124
|
.mushi-success-receipt-copy {
|
|
@@ -1121,7 +1132,7 @@ function getWidgetStyles(theme) {
|
|
|
1121
1132
|
gap: 4px;
|
|
1122
1133
|
padding: 6px 10px;
|
|
1123
1134
|
border-radius: 4px;
|
|
1124
|
-
background: ${
|
|
1135
|
+
background: ${widgetAccent};
|
|
1125
1136
|
color: #fff;
|
|
1126
1137
|
font-family: ${fontMono};
|
|
1127
1138
|
font-size: 11px;
|
|
@@ -1140,7 +1151,7 @@ function getWidgetStyles(theme) {
|
|
|
1140
1151
|
height: 11px;
|
|
1141
1152
|
border-radius: 50%;
|
|
1142
1153
|
border: 1.5px solid ${rule};
|
|
1143
|
-
border-top-color: ${
|
|
1154
|
+
border-top-color: ${widgetAccent};
|
|
1144
1155
|
animation: mushi-receipt-spin 0.8s linear infinite;
|
|
1145
1156
|
}
|
|
1146
1157
|
@keyframes mushi-receipt-spin {
|
|
@@ -1151,7 +1162,7 @@ function getWidgetStyles(theme) {
|
|
|
1151
1162
|
font-style: italic;
|
|
1152
1163
|
}
|
|
1153
1164
|
.mushi-success-receipt-warn {
|
|
1154
|
-
color: ${
|
|
1165
|
+
color: ${widgetAccent};
|
|
1155
1166
|
}
|
|
1156
1167
|
.mushi-success-sla {
|
|
1157
1168
|
margin-top: 2px;
|
|
@@ -1178,8 +1189,8 @@ function getWidgetStyles(theme) {
|
|
|
1178
1189
|
.mushi-error {
|
|
1179
1190
|
margin-top: 10px;
|
|
1180
1191
|
padding: 8px 0 8px 10px;
|
|
1181
|
-
border-left: 2px solid ${
|
|
1182
|
-
color: ${
|
|
1192
|
+
border-left: 2px solid ${widgetAccent};
|
|
1193
|
+
color: ${widgetAccent};
|
|
1183
1194
|
font-size: 12px;
|
|
1184
1195
|
font-family: ${fontMono};
|
|
1185
1196
|
letter-spacing: 0.02em;
|
|
@@ -1219,7 +1230,7 @@ function getWidgetStyles(theme) {
|
|
|
1219
1230
|
.mushi-rewards-pts-earn {
|
|
1220
1231
|
font-family: ${fontMono};
|
|
1221
1232
|
font-size: 10px;
|
|
1222
|
-
color: ${
|
|
1233
|
+
color: ${widgetAccent};
|
|
1223
1234
|
letter-spacing: 0.04em;
|
|
1224
1235
|
white-space: nowrap;
|
|
1225
1236
|
}
|
|
@@ -1232,7 +1243,7 @@ function getWidgetStyles(theme) {
|
|
|
1232
1243
|
}
|
|
1233
1244
|
.mushi-tier-bar-fill {
|
|
1234
1245
|
height: 100%;
|
|
1235
|
-
background: ${
|
|
1246
|
+
background: ${widgetAccent};
|
|
1236
1247
|
border-radius: 2px;
|
|
1237
1248
|
transition: width 600ms ${easeStamp};
|
|
1238
1249
|
}
|
|
@@ -1255,7 +1266,7 @@ function getWidgetStyles(theme) {
|
|
|
1255
1266
|
font-family: ${fontMono};
|
|
1256
1267
|
font-size: 22px;
|
|
1257
1268
|
font-weight: 700;
|
|
1258
|
-
color: ${
|
|
1269
|
+
color: ${widgetAccent};
|
|
1259
1270
|
text-align: center;
|
|
1260
1271
|
letter-spacing: 0.06em;
|
|
1261
1272
|
margin-bottom: 10px;
|
|
@@ -1270,13 +1281,17 @@ function getWidgetStyles(theme) {
|
|
|
1270
1281
|
}
|
|
1271
1282
|
|
|
1272
1283
|
/* \u2500\u2500\u2500 Beta mode strip (category step) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1284
|
+
/* Brand palette: widgetAccent (vermillion) + washi ink for the strip.
|
|
1285
|
+
The previous indigo (#6366f1) is the single most recognisable AI-template
|
|
1286
|
+
colour; replaced with the widget's own vermillion wash so the beta panel
|
|
1287
|
+
reads as a Mushi-native surface rather than a generic SaaS plug-in. */
|
|
1273
1288
|
|
|
1274
1289
|
.mushi-beta-strip {
|
|
1275
1290
|
margin: 0 16px 2px;
|
|
1276
1291
|
padding: 9px 12px;
|
|
1277
|
-
background:
|
|
1278
|
-
border: 1px solid rgba(
|
|
1279
|
-
border-radius:
|
|
1292
|
+
background: ${widgetAccentWash};
|
|
1293
|
+
border: 1px solid ${isDark ? "rgba(255,90,71,0.22)" : "rgba(224,60,44,0.16)"};
|
|
1294
|
+
border-radius: 4px;
|
|
1280
1295
|
display: flex;
|
|
1281
1296
|
flex-direction: column;
|
|
1282
1297
|
gap: 4px;
|
|
@@ -1292,38 +1307,30 @@ function getWidgetStyles(theme) {
|
|
|
1292
1307
|
display: inline-flex;
|
|
1293
1308
|
align-items: center;
|
|
1294
1309
|
padding: 1px 6px;
|
|
1295
|
-
border-radius:
|
|
1296
|
-
background:
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
font-family: var(--mushi-font-mono);
|
|
1310
|
+
border-radius: 3px;
|
|
1311
|
+
background: ${widgetAccent};
|
|
1312
|
+
color: #FAF7F0;
|
|
1313
|
+
font-family: ${fontMono};
|
|
1300
1314
|
font-size: 9px;
|
|
1301
1315
|
font-weight: 700;
|
|
1302
|
-
letter-spacing: 0.
|
|
1316
|
+
letter-spacing: 0.14em;
|
|
1303
1317
|
line-height: 1.6;
|
|
1304
1318
|
white-space: nowrap;
|
|
1305
1319
|
flex-shrink: 0;
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
@media (prefers-color-scheme: dark) {
|
|
1309
|
-
.mushi-beta-tag {
|
|
1310
|
-
background: rgba(245, 158, 11, 0.12);
|
|
1311
|
-
border-color: rgba(245, 158, 11, 0.28);
|
|
1312
|
-
color: #fbbf24;
|
|
1313
|
-
}
|
|
1320
|
+
text-transform: uppercase;
|
|
1314
1321
|
}
|
|
1315
1322
|
|
|
1316
1323
|
.mushi-beta-msg {
|
|
1317
1324
|
font-size: 11px;
|
|
1318
|
-
color:
|
|
1325
|
+
color: ${inkMuted};
|
|
1319
1326
|
line-height: 1.45;
|
|
1320
1327
|
}
|
|
1321
1328
|
|
|
1322
1329
|
.mushi-beta-contact-hint {
|
|
1323
1330
|
font-size: 10px;
|
|
1324
|
-
color:
|
|
1325
|
-
|
|
1326
|
-
|
|
1331
|
+
color: ${inkFaint};
|
|
1332
|
+
font-family: ${fontMono};
|
|
1333
|
+
letter-spacing: 0.06em;
|
|
1327
1334
|
}
|
|
1328
1335
|
|
|
1329
1336
|
.mushi-beta-perks {
|
|
@@ -1337,16 +1344,10 @@ function getWidgetStyles(theme) {
|
|
|
1337
1344
|
|
|
1338
1345
|
.mushi-beta-perks li {
|
|
1339
1346
|
font-size: 10.5px;
|
|
1340
|
-
color:
|
|
1347
|
+
color: ${widgetAccentInk};
|
|
1341
1348
|
font-weight: 500;
|
|
1342
1349
|
}
|
|
1343
1350
|
|
|
1344
|
-
@media (prefers-color-scheme: dark) {
|
|
1345
|
-
.mushi-beta-perks li {
|
|
1346
|
-
color: #818cf8;
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
1351
|
/* \u2500\u2500\u2500 Beta changelog (collapsible What's new) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1351
1352
|
|
|
1352
1353
|
.mushi-changelog {
|
|
@@ -1395,9 +1396,9 @@ function getWidgetStyles(theme) {
|
|
|
1395
1396
|
.mushi-beta-success-footer {
|
|
1396
1397
|
margin-top: 14px;
|
|
1397
1398
|
padding: 10px 14px;
|
|
1398
|
-
background:
|
|
1399
|
-
border: 1px solid rgba(
|
|
1400
|
-
border-radius:
|
|
1399
|
+
background: ${widgetAccentWash};
|
|
1400
|
+
border: 1px solid ${isDark ? "rgba(255,90,71,0.18)" : "rgba(224,60,44,0.14)"};
|
|
1401
|
+
border-radius: 4px;
|
|
1401
1402
|
display: flex;
|
|
1402
1403
|
flex-direction: column;
|
|
1403
1404
|
gap: 3px;
|
|
@@ -1458,9 +1459,9 @@ function getWidgetStyles(theme) {
|
|
|
1458
1459
|
background: rgba(0,0,0,0.22);
|
|
1459
1460
|
}
|
|
1460
1461
|
|
|
1461
|
-
/* --- brand variant (
|
|
1462
|
+
/* --- brand variant (widgetAccent \u2014 editorial, app-quality) --- */
|
|
1462
1463
|
.mushi-banner.brand {
|
|
1463
|
-
background: ${
|
|
1464
|
+
background: ${widgetAccent};
|
|
1464
1465
|
color: #fff;
|
|
1465
1466
|
border-bottom: 1.5px solid ${isDark ? "#C4321E" : "#B52F1F"};
|
|
1466
1467
|
}
|
|
@@ -1477,23 +1478,29 @@ function getWidgetStyles(theme) {
|
|
|
1477
1478
|
background: rgba(255,255,255,0.28);
|
|
1478
1479
|
}
|
|
1479
1480
|
|
|
1480
|
-
/* --- subtle variant (
|
|
1481
|
+
/* --- subtle variant (frosted-glass, muted \u2014 least disruptive) ---
|
|
1482
|
+
Uses the widget's own paper colour at high opacity + backdrop-blur so
|
|
1483
|
+
it blends with the host app while remaining legible. The previous 4-6%
|
|
1484
|
+
opacity values were effectively invisible \u2014 users could not distinguish
|
|
1485
|
+
the banner from the page content below it. */
|
|
1481
1486
|
.mushi-banner.subtle {
|
|
1482
|
-
background: ${isDark ? "rgba(
|
|
1483
|
-
|
|
1484
|
-
|
|
1487
|
+
background: ${isDark ? "rgba(15,14,12,0.88)" : "rgba(248,244,237,0.92)"};
|
|
1488
|
+
backdrop-filter: blur(14px);
|
|
1489
|
+
-webkit-backdrop-filter: blur(14px);
|
|
1490
|
+
color: ${ink};
|
|
1491
|
+
border-bottom: 1px solid ${ruleStrong};
|
|
1485
1492
|
}
|
|
1486
1493
|
.mushi-banner.subtle.bottom {
|
|
1487
|
-
border-top: 1px solid ${
|
|
1494
|
+
border-top: 1px solid ${ruleStrong};
|
|
1488
1495
|
border-bottom: none;
|
|
1489
1496
|
}
|
|
1490
1497
|
.mushi-banner.subtle .mushi-banner-btn {
|
|
1491
|
-
background: ${isDark ? "rgba(242,235,221,0.10)" : "rgba(14,13,11,0.
|
|
1498
|
+
background: ${isDark ? "rgba(242,235,221,0.10)" : "rgba(14,13,11,0.08)"};
|
|
1492
1499
|
color: ${ink};
|
|
1493
|
-
border: 1px solid ${
|
|
1500
|
+
border: 1px solid ${ruleStrong};
|
|
1494
1501
|
}
|
|
1495
1502
|
.mushi-banner.subtle .mushi-banner-btn:hover {
|
|
1496
|
-
background: ${isDark ? "rgba(242,235,221,0.
|
|
1503
|
+
background: ${isDark ? "rgba(242,235,221,0.18)" : "rgba(14,13,11,0.14)"};
|
|
1497
1504
|
}
|
|
1498
1505
|
|
|
1499
1506
|
.mushi-banner-label {
|
|
@@ -1518,7 +1525,7 @@ function getWidgetStyles(theme) {
|
|
|
1518
1525
|
line-height: 1;
|
|
1519
1526
|
}
|
|
1520
1527
|
.mushi-banner-btn:focus-visible {
|
|
1521
|
-
outline: 2px solid ${
|
|
1528
|
+
outline: 2px solid ${widgetAccent};
|
|
1522
1529
|
outline-offset: 2px;
|
|
1523
1530
|
}
|
|
1524
1531
|
|
|
@@ -1629,7 +1636,8 @@ var MushiWidget = class _MushiWidget {
|
|
|
1629
1636
|
responseSlaLabel: config.responseSlaLabel ?? "",
|
|
1630
1637
|
featureRequestCard: config.featureRequestCard ?? true,
|
|
1631
1638
|
featureRequestLabel: config.featureRequestLabel ?? "",
|
|
1632
|
-
featureRequestDescription: config.featureRequestDescription ?? ""
|
|
1639
|
+
featureRequestDescription: config.featureRequestDescription ?? "",
|
|
1640
|
+
avoidSelectors: config.avoidSelectors ?? []
|
|
1633
1641
|
};
|
|
1634
1642
|
this.callbacks = callbacks;
|
|
1635
1643
|
this.locale = getLocale(this.config.locale === "auto" ? void 0 : this.config.locale);
|
|
@@ -1706,6 +1714,7 @@ var MushiWidget = class _MushiWidget {
|
|
|
1706
1714
|
bannerDismissed = false;
|
|
1707
1715
|
mount() {
|
|
1708
1716
|
if (this.host.isConnected) return;
|
|
1717
|
+
this.syncHostChromeState();
|
|
1709
1718
|
document.body.appendChild(this.host);
|
|
1710
1719
|
this.syncAttachedLaunchers();
|
|
1711
1720
|
this.syncSmartHide();
|
|
@@ -1746,6 +1755,7 @@ var MushiWidget = class _MushiWidget {
|
|
|
1746
1755
|
...config.featureRequestDescription !== void 0 ? { featureRequestDescription: config.featureRequestDescription } : {}
|
|
1747
1756
|
};
|
|
1748
1757
|
this.locale = getLocale(this.config.locale === "auto" ? void 0 : this.config.locale);
|
|
1758
|
+
if (this.host.isConnected) this.syncHostChromeState();
|
|
1749
1759
|
this.syncAttachedLaunchers();
|
|
1750
1760
|
this.syncSmartHide();
|
|
1751
1761
|
this.render();
|
|
@@ -1978,6 +1988,59 @@ var MushiWidget = class _MushiWidget {
|
|
|
1978
1988
|
this.removeBodyNudge();
|
|
1979
1989
|
this.host.remove();
|
|
1980
1990
|
}
|
|
1991
|
+
/* ── Host chrome contract ────────────────────────────────────────────────
|
|
1992
|
+
The host element must never create an invisible full-screen touch blocker.
|
|
1993
|
+
We own these inline styles — consumer CSS can only win with `!important`,
|
|
1994
|
+
which is explicitly banned by the SDK contract. Calling this at mount()
|
|
1995
|
+
and after every zIndex update is the only safe invariant. */
|
|
1996
|
+
/**
|
|
1997
|
+
* Apply the SDK-owned pass-through layout to the host element so it is
|
|
1998
|
+
* always zero-sized and click/touch-transparent. Only the shadow-root
|
|
1999
|
+
* internals (`.mushi-trigger`, `.mushi-banner`, `.mushi-panel`) opt back
|
|
2000
|
+
* into pointer events. This is idempotent and safe to call repeatedly.
|
|
2001
|
+
*/
|
|
2002
|
+
syncHostChromeState() {
|
|
2003
|
+
const s = this.host.style;
|
|
2004
|
+
s.setProperty("position", "fixed");
|
|
2005
|
+
s.setProperty("top", "0");
|
|
2006
|
+
s.setProperty("left", "0");
|
|
2007
|
+
s.setProperty("width", "0");
|
|
2008
|
+
s.setProperty("height", "0");
|
|
2009
|
+
s.setProperty("overflow", "visible");
|
|
2010
|
+
s.setProperty("pointer-events", "none");
|
|
2011
|
+
s.setProperty("z-index", String(this.config.zIndex));
|
|
2012
|
+
s.setProperty("margin", "0");
|
|
2013
|
+
s.setProperty("padding", "0");
|
|
2014
|
+
s.setProperty("border", "none");
|
|
2015
|
+
s.setProperty("background", "none");
|
|
2016
|
+
}
|
|
2017
|
+
/**
|
|
2018
|
+
* Returns true when a DOM element matching `hideOnSelector` is currently
|
|
2019
|
+
* present in the host document. Used by both the trigger and the banner
|
|
2020
|
+
* so a single selector consistently hides ALL SDK-injected launcher
|
|
2021
|
+
* surfaces. Invalid selectors are swallowed silently (non-fatal).
|
|
2022
|
+
*/
|
|
2023
|
+
isSuppressedByHost() {
|
|
2024
|
+
if (!this.config.hideOnSelector || typeof document === "undefined") return false;
|
|
2025
|
+
try {
|
|
2026
|
+
return Boolean(document.querySelector(this.config.hideOnSelector));
|
|
2027
|
+
} catch {
|
|
2028
|
+
return false;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
/**
|
|
2032
|
+
* Returns a snapshot of the widget's host-layer health for use in
|
|
2033
|
+
* `Mushi.diagnose()`. Callers check this to know whether the widget
|
|
2034
|
+
* could ever block host-app UI without opening a browser devtools.
|
|
2035
|
+
*/
|
|
2036
|
+
getWidgetDiagnostics() {
|
|
2037
|
+
const s = this.host.style;
|
|
2038
|
+
const widgetHostPointerSafe = s.pointerEvents === "none" && (s.width === "0" || s.width === "0px") && (s.height === "0" || s.height === "0px");
|
|
2039
|
+
const widgetHostBounds = this.host.isConnected ? { width: this.host.offsetWidth, height: this.host.offsetHeight } : null;
|
|
2040
|
+
const widgetSuppressed = this.isSuppressedByHost() || this.isRouteHidden() || !this.triggerVisible;
|
|
2041
|
+
const bannerRendered = this.config.trigger === "banner" && !this.bannerDismissed && !this.isSuppressedByHost() && !this.isRouteHidden() && this.triggerVisible;
|
|
2042
|
+
return { widgetHostPointerSafe, widgetHostBounds, widgetSuppressed, bannerRendered };
|
|
2043
|
+
}
|
|
1981
2044
|
syncAttachedLaunchers() {
|
|
1982
2045
|
this.attachedLaunchers.forEach((cleanup) => cleanup());
|
|
1983
2046
|
this.attachedLaunchers = [];
|
|
@@ -2018,7 +2081,7 @@ var MushiWidget = class _MushiWidget {
|
|
|
2018
2081
|
}
|
|
2019
2082
|
if (this.isMobileSmartHidden()) return false;
|
|
2020
2083
|
if (this.isRouteHidden()) return false;
|
|
2021
|
-
if (this.
|
|
2084
|
+
if (this.isSuppressedByHost()) return false;
|
|
2022
2085
|
const action = this.config.environments[this.detectEnvironment()];
|
|
2023
2086
|
return action !== "never" && action !== "manual";
|
|
2024
2087
|
}
|
|
@@ -2067,6 +2130,10 @@ var MushiWidget = class _MushiWidget {
|
|
|
2067
2130
|
this.removeBodyNudge();
|
|
2068
2131
|
return;
|
|
2069
2132
|
}
|
|
2133
|
+
if (this.isSuppressedByHost()) {
|
|
2134
|
+
this.removeBodyNudge();
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2070
2137
|
const bc = this.config.bannerConfig ?? {};
|
|
2071
2138
|
const variant = bc.variant ?? "brand";
|
|
2072
2139
|
const position = bc.position ?? "top";
|
|
@@ -2185,6 +2252,32 @@ var MushiWidget = class _MushiWidget {
|
|
|
2185
2252
|
this.trapFocus(panel);
|
|
2186
2253
|
}
|
|
2187
2254
|
}
|
|
2255
|
+
/**
|
|
2256
|
+
* Queries each `avoidSelectors` element in the host document and returns
|
|
2257
|
+
* the minimum top-offset in px so that a top-anchored element clears all
|
|
2258
|
+
* of them by `gap` pixels. Returns `null` when no selectors are provided
|
|
2259
|
+
* or no matching elements have a non-zero bounding rect.
|
|
2260
|
+
*
|
|
2261
|
+
* Runs in the host document (not shadow DOM) so it can reach fixed headers,
|
|
2262
|
+
* sticky nav bars, and sign-in CTAs.
|
|
2263
|
+
*/
|
|
2264
|
+
computeAvoidTopPx(gap = 8) {
|
|
2265
|
+
const sels = this.config.avoidSelectors;
|
|
2266
|
+
if (!sels?.length) return null;
|
|
2267
|
+
let maxBottom = 0;
|
|
2268
|
+
for (const sel of sels) {
|
|
2269
|
+
try {
|
|
2270
|
+
const el = document.querySelector(sel);
|
|
2271
|
+
if (!el) continue;
|
|
2272
|
+
const r = el.getBoundingClientRect();
|
|
2273
|
+
if (r.bottom > maxBottom && r.width > 0 && r.height > 0) {
|
|
2274
|
+
maxBottom = r.bottom;
|
|
2275
|
+
}
|
|
2276
|
+
} catch {
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
return maxBottom > 0 ? Math.ceil(maxBottom) + gap : null;
|
|
2280
|
+
}
|
|
2188
2281
|
applyInsetVars(el) {
|
|
2189
2282
|
const { anchor } = this.config;
|
|
2190
2283
|
if (anchor && Object.keys(anchor).length > 0) {
|
|
@@ -2193,20 +2286,27 @@ var MushiWidget = class _MushiWidget {
|
|
|
2193
2286
|
if (value !== void 0) el.style.setProperty(`--mushi-${edge}`, value);
|
|
2194
2287
|
});
|
|
2195
2288
|
el.style.setProperty("--mushi-safe-area", this.config.respectSafeArea ? "1" : "0");
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2289
|
+
} else {
|
|
2290
|
+
const { inset } = this.config;
|
|
2291
|
+
if (!this.config.respectSafeArea) {
|
|
2292
|
+
["top", "right", "bottom", "left"].forEach((edge) => {
|
|
2293
|
+
if (inset[edge] === void 0) el.style.setProperty(`--mushi-${edge}`, "24px");
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2200
2296
|
["top", "right", "bottom", "left"].forEach((edge) => {
|
|
2201
|
-
|
|
2297
|
+
const value = inset[edge];
|
|
2298
|
+
if (value === void 0) return;
|
|
2299
|
+
el.style.setProperty(`--mushi-${edge}`, value === "auto" ? "auto" : `${value}px`);
|
|
2202
2300
|
});
|
|
2301
|
+
el.style.setProperty("--mushi-safe-area", this.config.respectSafeArea ? "1" : "0");
|
|
2302
|
+
}
|
|
2303
|
+
const isTopAnchored = anchor?.top !== void 0 || this.config.position?.startsWith("top") || !this.config.position && !anchor?.bottom;
|
|
2304
|
+
if (isTopAnchored) {
|
|
2305
|
+
const avoidPx = this.computeAvoidTopPx();
|
|
2306
|
+
if (avoidPx !== null) {
|
|
2307
|
+
el.style.setProperty("--mushi-top", `${avoidPx}px`);
|
|
2308
|
+
}
|
|
2203
2309
|
}
|
|
2204
|
-
["top", "right", "bottom", "left"].forEach((edge) => {
|
|
2205
|
-
const value = inset[edge];
|
|
2206
|
-
if (value === void 0) return;
|
|
2207
|
-
el.style.setProperty(`--mushi-${edge}`, value === "auto" ? "auto" : `${value}px`);
|
|
2208
|
-
});
|
|
2209
|
-
el.style.setProperty("--mushi-safe-area", this.config.respectSafeArea ? "1" : "0");
|
|
2210
2310
|
}
|
|
2211
2311
|
renderStep() {
|
|
2212
2312
|
switch (this.step) {
|
|
@@ -3040,6 +3140,15 @@ var optedIn = false;
|
|
|
3040
3140
|
var tierCache = null;
|
|
3041
3141
|
var tierCacheTime = 0;
|
|
3042
3142
|
var TIER_CACHE_TTL = 5 * 60 * 1e3;
|
|
3143
|
+
var rewardsApiBackoffUntil = 0;
|
|
3144
|
+
var REWARDS_4XX_BACKOFF_MS = 15 * 60 * 1e3;
|
|
3145
|
+
function isRewardsApiBackedOff() {
|
|
3146
|
+
return Date.now() < rewardsApiBackoffUntil;
|
|
3147
|
+
}
|
|
3148
|
+
function noteRewardsApiFailure(code) {
|
|
3149
|
+
if (!code?.startsWith("HTTP_4")) return;
|
|
3150
|
+
rewardsApiBackoffUntil = Date.now() + REWARDS_4XX_BACKOFF_MS;
|
|
3151
|
+
}
|
|
3043
3152
|
var seenRoutes = /* @__PURE__ */ new Set();
|
|
3044
3153
|
function getConsentKey(projectId) {
|
|
3045
3154
|
return `mushi_rewards_consent_${projectId}`;
|
|
@@ -3144,14 +3253,22 @@ async function flush(ctx) {
|
|
|
3144
3253
|
} catch {
|
|
3145
3254
|
}
|
|
3146
3255
|
}
|
|
3256
|
+
if (isRewardsApiBackedOff()) return;
|
|
3147
3257
|
const batch = pendingEvents.splice(0, 100);
|
|
3148
3258
|
try {
|
|
3149
|
-
await ctx.client.submitActivity(currentUserId, batch, {
|
|
3259
|
+
const result = await ctx.client.submitActivity(currentUserId, batch, {
|
|
3150
3260
|
userTraits: currentUserTraits ?? void 0,
|
|
3151
3261
|
reporterTokenHash: reporterTokenHash ?? void 0,
|
|
3152
3262
|
optedIn: true,
|
|
3153
3263
|
hostJwt: hostJwt ?? void 0
|
|
3154
3264
|
});
|
|
3265
|
+
if (!result.ok) {
|
|
3266
|
+
noteRewardsApiFailure(result.error?.code);
|
|
3267
|
+
const permanent = result.error?.code?.startsWith("HTTP_4");
|
|
3268
|
+
if (!permanent) {
|
|
3269
|
+
pendingEvents.unshift(...batch.slice(0, 50));
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3155
3272
|
} catch {
|
|
3156
3273
|
pendingEvents.unshift(...batch.slice(0, 50));
|
|
3157
3274
|
}
|
|
@@ -3162,13 +3279,14 @@ async function getTier(userId) {
|
|
|
3162
3279
|
return fetchAndCacheTier(userId);
|
|
3163
3280
|
}
|
|
3164
3281
|
async function fetchAndCacheTier(userId) {
|
|
3165
|
-
if (!apiClient) return null;
|
|
3282
|
+
if (!apiClient || isRewardsApiBackedOff()) return null;
|
|
3166
3283
|
const res = await apiClient.getMyTier(userId);
|
|
3167
3284
|
if (res.ok && res.data) {
|
|
3168
3285
|
tierCache = res.data;
|
|
3169
3286
|
tierCacheTime = Date.now();
|
|
3170
3287
|
return tierCache;
|
|
3171
3288
|
}
|
|
3289
|
+
noteRewardsApiFailure(res.error?.code);
|
|
3172
3290
|
return null;
|
|
3173
3291
|
}
|
|
3174
3292
|
var routeObserver = null;
|
|
@@ -4596,6 +4714,7 @@ function recordApiFailure(failedRequests, callbacks) {
|
|
|
4596
4714
|
// src/proactive-manager.ts
|
|
4597
4715
|
var STORAGE_KEY_LAST_DISMISS = "mushi:lastDismiss";
|
|
4598
4716
|
var STORAGE_KEY_CONSEC_DISMISS = "mushi:consecDismiss";
|
|
4717
|
+
var STORAGE_KEY_LAST_SHOWN = "mushi:lastShown";
|
|
4599
4718
|
function readStorage(key) {
|
|
4600
4719
|
try {
|
|
4601
4720
|
return localStorage.getItem(key);
|
|
@@ -4613,20 +4732,30 @@ function createProactiveManager(config = {}) {
|
|
|
4613
4732
|
const maxPerSession = config.maxProactivePerSession ?? 2;
|
|
4614
4733
|
const cooldownHours = config.dismissCooldownHours ?? 24;
|
|
4615
4734
|
const suppressThreshold = config.suppressAfterDismissals ?? 3;
|
|
4735
|
+
const reshowCooldownMs = (config.reshowCooldownMinutes ?? 30) * 60 * 1e3;
|
|
4616
4736
|
let sessionPromptCount = 0;
|
|
4617
4737
|
const sessionTriggerTypes = /* @__PURE__ */ new Set();
|
|
4618
4738
|
function shouldShow(triggerType) {
|
|
4739
|
+
const now = Date.now();
|
|
4619
4740
|
const consecDismissals = parseInt(readStorage(STORAGE_KEY_CONSEC_DISMISS) ?? "0", 10);
|
|
4620
4741
|
if (consecDismissals >= suppressThreshold) return false;
|
|
4621
4742
|
const lastDismiss = readStorage(STORAGE_KEY_LAST_DISMISS);
|
|
4622
4743
|
if (lastDismiss) {
|
|
4623
|
-
const elapsed =
|
|
4744
|
+
const elapsed = now - parseInt(lastDismiss, 10);
|
|
4624
4745
|
if (elapsed < cooldownHours * 60 * 60 * 1e3) return false;
|
|
4625
4746
|
}
|
|
4747
|
+
if (reshowCooldownMs > 0 && sessionPromptCount === 0) {
|
|
4748
|
+
const lastShown = readStorage(STORAGE_KEY_LAST_SHOWN);
|
|
4749
|
+
if (lastShown) {
|
|
4750
|
+
const elapsed = now - parseInt(lastShown, 10);
|
|
4751
|
+
if (elapsed < reshowCooldownMs) return false;
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4626
4754
|
if (sessionPromptCount >= maxPerSession) return false;
|
|
4627
4755
|
if (sessionTriggerTypes.has(triggerType)) return false;
|
|
4628
4756
|
sessionTriggerTypes.add(triggerType);
|
|
4629
4757
|
sessionPromptCount++;
|
|
4758
|
+
writeStorage(STORAGE_KEY_LAST_SHOWN, String(now));
|
|
4630
4759
|
return true;
|
|
4631
4760
|
}
|
|
4632
4761
|
function recordDismissal() {
|
|
@@ -4640,13 +4769,17 @@ function createProactiveManager(config = {}) {
|
|
|
4640
4769
|
function reset() {
|
|
4641
4770
|
sessionPromptCount = 0;
|
|
4642
4771
|
sessionTriggerTypes.clear();
|
|
4772
|
+
try {
|
|
4773
|
+
localStorage.removeItem(STORAGE_KEY_LAST_SHOWN);
|
|
4774
|
+
} catch {
|
|
4775
|
+
}
|
|
4643
4776
|
}
|
|
4644
4777
|
return { shouldShow, recordDismissal, recordSubmission, reset };
|
|
4645
4778
|
}
|
|
4646
4779
|
|
|
4647
4780
|
// src/version.ts
|
|
4648
4781
|
var MUSHI_SDK_PACKAGE = "@mushi-mushi/web";
|
|
4649
|
-
var MUSHI_SDK_VERSION = "1.7.
|
|
4782
|
+
var MUSHI_SDK_VERSION = "1.7.6" ;
|
|
4650
4783
|
|
|
4651
4784
|
// src/mushi.ts
|
|
4652
4785
|
var instance = null;
|
|
@@ -4827,15 +4960,26 @@ function createInstance(config) {
|
|
|
4827
4960
|
});
|
|
4828
4961
|
let detachAutoBreadcrumbs = null;
|
|
4829
4962
|
detachAutoBreadcrumbs = installAutoBreadcrumbs(breadcrumbs);
|
|
4963
|
+
async function autoCaptureScreenshot(when) {
|
|
4964
|
+
const mode = activeConfig.capture?.screenshot;
|
|
4965
|
+
if (!screenshotCap || mode === "off" || pendingScreenshot) return;
|
|
4966
|
+
if (when === "open" && mode !== "auto") return;
|
|
4967
|
+
if (when === "submit" && mode !== "on-report" && mode !== "auto") return;
|
|
4968
|
+
log.debug("Auto-capturing screenshot", { when, mode });
|
|
4969
|
+
pendingScreenshot = await screenshotCap.take();
|
|
4970
|
+
widget.setScreenshotAttached(pendingScreenshot !== null);
|
|
4971
|
+
}
|
|
4830
4972
|
widget = new MushiWidget(bootstrapConfig.widget, {
|
|
4831
4973
|
onSubmit: async ({ category, description, intent }) => {
|
|
4832
4974
|
log.info("Report submitted", { category, intent });
|
|
4833
4975
|
proactiveManager?.recordSubmission();
|
|
4976
|
+
await autoCaptureScreenshot("submit");
|
|
4834
4977
|
const outcome = await submitReport(category, description, intent);
|
|
4835
4978
|
return outcome ?? { reportId: null, queuedOffline: true };
|
|
4836
4979
|
},
|
|
4837
4980
|
onOpen: () => {
|
|
4838
4981
|
log.debug("Widget opened");
|
|
4982
|
+
void autoCaptureScreenshot("open");
|
|
4839
4983
|
emit("widget:opened");
|
|
4840
4984
|
},
|
|
4841
4985
|
onClose: () => {
|
|
@@ -5064,7 +5208,7 @@ function createInstance(config) {
|
|
|
5064
5208
|
...sentryCtx.tags ? { tags: scrubTagsForWire(sentryCtx.tags) } : {}
|
|
5065
5209
|
} : void 0;
|
|
5066
5210
|
const report = {
|
|
5067
|
-
id:
|
|
5211
|
+
id: newUuid(),
|
|
5068
5212
|
projectId: config.projectId,
|
|
5069
5213
|
category,
|
|
5070
5214
|
description: scrubbedDescription,
|
|
@@ -5242,7 +5386,8 @@ function createInstance(config) {
|
|
|
5242
5386
|
widgetMounted: widget.getIsMounted(),
|
|
5243
5387
|
runtimeConfigLoaded,
|
|
5244
5388
|
captureScreenshotAvailable: screenshotCap !== null,
|
|
5245
|
-
captureNetworkIntercepting: networkCap !== null
|
|
5389
|
+
captureNetworkIntercepting: networkCap !== null,
|
|
5390
|
+
widgetDiagnostics: widget.getWidgetDiagnostics()
|
|
5246
5391
|
});
|
|
5247
5392
|
},
|
|
5248
5393
|
destroy() {
|
|
@@ -5285,7 +5430,7 @@ function createInstance(config) {
|
|
|
5285
5430
|
...sentryCtx.tags ? { tags: scrubTagsForWire(sentryCtx.tags) } : {}
|
|
5286
5431
|
} : void 0;
|
|
5287
5432
|
const report = {
|
|
5288
|
-
id:
|
|
5433
|
+
id: newUuid(),
|
|
5289
5434
|
projectId: config.projectId,
|
|
5290
5435
|
category,
|
|
5291
5436
|
description,
|
|
@@ -5591,7 +5736,11 @@ async function runDiagnostics(options) {
|
|
|
5591
5736
|
runtimeConfigLoaded: options.runtimeConfigLoaded,
|
|
5592
5737
|
captureScreenshotAvailable: options.captureScreenshotAvailable,
|
|
5593
5738
|
captureNetworkIntercepting: options.captureNetworkIntercepting,
|
|
5594
|
-
sdkVersion: MUSHI_SDK_VERSION
|
|
5739
|
+
sdkVersion: MUSHI_SDK_VERSION,
|
|
5740
|
+
widgetHostPointerSafe: options.widgetDiagnostics?.widgetHostPointerSafe ?? false,
|
|
5741
|
+
widgetHostBounds: options.widgetDiagnostics?.widgetHostBounds ?? null,
|
|
5742
|
+
widgetSuppressed: options.widgetDiagnostics?.widgetSuppressed ?? false,
|
|
5743
|
+
bannerRendered: options.widgetDiagnostics?.bannerRendered ?? false
|
|
5595
5744
|
};
|
|
5596
5745
|
}
|
|
5597
5746
|
async function diagnoseWithoutInstance() {
|
|
@@ -5604,7 +5753,11 @@ async function diagnoseWithoutInstance() {
|
|
|
5604
5753
|
runtimeConfigLoaded: false,
|
|
5605
5754
|
captureScreenshotAvailable: false,
|
|
5606
5755
|
captureNetworkIntercepting: false,
|
|
5607
|
-
sdkVersion: MUSHI_SDK_VERSION
|
|
5756
|
+
sdkVersion: MUSHI_SDK_VERSION,
|
|
5757
|
+
widgetHostPointerSafe: false,
|
|
5758
|
+
widgetHostBounds: null,
|
|
5759
|
+
widgetSuppressed: false,
|
|
5760
|
+
bannerRendered: false
|
|
5608
5761
|
};
|
|
5609
5762
|
}
|
|
5610
5763
|
async function probeApiEndpoint(apiEndpoint) {
|