@mushi-mushi/react-native 0.13.0 → 0.14.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/CONTRIBUTING.md +0 -11
- package/README.md +6 -0
- package/dist/index.cjs +174 -8
- package/dist/index.d.cts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +177 -9
- package/package.json +7 -3
package/CONTRIBUTING.md
CHANGED
|
@@ -101,17 +101,6 @@ Releases are fully automated. Maintainers don't run `npm publish` by hand.
|
|
|
101
101
|
|
|
102
102
|
If GitHub's anti-loop protection suppresses the auto re-fire (the squash merge can be attributed to `github-actions[bot]`), trigger the workflow manually: **Actions → release → Run workflow → master**.
|
|
103
103
|
|
|
104
|
-
### Known CI/CD quirks and their automatic safeguards
|
|
105
|
-
|
|
106
|
-
A handful of GitHub-Actions × Changesets edge cases have caused release-pipeline stalls in the past. Each is now caught automatically — keep these in mind when you see the symptom:
|
|
107
|
-
|
|
108
|
-
| Symptom | Root cause | Automatic safeguard |
|
|
109
|
-
| --- | --- | --- |
|
|
110
|
-
| The `Build & Test` required check never registers on the `chore: version packages` PR — the PR stays "Required check missing" forever | `changeset-release/master` is pushed by `github-actions[bot]`. GitHub silently drops the downstream `pull_request` event to prevent bot loops (observed on PR #45, #102, #124). | `ci.yml` now also triggers on `push` to `changeset-release/master`, so `Build & Test` reports against the head commit directly. No empty-commit nudge needed. |
|
|
111
|
-
| Release workflow fails with `No commits between master and changeset-release/master` after merging a PR with a new changeset. | A `.changeset/*.md` file whose YAML frontmatter only targets packages listed in `.changeset/config.json#ignore` (e.g. `@mushi-mushi/server`, `@mushi-mushi/admin`). `changeset version` produces no bumps, the version PR is empty, the next push errors (PR #102 / #121, 2026-05-19). | `pnpm check:changeset-orphans` runs in both `ci.yml` and `release.yml`. PR CI fails with an actionable message naming the orphan file *before* it can reach master. If you legitimately need to record an internal-only change, omit the changeset entirely — the diff lives in git history. |
|
|
112
|
-
| Release workflow's `Audit signatures of installed dependencies` step fails with `npm ETARGET / No matching version found for @mushi-mushi/<pkg>@<ver>` seconds after the publish step succeeded. | npm's registry CDN can take up to ~30s to propagate a freshly-published manifest. The audit step shells out to `npm install` against the just-published version and races the CDN (observed 2026-05-20, run 26149167393). | The audit step retries with exponential backoff (1, 2, 4, 8, 16, 32s — 63s total) before failing. Sigstore signatures are written at publish time, so a one-off audit failure never indicates a corrupted package — `pnpm view <pkg> version` is the ground truth. |
|
|
113
|
-
| Push to `master` after merging a PR doesn't fire the `Release` workflow. | Same anti-loop protection: when a squash merge is attributed to `github-actions[bot]`, GitHub may suppress the downstream `push` trigger. Sporadic — observed twice in the last 60 days. | `release.yml` keeps `workflow_dispatch` as the manual fallback. Recovery: **Actions → Release → Run workflow → master**. The `Build & Verify` job re-runs identically to the auto-fired path. |
|
|
114
|
-
|
|
115
104
|
### Adding a brand-new publishable package
|
|
116
105
|
|
|
117
106
|
Trusted Publisher bindings are configured **per package** on `npmjs.com` and require the package to already exist on the registry. New packages therefore need a one-time bootstrap before OIDC can take over.
|
package/README.md
CHANGED
|
@@ -115,3 +115,9 @@ See the full [CHANGELOG](https://github.com/kensaurus/mushi-mushi/blob/master/pa
|
|
|
115
115
|
## License
|
|
116
116
|
|
|
117
117
|
MIT
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
<!-- mushi-readme-stats-footer -->
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
<sub>Monorepo scale (June 2026): 43 edge functions · 234 SQL migrations · 13 outbound plugins · 11 inbound adapters. Canonical counts: <a href="https://github.com/kensaurus/mushi-mushi/blob/master/docs/stats.md">docs/stats.md</a> · <code>pnpm docs-stats</code></sub>
|
package/dist/index.cjs
CHANGED
|
@@ -319,7 +319,12 @@ var CATEGORIES = [
|
|
|
319
319
|
{ key: "confusing", emoji: "\u{1F615}", label: "Confusing" },
|
|
320
320
|
{ key: "other", emoji: "\u{1F4AC}", label: "Other" }
|
|
321
321
|
];
|
|
322
|
-
var MushiBottomSheet = ({
|
|
322
|
+
var MushiBottomSheet = ({
|
|
323
|
+
visible,
|
|
324
|
+
onClose,
|
|
325
|
+
screenshotDataUrl,
|
|
326
|
+
onClearScreenshot
|
|
327
|
+
}) => {
|
|
323
328
|
const mushi = useMushiContext();
|
|
324
329
|
const scheme = (0, import_react_native2.useColorScheme)();
|
|
325
330
|
const dark = scheme === "dark";
|
|
@@ -328,6 +333,10 @@ var MushiBottomSheet = ({ visible, onClose }) => {
|
|
|
328
333
|
const [category, setCategory] = (0, import_react.useState)(null);
|
|
329
334
|
const [description, setDescription] = (0, import_react.useState)("");
|
|
330
335
|
const [phase, setPhase] = (0, import_react.useState)("form");
|
|
336
|
+
const [screenshotAttached, setScreenshotAttached] = (0, import_react.useState)(true);
|
|
337
|
+
(0, import_react.useEffect)(() => {
|
|
338
|
+
if (visible) setScreenshotAttached(true);
|
|
339
|
+
}, [visible]);
|
|
331
340
|
const resetForm = (0, import_react.useCallback)(() => {
|
|
332
341
|
setCategory(null);
|
|
333
342
|
setDescription("");
|
|
@@ -399,13 +408,18 @@ var MushiBottomSheet = ({ visible, onClose }) => {
|
|
|
399
408
|
if (!category || !description.trim() || !mushi) return;
|
|
400
409
|
setPhase("sending");
|
|
401
410
|
try {
|
|
402
|
-
await mushi.submitReport({
|
|
411
|
+
await mushi.submitReport({
|
|
412
|
+
category,
|
|
413
|
+
description: description.trim(),
|
|
414
|
+
screenshotDataUrl: screenshotDataUrl && screenshotAttached ? screenshotDataUrl : void 0
|
|
415
|
+
});
|
|
403
416
|
setPhase("sent");
|
|
404
417
|
setTimeout(handleClose, 1400);
|
|
405
418
|
} catch {
|
|
406
419
|
setPhase("form");
|
|
407
420
|
}
|
|
408
421
|
};
|
|
422
|
+
const activeScreenshot = screenshotDataUrl && screenshotAttached ? screenshotDataUrl : null;
|
|
409
423
|
const colors = dark ? { bg: "#1c1c1e", text: "#f2f2f7", sub: "#8e8e93", card: "#2c2c2e", accent: "#0a84ff", border: "#38383a", backdrop: "rgba(0,0,0,0.6)" } : { bg: "#ffffff", text: "#1c1c1e", sub: "#8e8e93", card: "#f2f2f7", accent: "#007aff", border: "#e5e5ea", backdrop: "rgba(0,0,0,0.35)" };
|
|
410
424
|
const canSubmit = !!category && description.trim().length > 0 && phase === "form";
|
|
411
425
|
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)(
|
|
@@ -486,6 +500,32 @@ var MushiBottomSheet = ({ visible, onClose }) => {
|
|
|
486
500
|
editable: phase === "form"
|
|
487
501
|
}
|
|
488
502
|
),
|
|
503
|
+
activeScreenshot ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.screenshotRow, children: [
|
|
504
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
505
|
+
import_react_native2.Image,
|
|
506
|
+
{
|
|
507
|
+
source: { uri: activeScreenshot },
|
|
508
|
+
style: s.screenshotThumb,
|
|
509
|
+
accessibilityLabel: "Attached screenshot"
|
|
510
|
+
}
|
|
511
|
+
),
|
|
512
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.screenshotMeta, children: [
|
|
513
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotLabel, { color: colors.text }], children: "Screenshot attached" }),
|
|
514
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotSub, { color: colors.sub }], children: "Helps the team see the issue" })
|
|
515
|
+
] }),
|
|
516
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
517
|
+
import_react_native2.TouchableOpacity,
|
|
518
|
+
{
|
|
519
|
+
onPress: () => {
|
|
520
|
+
setScreenshotAttached(false);
|
|
521
|
+
onClearScreenshot?.();
|
|
522
|
+
},
|
|
523
|
+
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
524
|
+
accessibilityLabel: "Remove screenshot",
|
|
525
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [s.screenshotRemove, { color: colors.sub }], children: "\u2715" })
|
|
526
|
+
}
|
|
527
|
+
)
|
|
528
|
+
] }) : null,
|
|
489
529
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
490
530
|
import_react_native2.TouchableOpacity,
|
|
491
531
|
{
|
|
@@ -598,6 +638,39 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
598
638
|
sentText: {
|
|
599
639
|
fontSize: 20,
|
|
600
640
|
fontWeight: "600"
|
|
641
|
+
},
|
|
642
|
+
screenshotRow: {
|
|
643
|
+
flexDirection: "row",
|
|
644
|
+
alignItems: "center",
|
|
645
|
+
gap: 10,
|
|
646
|
+
marginBottom: 12,
|
|
647
|
+
paddingHorizontal: 10,
|
|
648
|
+
paddingVertical: 8,
|
|
649
|
+
borderRadius: 10,
|
|
650
|
+
backgroundColor: "rgba(128,128,128,0.1)"
|
|
651
|
+
},
|
|
652
|
+
screenshotThumb: {
|
|
653
|
+
width: 48,
|
|
654
|
+
height: 36,
|
|
655
|
+
borderRadius: 4,
|
|
656
|
+
backgroundColor: "#000",
|
|
657
|
+
flexShrink: 0
|
|
658
|
+
},
|
|
659
|
+
screenshotMeta: {
|
|
660
|
+
flex: 1,
|
|
661
|
+
gap: 2
|
|
662
|
+
},
|
|
663
|
+
screenshotLabel: {
|
|
664
|
+
fontSize: 13,
|
|
665
|
+
fontWeight: "600"
|
|
666
|
+
},
|
|
667
|
+
screenshotSub: {
|
|
668
|
+
fontSize: 11
|
|
669
|
+
},
|
|
670
|
+
screenshotRemove: {
|
|
671
|
+
fontSize: 16,
|
|
672
|
+
fontWeight: "700",
|
|
673
|
+
paddingHorizontal: 4
|
|
601
674
|
}
|
|
602
675
|
});
|
|
603
676
|
|
|
@@ -683,6 +756,15 @@ function MushiProvider({ children, ...config }) {
|
|
|
683
756
|
const queueRef = (0, import_react3.useRef)(null);
|
|
684
757
|
const apiClientRef = (0, import_react3.useRef)(null);
|
|
685
758
|
const [sheetVisible, setSheetVisible] = (0, import_react3.useState)(false);
|
|
759
|
+
const [sheetScreenshot, setSheetScreenshot] = (0, import_react3.useState)(null);
|
|
760
|
+
const reporterTokenRef = (0, import_react3.useRef)(`rn-${config.projectId}-anon`);
|
|
761
|
+
let resolveReporterTokenReady = () => {
|
|
762
|
+
};
|
|
763
|
+
const reporterTokenReadyRef = (0, import_react3.useRef)(
|
|
764
|
+
new Promise((resolve) => {
|
|
765
|
+
resolveReporterTokenReady = resolve;
|
|
766
|
+
})
|
|
767
|
+
);
|
|
686
768
|
if (config.endpoint !== void 0 && config.endpoint.trim() === "") {
|
|
687
769
|
throw new Error(
|
|
688
770
|
"[MushiProvider] endpoint is set to an empty string. Set endpoint to your Supabase edge function URL, e.g. https://xyz.supabase.co/functions/v1/api, or omit it to use the cloud default."
|
|
@@ -708,6 +790,27 @@ function MushiProvider({ children, ...config }) {
|
|
|
708
790
|
});
|
|
709
791
|
queueRef.current.flush().catch(() => {
|
|
710
792
|
});
|
|
793
|
+
(async () => {
|
|
794
|
+
const TOKEN_KEY = "@mushi:reporter_token";
|
|
795
|
+
try {
|
|
796
|
+
const AsyncStorage = (await import("@react-native-async-storage/async-storage")).default;
|
|
797
|
+
const existing = await AsyncStorage.getItem(TOKEN_KEY);
|
|
798
|
+
if (existing && existing.startsWith("mushi_")) {
|
|
799
|
+
reporterTokenRef.current = existing;
|
|
800
|
+
} else {
|
|
801
|
+
const fresh = `mushi_${(0, import_core.newUuid)()}`;
|
|
802
|
+
reporterTokenRef.current = fresh;
|
|
803
|
+
await AsyncStorage.setItem(TOKEN_KEY, fresh);
|
|
804
|
+
}
|
|
805
|
+
resolveReporterTokenReady();
|
|
806
|
+
} catch {
|
|
807
|
+
if (reporterTokenRef.current === `rn-${config.projectId}-anon`) {
|
|
808
|
+
reporterTokenRef.current = `mushi_${(0, import_core.newUuid)()}`;
|
|
809
|
+
}
|
|
810
|
+
resolveReporterTokenReady();
|
|
811
|
+
}
|
|
812
|
+
})().catch(() => {
|
|
813
|
+
});
|
|
711
814
|
return () => {
|
|
712
815
|
consoleRef.current?.restore();
|
|
713
816
|
networkRef.current?.restore();
|
|
@@ -727,7 +830,25 @@ function MushiProvider({ children, ...config }) {
|
|
|
727
830
|
}
|
|
728
831
|
return () => unsubscribe?.();
|
|
729
832
|
}, []);
|
|
730
|
-
const open = (0, import_react3.useCallback)(() =>
|
|
833
|
+
const open = (0, import_react3.useCallback)(() => {
|
|
834
|
+
let vshot = null;
|
|
835
|
+
try {
|
|
836
|
+
vshot = require("react-native-view-shot");
|
|
837
|
+
} catch {
|
|
838
|
+
}
|
|
839
|
+
if (!vshot) {
|
|
840
|
+
setSheetScreenshot(null);
|
|
841
|
+
setSheetVisible(true);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
vshot.captureScreen({ format: "jpg", quality: 0.7, result: "data-uri" }).then((url) => {
|
|
845
|
+
setSheetScreenshot(url);
|
|
846
|
+
}).catch(() => {
|
|
847
|
+
setSheetScreenshot(null);
|
|
848
|
+
}).finally(() => {
|
|
849
|
+
setSheetVisible(true);
|
|
850
|
+
});
|
|
851
|
+
}, []);
|
|
731
852
|
const close = (0, import_react3.useCallback)(() => setSheetVisible(false), []);
|
|
732
853
|
const attachTo = (0, import_react3.useCallback)(() => ({ onPress: open }), [open]);
|
|
733
854
|
(0, import_react3.useEffect)(() => {
|
|
@@ -761,8 +882,16 @@ function MushiProvider({ children, ...config }) {
|
|
|
761
882
|
const submitReport = (0, import_react3.useCallback)(
|
|
762
883
|
async (data) => {
|
|
763
884
|
const deviceInfo = getDeviceInfo();
|
|
885
|
+
const contextMeta = {};
|
|
886
|
+
if (userRef.current?.id) contextMeta.userId = userRef.current.id;
|
|
887
|
+
if (userRef.current?.email) contextMeta.userEmail = userRef.current.email;
|
|
888
|
+
if (userRef.current?.name) contextMeta.userName = userRef.current.name;
|
|
889
|
+
if (screenRef.current?.name) contextMeta.screenName = screenRef.current.name;
|
|
890
|
+
if (screenRef.current?.route) contextMeta.screenRoute = screenRef.current.route;
|
|
891
|
+
if (screenRef.current?.feature) contextMeta.screenFeature = screenRef.current.feature;
|
|
892
|
+
const merged = Object.keys(metadataRef.current).length > 0 ? { ...contextMeta, ...metadataRef.current } : Object.keys(contextMeta).length > 0 ? contextMeta : void 0;
|
|
764
893
|
const report = {
|
|
765
|
-
id:
|
|
894
|
+
id: (0, import_core.newUuid)(),
|
|
766
895
|
projectId: config.projectId,
|
|
767
896
|
category: data.category,
|
|
768
897
|
description: data.description,
|
|
@@ -771,7 +900,7 @@ function MushiProvider({ children, ...config }) {
|
|
|
771
900
|
platform: deviceInfo.platform ?? "mobile",
|
|
772
901
|
language: deviceInfo.locale ?? "en",
|
|
773
902
|
viewport: { width: deviceInfo.screenWidth ?? 0, height: deviceInfo.screenHeight ?? 0 },
|
|
774
|
-
url: "",
|
|
903
|
+
url: screenRef.current?.route ?? "",
|
|
775
904
|
referrer: "",
|
|
776
905
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
777
906
|
timezone: deviceInfo.timezone ?? "UTC"
|
|
@@ -781,7 +910,9 @@ function MushiProvider({ children, ...config }) {
|
|
|
781
910
|
...entry,
|
|
782
911
|
status: entry.status ?? 0
|
|
783
912
|
})) ?? [],
|
|
784
|
-
|
|
913
|
+
screenshotDataUrl: data.screenshotDataUrl,
|
|
914
|
+
metadata: merged,
|
|
915
|
+
reporterToken: reporterTokenRef.current,
|
|
785
916
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
786
917
|
};
|
|
787
918
|
const client = apiClientRef.current;
|
|
@@ -791,7 +922,7 @@ function MushiProvider({ children, ...config }) {
|
|
|
791
922
|
await queueRef.current?.enqueue(report);
|
|
792
923
|
}
|
|
793
924
|
},
|
|
794
|
-
[config.projectId,
|
|
925
|
+
[config.projectId, apiEndpoint]
|
|
795
926
|
);
|
|
796
927
|
const userRef = (0, import_react3.useRef)(null);
|
|
797
928
|
const metadataRef = (0, import_react3.useRef)({});
|
|
@@ -842,6 +973,33 @@ function MushiProvider({ children, ...config }) {
|
|
|
842
973
|
setScreen(screen) {
|
|
843
974
|
screenRef.current = screen;
|
|
844
975
|
},
|
|
976
|
+
// Reporter API — scoped to the device's persistent reporter token
|
|
977
|
+
async listMyReports() {
|
|
978
|
+
const client = apiClientRef.current;
|
|
979
|
+
if (!client) return [];
|
|
980
|
+
await reporterTokenReadyRef.current;
|
|
981
|
+
const res = await client.listReporterReports(reporterTokenRef.current);
|
|
982
|
+
return res.ok ? res.data?.reports ?? [] : [];
|
|
983
|
+
},
|
|
984
|
+
async listMyComments(reportId) {
|
|
985
|
+
const client = apiClientRef.current;
|
|
986
|
+
if (!client) return [];
|
|
987
|
+
const res = await client.listReporterComments(reportId, reporterTokenRef.current);
|
|
988
|
+
return res.ok ? res.data.comments ?? [] : [];
|
|
989
|
+
},
|
|
990
|
+
async replyToReport(reportId, body) {
|
|
991
|
+
const client = apiClientRef.current;
|
|
992
|
+
if (!client) return null;
|
|
993
|
+
const res = await client.replyToReporterReport(reportId, reporterTokenRef.current, body);
|
|
994
|
+
return res.ok ? res.data.comment : null;
|
|
995
|
+
},
|
|
996
|
+
// Leaderboard — SDK-public anonymized hall-of-fame
|
|
997
|
+
async getHallOfFame(limit = 10) {
|
|
998
|
+
const client = apiClientRef.current;
|
|
999
|
+
if (!client) return [];
|
|
1000
|
+
const res = await client.getHallOfFame(limit);
|
|
1001
|
+
return res.ok ? res.data.data ?? [] : [];
|
|
1002
|
+
},
|
|
845
1003
|
// Rewards (P1)
|
|
846
1004
|
recordActivity(action, metadata) {
|
|
847
1005
|
if (!config.rewards?.enabled) return;
|
|
@@ -883,7 +1041,15 @@ function MushiProvider({ children, ...config }) {
|
|
|
883
1041
|
inset: config.widget?.inset
|
|
884
1042
|
}
|
|
885
1043
|
),
|
|
886
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1044
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1045
|
+
MushiBottomSheet,
|
|
1046
|
+
{
|
|
1047
|
+
visible: sheetVisible,
|
|
1048
|
+
onClose: close,
|
|
1049
|
+
screenshotDataUrl: sheetScreenshot ?? void 0,
|
|
1050
|
+
onClearScreenshot: () => setSheetScreenshot(null)
|
|
1051
|
+
}
|
|
1052
|
+
)
|
|
887
1053
|
] });
|
|
888
1054
|
}
|
|
889
1055
|
function useMushiContext() {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode, FC, ReactElement } from 'react';
|
|
4
|
-
import { MushiRewardsConfig, MushiTierResult, MushiReputationResult } from '@mushi-mushi/core';
|
|
4
|
+
import { MushiRewardsConfig, MushiReporterReport, MushiReporterComment, MushiHallOfFameEntry, MushiTierResult, MushiReputationResult } from '@mushi-mushi/core';
|
|
5
|
+
export { MushiHallOfFameEntry, MushiReporterComment, MushiReporterReport } from '@mushi-mushi/core';
|
|
5
6
|
|
|
6
7
|
interface ConsoleEntry {
|
|
7
8
|
level: 'log' | 'warn' | 'error';
|
|
@@ -69,15 +70,18 @@ interface MushiRNConfig {
|
|
|
69
70
|
};
|
|
70
71
|
rewards?: MushiRewardsConfig;
|
|
71
72
|
}
|
|
73
|
+
|
|
72
74
|
interface MushiRNInstance {
|
|
73
75
|
open(): void;
|
|
74
76
|
close(): void;
|
|
75
77
|
attachTo(): {
|
|
76
78
|
onPress: () => void;
|
|
77
79
|
};
|
|
80
|
+
/** screenshotDataUrl is optional — pass `undefined` if not captured or removed by the user. */
|
|
78
81
|
submitReport(data: {
|
|
79
82
|
description: string;
|
|
80
83
|
category: string;
|
|
84
|
+
screenshotDataUrl?: string;
|
|
81
85
|
}): Promise<void>;
|
|
82
86
|
getDeviceInfo(): ReturnType<typeof getDeviceInfo>;
|
|
83
87
|
getConsoleEntries(): ReturnType<ReturnType<typeof setupConsoleCapture>['getEntries']>;
|
|
@@ -97,6 +101,14 @@ interface MushiRNInstance {
|
|
|
97
101
|
route?: string;
|
|
98
102
|
feature?: string;
|
|
99
103
|
}): void;
|
|
104
|
+
/** List this device's reports ordered by most recent. Returns [] on failure. */
|
|
105
|
+
listMyReports(): Promise<MushiReporterReport[]>;
|
|
106
|
+
/** List admin + reporter comments on a specific report. */
|
|
107
|
+
listMyComments(reportId: string): Promise<MushiReporterComment[]>;
|
|
108
|
+
/** Post a reporter reply on a report thread. Returns the new comment or null on failure. */
|
|
109
|
+
replyToReport(reportId: string, body: string): Promise<MushiReporterComment | null>;
|
|
110
|
+
/** Fetch the project's top contributors by points (max 50). */
|
|
111
|
+
getHallOfFame(limit?: number): Promise<MushiHallOfFameEntry[]>;
|
|
100
112
|
/** Manually record a host-defined activity event. */
|
|
101
113
|
recordActivity(action: string, metadata?: Record<string, unknown>): void;
|
|
102
114
|
/** Returns the current user's tier. */
|
|
@@ -153,6 +165,10 @@ declare function useMushiWidget(): {
|
|
|
153
165
|
interface MushiBottomSheetProps {
|
|
154
166
|
visible: boolean;
|
|
155
167
|
onClose: () => void;
|
|
168
|
+
/** Base64 data-URI of the screenshot captured before the sheet opened. Optional. */
|
|
169
|
+
screenshotDataUrl?: string;
|
|
170
|
+
/** Called when the user removes the attached screenshot. */
|
|
171
|
+
onClearScreenshot?: () => void;
|
|
156
172
|
}
|
|
157
173
|
declare const MushiBottomSheet: FC<MushiBottomSheetProps>;
|
|
158
174
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode, FC, ReactElement } from 'react';
|
|
4
|
-
import { MushiRewardsConfig, MushiTierResult, MushiReputationResult } from '@mushi-mushi/core';
|
|
4
|
+
import { MushiRewardsConfig, MushiReporterReport, MushiReporterComment, MushiHallOfFameEntry, MushiTierResult, MushiReputationResult } from '@mushi-mushi/core';
|
|
5
|
+
export { MushiHallOfFameEntry, MushiReporterComment, MushiReporterReport } from '@mushi-mushi/core';
|
|
5
6
|
|
|
6
7
|
interface ConsoleEntry {
|
|
7
8
|
level: 'log' | 'warn' | 'error';
|
|
@@ -69,15 +70,18 @@ interface MushiRNConfig {
|
|
|
69
70
|
};
|
|
70
71
|
rewards?: MushiRewardsConfig;
|
|
71
72
|
}
|
|
73
|
+
|
|
72
74
|
interface MushiRNInstance {
|
|
73
75
|
open(): void;
|
|
74
76
|
close(): void;
|
|
75
77
|
attachTo(): {
|
|
76
78
|
onPress: () => void;
|
|
77
79
|
};
|
|
80
|
+
/** screenshotDataUrl is optional — pass `undefined` if not captured or removed by the user. */
|
|
78
81
|
submitReport(data: {
|
|
79
82
|
description: string;
|
|
80
83
|
category: string;
|
|
84
|
+
screenshotDataUrl?: string;
|
|
81
85
|
}): Promise<void>;
|
|
82
86
|
getDeviceInfo(): ReturnType<typeof getDeviceInfo>;
|
|
83
87
|
getConsoleEntries(): ReturnType<ReturnType<typeof setupConsoleCapture>['getEntries']>;
|
|
@@ -97,6 +101,14 @@ interface MushiRNInstance {
|
|
|
97
101
|
route?: string;
|
|
98
102
|
feature?: string;
|
|
99
103
|
}): void;
|
|
104
|
+
/** List this device's reports ordered by most recent. Returns [] on failure. */
|
|
105
|
+
listMyReports(): Promise<MushiReporterReport[]>;
|
|
106
|
+
/** List admin + reporter comments on a specific report. */
|
|
107
|
+
listMyComments(reportId: string): Promise<MushiReporterComment[]>;
|
|
108
|
+
/** Post a reporter reply on a report thread. Returns the new comment or null on failure. */
|
|
109
|
+
replyToReport(reportId: string, body: string): Promise<MushiReporterComment | null>;
|
|
110
|
+
/** Fetch the project's top contributors by points (max 50). */
|
|
111
|
+
getHallOfFame(limit?: number): Promise<MushiHallOfFameEntry[]>;
|
|
100
112
|
/** Manually record a host-defined activity event. */
|
|
101
113
|
recordActivity(action: string, metadata?: Record<string, unknown>): void;
|
|
102
114
|
/** Returns the current user's tier. */
|
|
@@ -153,6 +165,10 @@ declare function useMushiWidget(): {
|
|
|
153
165
|
interface MushiBottomSheetProps {
|
|
154
166
|
visible: boolean;
|
|
155
167
|
onClose: () => void;
|
|
168
|
+
/** Base64 data-URI of the screenshot captured before the sheet opened. Optional. */
|
|
169
|
+
screenshotDataUrl?: string;
|
|
170
|
+
/** Called when the user removes the attached screenshot. */
|
|
171
|
+
onClearScreenshot?: () => void;
|
|
156
172
|
}
|
|
157
173
|
declare const MushiBottomSheet: FC<MushiBottomSheetProps>;
|
|
158
174
|
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
} from "react";
|
|
18
18
|
import {
|
|
19
19
|
createApiClient,
|
|
20
|
-
DEFAULT_API_ENDPOINT
|
|
20
|
+
DEFAULT_API_ENDPOINT,
|
|
21
|
+
newUuid
|
|
21
22
|
} from "@mushi-mushi/core";
|
|
22
23
|
|
|
23
24
|
// src/capture/console-capture.ts
|
|
@@ -288,6 +289,7 @@ import {
|
|
|
288
289
|
View,
|
|
289
290
|
Text,
|
|
290
291
|
TextInput,
|
|
292
|
+
Image,
|
|
291
293
|
TouchableOpacity,
|
|
292
294
|
Animated,
|
|
293
295
|
PanResponder,
|
|
@@ -308,7 +310,12 @@ var CATEGORIES = [
|
|
|
308
310
|
{ key: "confusing", emoji: "\u{1F615}", label: "Confusing" },
|
|
309
311
|
{ key: "other", emoji: "\u{1F4AC}", label: "Other" }
|
|
310
312
|
];
|
|
311
|
-
var MushiBottomSheet = ({
|
|
313
|
+
var MushiBottomSheet = ({
|
|
314
|
+
visible,
|
|
315
|
+
onClose,
|
|
316
|
+
screenshotDataUrl,
|
|
317
|
+
onClearScreenshot
|
|
318
|
+
}) => {
|
|
312
319
|
const mushi = useMushiContext();
|
|
313
320
|
const scheme = useColorScheme();
|
|
314
321
|
const dark = scheme === "dark";
|
|
@@ -317,6 +324,10 @@ var MushiBottomSheet = ({ visible, onClose }) => {
|
|
|
317
324
|
const [category, setCategory] = useState(null);
|
|
318
325
|
const [description, setDescription] = useState("");
|
|
319
326
|
const [phase, setPhase] = useState("form");
|
|
327
|
+
const [screenshotAttached, setScreenshotAttached] = useState(true);
|
|
328
|
+
useEffect(() => {
|
|
329
|
+
if (visible) setScreenshotAttached(true);
|
|
330
|
+
}, [visible]);
|
|
320
331
|
const resetForm = useCallback(() => {
|
|
321
332
|
setCategory(null);
|
|
322
333
|
setDescription("");
|
|
@@ -388,13 +399,18 @@ var MushiBottomSheet = ({ visible, onClose }) => {
|
|
|
388
399
|
if (!category || !description.trim() || !mushi) return;
|
|
389
400
|
setPhase("sending");
|
|
390
401
|
try {
|
|
391
|
-
await mushi.submitReport({
|
|
402
|
+
await mushi.submitReport({
|
|
403
|
+
category,
|
|
404
|
+
description: description.trim(),
|
|
405
|
+
screenshotDataUrl: screenshotDataUrl && screenshotAttached ? screenshotDataUrl : void 0
|
|
406
|
+
});
|
|
392
407
|
setPhase("sent");
|
|
393
408
|
setTimeout(handleClose, 1400);
|
|
394
409
|
} catch {
|
|
395
410
|
setPhase("form");
|
|
396
411
|
}
|
|
397
412
|
};
|
|
413
|
+
const activeScreenshot = screenshotDataUrl && screenshotAttached ? screenshotDataUrl : null;
|
|
398
414
|
const colors = dark ? { bg: "#1c1c1e", text: "#f2f2f7", sub: "#8e8e93", card: "#2c2c2e", accent: "#0a84ff", border: "#38383a", backdrop: "rgba(0,0,0,0.6)" } : { bg: "#ffffff", text: "#1c1c1e", sub: "#8e8e93", card: "#f2f2f7", accent: "#007aff", border: "#e5e5ea", backdrop: "rgba(0,0,0,0.35)" };
|
|
399
415
|
const canSubmit = !!category && description.trim().length > 0 && phase === "form";
|
|
400
416
|
return /* @__PURE__ */ jsx(Modal, { visible, transparent: true, animationType: "none", statusBarTranslucent: true, children: /* @__PURE__ */ jsxs(
|
|
@@ -475,6 +491,32 @@ var MushiBottomSheet = ({ visible, onClose }) => {
|
|
|
475
491
|
editable: phase === "form"
|
|
476
492
|
}
|
|
477
493
|
),
|
|
494
|
+
activeScreenshot ? /* @__PURE__ */ jsxs(View, { style: s.screenshotRow, children: [
|
|
495
|
+
/* @__PURE__ */ jsx(
|
|
496
|
+
Image,
|
|
497
|
+
{
|
|
498
|
+
source: { uri: activeScreenshot },
|
|
499
|
+
style: s.screenshotThumb,
|
|
500
|
+
accessibilityLabel: "Attached screenshot"
|
|
501
|
+
}
|
|
502
|
+
),
|
|
503
|
+
/* @__PURE__ */ jsxs(View, { style: s.screenshotMeta, children: [
|
|
504
|
+
/* @__PURE__ */ jsx(Text, { style: [s.screenshotLabel, { color: colors.text }], children: "Screenshot attached" }),
|
|
505
|
+
/* @__PURE__ */ jsx(Text, { style: [s.screenshotSub, { color: colors.sub }], children: "Helps the team see the issue" })
|
|
506
|
+
] }),
|
|
507
|
+
/* @__PURE__ */ jsx(
|
|
508
|
+
TouchableOpacity,
|
|
509
|
+
{
|
|
510
|
+
onPress: () => {
|
|
511
|
+
setScreenshotAttached(false);
|
|
512
|
+
onClearScreenshot?.();
|
|
513
|
+
},
|
|
514
|
+
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
515
|
+
accessibilityLabel: "Remove screenshot",
|
|
516
|
+
children: /* @__PURE__ */ jsx(Text, { style: [s.screenshotRemove, { color: colors.sub }], children: "\u2715" })
|
|
517
|
+
}
|
|
518
|
+
)
|
|
519
|
+
] }) : null,
|
|
478
520
|
/* @__PURE__ */ jsx(
|
|
479
521
|
TouchableOpacity,
|
|
480
522
|
{
|
|
@@ -587,6 +629,39 @@ var s = StyleSheet.create({
|
|
|
587
629
|
sentText: {
|
|
588
630
|
fontSize: 20,
|
|
589
631
|
fontWeight: "600"
|
|
632
|
+
},
|
|
633
|
+
screenshotRow: {
|
|
634
|
+
flexDirection: "row",
|
|
635
|
+
alignItems: "center",
|
|
636
|
+
gap: 10,
|
|
637
|
+
marginBottom: 12,
|
|
638
|
+
paddingHorizontal: 10,
|
|
639
|
+
paddingVertical: 8,
|
|
640
|
+
borderRadius: 10,
|
|
641
|
+
backgroundColor: "rgba(128,128,128,0.1)"
|
|
642
|
+
},
|
|
643
|
+
screenshotThumb: {
|
|
644
|
+
width: 48,
|
|
645
|
+
height: 36,
|
|
646
|
+
borderRadius: 4,
|
|
647
|
+
backgroundColor: "#000",
|
|
648
|
+
flexShrink: 0
|
|
649
|
+
},
|
|
650
|
+
screenshotMeta: {
|
|
651
|
+
flex: 1,
|
|
652
|
+
gap: 2
|
|
653
|
+
},
|
|
654
|
+
screenshotLabel: {
|
|
655
|
+
fontSize: 13,
|
|
656
|
+
fontWeight: "600"
|
|
657
|
+
},
|
|
658
|
+
screenshotSub: {
|
|
659
|
+
fontSize: 11
|
|
660
|
+
},
|
|
661
|
+
screenshotRemove: {
|
|
662
|
+
fontSize: 16,
|
|
663
|
+
fontWeight: "700",
|
|
664
|
+
paddingHorizontal: 4
|
|
590
665
|
}
|
|
591
666
|
});
|
|
592
667
|
|
|
@@ -678,6 +753,15 @@ function MushiProvider({ children, ...config }) {
|
|
|
678
753
|
const queueRef = useRef3(null);
|
|
679
754
|
const apiClientRef = useRef3(null);
|
|
680
755
|
const [sheetVisible, setSheetVisible] = useState2(false);
|
|
756
|
+
const [sheetScreenshot, setSheetScreenshot] = useState2(null);
|
|
757
|
+
const reporterTokenRef = useRef3(`rn-${config.projectId}-anon`);
|
|
758
|
+
let resolveReporterTokenReady = () => {
|
|
759
|
+
};
|
|
760
|
+
const reporterTokenReadyRef = useRef3(
|
|
761
|
+
new Promise((resolve) => {
|
|
762
|
+
resolveReporterTokenReady = resolve;
|
|
763
|
+
})
|
|
764
|
+
);
|
|
681
765
|
if (config.endpoint !== void 0 && config.endpoint.trim() === "") {
|
|
682
766
|
throw new Error(
|
|
683
767
|
"[MushiProvider] endpoint is set to an empty string. Set endpoint to your Supabase edge function URL, e.g. https://xyz.supabase.co/functions/v1/api, or omit it to use the cloud default."
|
|
@@ -703,6 +787,27 @@ function MushiProvider({ children, ...config }) {
|
|
|
703
787
|
});
|
|
704
788
|
queueRef.current.flush().catch(() => {
|
|
705
789
|
});
|
|
790
|
+
(async () => {
|
|
791
|
+
const TOKEN_KEY = "@mushi:reporter_token";
|
|
792
|
+
try {
|
|
793
|
+
const AsyncStorage = (await import("@react-native-async-storage/async-storage")).default;
|
|
794
|
+
const existing = await AsyncStorage.getItem(TOKEN_KEY);
|
|
795
|
+
if (existing && existing.startsWith("mushi_")) {
|
|
796
|
+
reporterTokenRef.current = existing;
|
|
797
|
+
} else {
|
|
798
|
+
const fresh = `mushi_${newUuid()}`;
|
|
799
|
+
reporterTokenRef.current = fresh;
|
|
800
|
+
await AsyncStorage.setItem(TOKEN_KEY, fresh);
|
|
801
|
+
}
|
|
802
|
+
resolveReporterTokenReady();
|
|
803
|
+
} catch {
|
|
804
|
+
if (reporterTokenRef.current === `rn-${config.projectId}-anon`) {
|
|
805
|
+
reporterTokenRef.current = `mushi_${newUuid()}`;
|
|
806
|
+
}
|
|
807
|
+
resolveReporterTokenReady();
|
|
808
|
+
}
|
|
809
|
+
})().catch(() => {
|
|
810
|
+
});
|
|
706
811
|
return () => {
|
|
707
812
|
consoleRef.current?.restore();
|
|
708
813
|
networkRef.current?.restore();
|
|
@@ -722,7 +827,25 @@ function MushiProvider({ children, ...config }) {
|
|
|
722
827
|
}
|
|
723
828
|
return () => unsubscribe?.();
|
|
724
829
|
}, []);
|
|
725
|
-
const open = useCallback3(() =>
|
|
830
|
+
const open = useCallback3(() => {
|
|
831
|
+
let vshot = null;
|
|
832
|
+
try {
|
|
833
|
+
vshot = __require("react-native-view-shot");
|
|
834
|
+
} catch {
|
|
835
|
+
}
|
|
836
|
+
if (!vshot) {
|
|
837
|
+
setSheetScreenshot(null);
|
|
838
|
+
setSheetVisible(true);
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
vshot.captureScreen({ format: "jpg", quality: 0.7, result: "data-uri" }).then((url) => {
|
|
842
|
+
setSheetScreenshot(url);
|
|
843
|
+
}).catch(() => {
|
|
844
|
+
setSheetScreenshot(null);
|
|
845
|
+
}).finally(() => {
|
|
846
|
+
setSheetVisible(true);
|
|
847
|
+
});
|
|
848
|
+
}, []);
|
|
726
849
|
const close = useCallback3(() => setSheetVisible(false), []);
|
|
727
850
|
const attachTo = useCallback3(() => ({ onPress: open }), [open]);
|
|
728
851
|
useEffect2(() => {
|
|
@@ -756,8 +879,16 @@ function MushiProvider({ children, ...config }) {
|
|
|
756
879
|
const submitReport = useCallback3(
|
|
757
880
|
async (data) => {
|
|
758
881
|
const deviceInfo = getDeviceInfo();
|
|
882
|
+
const contextMeta = {};
|
|
883
|
+
if (userRef.current?.id) contextMeta.userId = userRef.current.id;
|
|
884
|
+
if (userRef.current?.email) contextMeta.userEmail = userRef.current.email;
|
|
885
|
+
if (userRef.current?.name) contextMeta.userName = userRef.current.name;
|
|
886
|
+
if (screenRef.current?.name) contextMeta.screenName = screenRef.current.name;
|
|
887
|
+
if (screenRef.current?.route) contextMeta.screenRoute = screenRef.current.route;
|
|
888
|
+
if (screenRef.current?.feature) contextMeta.screenFeature = screenRef.current.feature;
|
|
889
|
+
const merged = Object.keys(metadataRef.current).length > 0 ? { ...contextMeta, ...metadataRef.current } : Object.keys(contextMeta).length > 0 ? contextMeta : void 0;
|
|
759
890
|
const report = {
|
|
760
|
-
id:
|
|
891
|
+
id: newUuid(),
|
|
761
892
|
projectId: config.projectId,
|
|
762
893
|
category: data.category,
|
|
763
894
|
description: data.description,
|
|
@@ -766,7 +897,7 @@ function MushiProvider({ children, ...config }) {
|
|
|
766
897
|
platform: deviceInfo.platform ?? "mobile",
|
|
767
898
|
language: deviceInfo.locale ?? "en",
|
|
768
899
|
viewport: { width: deviceInfo.screenWidth ?? 0, height: deviceInfo.screenHeight ?? 0 },
|
|
769
|
-
url: "",
|
|
900
|
+
url: screenRef.current?.route ?? "",
|
|
770
901
|
referrer: "",
|
|
771
902
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
772
903
|
timezone: deviceInfo.timezone ?? "UTC"
|
|
@@ -776,7 +907,9 @@ function MushiProvider({ children, ...config }) {
|
|
|
776
907
|
...entry,
|
|
777
908
|
status: entry.status ?? 0
|
|
778
909
|
})) ?? [],
|
|
779
|
-
|
|
910
|
+
screenshotDataUrl: data.screenshotDataUrl,
|
|
911
|
+
metadata: merged,
|
|
912
|
+
reporterToken: reporterTokenRef.current,
|
|
780
913
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
781
914
|
};
|
|
782
915
|
const client = apiClientRef.current;
|
|
@@ -786,7 +919,7 @@ function MushiProvider({ children, ...config }) {
|
|
|
786
919
|
await queueRef.current?.enqueue(report);
|
|
787
920
|
}
|
|
788
921
|
},
|
|
789
|
-
[config.projectId,
|
|
922
|
+
[config.projectId, apiEndpoint]
|
|
790
923
|
);
|
|
791
924
|
const userRef = useRef3(null);
|
|
792
925
|
const metadataRef = useRef3({});
|
|
@@ -837,6 +970,33 @@ function MushiProvider({ children, ...config }) {
|
|
|
837
970
|
setScreen(screen) {
|
|
838
971
|
screenRef.current = screen;
|
|
839
972
|
},
|
|
973
|
+
// Reporter API — scoped to the device's persistent reporter token
|
|
974
|
+
async listMyReports() {
|
|
975
|
+
const client = apiClientRef.current;
|
|
976
|
+
if (!client) return [];
|
|
977
|
+
await reporterTokenReadyRef.current;
|
|
978
|
+
const res = await client.listReporterReports(reporterTokenRef.current);
|
|
979
|
+
return res.ok ? res.data?.reports ?? [] : [];
|
|
980
|
+
},
|
|
981
|
+
async listMyComments(reportId) {
|
|
982
|
+
const client = apiClientRef.current;
|
|
983
|
+
if (!client) return [];
|
|
984
|
+
const res = await client.listReporterComments(reportId, reporterTokenRef.current);
|
|
985
|
+
return res.ok ? res.data.comments ?? [] : [];
|
|
986
|
+
},
|
|
987
|
+
async replyToReport(reportId, body) {
|
|
988
|
+
const client = apiClientRef.current;
|
|
989
|
+
if (!client) return null;
|
|
990
|
+
const res = await client.replyToReporterReport(reportId, reporterTokenRef.current, body);
|
|
991
|
+
return res.ok ? res.data.comment : null;
|
|
992
|
+
},
|
|
993
|
+
// Leaderboard — SDK-public anonymized hall-of-fame
|
|
994
|
+
async getHallOfFame(limit = 10) {
|
|
995
|
+
const client = apiClientRef.current;
|
|
996
|
+
if (!client) return [];
|
|
997
|
+
const res = await client.getHallOfFame(limit);
|
|
998
|
+
return res.ok ? res.data.data ?? [] : [];
|
|
999
|
+
},
|
|
840
1000
|
// Rewards (P1)
|
|
841
1001
|
recordActivity(action, metadata) {
|
|
842
1002
|
if (!config.rewards?.enabled) return;
|
|
@@ -878,7 +1038,15 @@ function MushiProvider({ children, ...config }) {
|
|
|
878
1038
|
inset: config.widget?.inset
|
|
879
1039
|
}
|
|
880
1040
|
),
|
|
881
|
-
/* @__PURE__ */ jsx3(
|
|
1041
|
+
/* @__PURE__ */ jsx3(
|
|
1042
|
+
MushiBottomSheet,
|
|
1043
|
+
{
|
|
1044
|
+
visible: sheetVisible,
|
|
1045
|
+
onClose: close,
|
|
1046
|
+
screenshotDataUrl: sheetScreenshot ?? void 0,
|
|
1047
|
+
onClearScreenshot: () => setSheetScreenshot(null)
|
|
1048
|
+
}
|
|
1049
|
+
)
|
|
882
1050
|
] });
|
|
883
1051
|
}
|
|
884
1052
|
function useMushiContext() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mushi-mushi/react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React Native SDK for Mushi Mushi — shake-to-report, bottom sheet widget, full context capture",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"@react-navigation/native": ">=6",
|
|
13
13
|
"expo-sensors": ">=13",
|
|
14
14
|
"react": ">=18",
|
|
15
|
-
"react-native": ">=0.72"
|
|
15
|
+
"react-native": ">=0.72",
|
|
16
|
+
"react-native-view-shot": ">=3.8"
|
|
16
17
|
},
|
|
17
18
|
"peerDependenciesMeta": {
|
|
18
19
|
"@react-navigation/native": {
|
|
@@ -26,10 +27,13 @@
|
|
|
26
27
|
},
|
|
27
28
|
"@react-native-community/netinfo": {
|
|
28
29
|
"optional": true
|
|
30
|
+
},
|
|
31
|
+
"react-native-view-shot": {
|
|
32
|
+
"optional": true
|
|
29
33
|
}
|
|
30
34
|
},
|
|
31
35
|
"dependencies": {
|
|
32
|
-
"@mushi-mushi/core": "^1.
|
|
36
|
+
"@mushi-mushi/core": "^1.10.0"
|
|
33
37
|
},
|
|
34
38
|
"devDependencies": {
|
|
35
39
|
"@types/react": "^19.2.14",
|