@mushi-mushi/react-native 0.15.0 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +35 -12
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +35 -12
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -170,10 +170,12 @@ var AsyncStorageQueue = class {
|
|
|
170
170
|
maxSize;
|
|
171
171
|
apiEndpoint;
|
|
172
172
|
apiKey;
|
|
173
|
+
onSynced;
|
|
173
174
|
constructor(config) {
|
|
174
175
|
this.maxSize = config.maxSize ?? 50;
|
|
175
176
|
this.apiEndpoint = config.apiEndpoint;
|
|
176
177
|
this.apiKey = config.apiKey;
|
|
178
|
+
this.onSynced = config.onSynced;
|
|
177
179
|
}
|
|
178
180
|
async enqueue(report) {
|
|
179
181
|
const AsyncStorage = await this.getAsyncStorage();
|
|
@@ -195,6 +197,13 @@ var AsyncStorageQueue = class {
|
|
|
195
197
|
const ok = await sendWithRetry(item, this.apiEndpoint, this.apiKey);
|
|
196
198
|
if (ok) {
|
|
197
199
|
flushed++;
|
|
200
|
+
const reportId = item.report.id;
|
|
201
|
+
if (typeof reportId === "string") {
|
|
202
|
+
try {
|
|
203
|
+
this.onSynced?.(reportId);
|
|
204
|
+
} catch {
|
|
205
|
+
}
|
|
206
|
+
}
|
|
198
207
|
} else {
|
|
199
208
|
remaining.push(item);
|
|
200
209
|
break;
|
|
@@ -319,6 +328,7 @@ var CATEGORIES = [
|
|
|
319
328
|
{ key: "confusing", emoji: "\u{1F615}", label: "Confusing" },
|
|
320
329
|
{ key: "other", emoji: "\u{1F4AC}", label: "Other" }
|
|
321
330
|
];
|
|
331
|
+
var VERIFIABLE_STATUSES = /* @__PURE__ */ new Set(["fixed", "resolved", "verified"]);
|
|
322
332
|
var MushiBottomSheet = ({
|
|
323
333
|
visible,
|
|
324
334
|
onClose,
|
|
@@ -340,12 +350,6 @@ var MushiBottomSheet = ({
|
|
|
340
350
|
const [threadComments, setThreadComments] = (0, import_react.useState)([]);
|
|
341
351
|
const [replyText, setReplyText] = (0, import_react.useState)("");
|
|
342
352
|
const [screenshotAttached, setScreenshotAttached] = (0, import_react.useState)(true);
|
|
343
|
-
(0, import_react.useEffect)(() => {
|
|
344
|
-
if (visible) {
|
|
345
|
-
setScreenshotAttached(true);
|
|
346
|
-
if (sheetTab === "inbox") void loadInbox();
|
|
347
|
-
}
|
|
348
|
-
}, [visible, sheetTab]);
|
|
349
353
|
const loadInbox = (0, import_react.useCallback)(async () => {
|
|
350
354
|
if (!mushi?.listMyReports) return;
|
|
351
355
|
setInboxLoading(true);
|
|
@@ -356,6 +360,12 @@ var MushiBottomSheet = ({
|
|
|
356
360
|
setInboxLoading(false);
|
|
357
361
|
}
|
|
358
362
|
}, [mushi]);
|
|
363
|
+
(0, import_react.useEffect)(() => {
|
|
364
|
+
if (visible) {
|
|
365
|
+
setScreenshotAttached(true);
|
|
366
|
+
if (sheetTab === "inbox") void loadInbox();
|
|
367
|
+
}
|
|
368
|
+
}, [visible, sheetTab, loadInbox]);
|
|
359
369
|
const openThread = (0, import_react.useCallback)(async (reportId) => {
|
|
360
370
|
setSelectedReportId(reportId);
|
|
361
371
|
if (!mushi?.listMyComments) return;
|
|
@@ -500,7 +510,9 @@ var MushiBottomSheet = ({
|
|
|
500
510
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.sub, fontSize: 11 }, children: c.author_kind }),
|
|
501
511
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: { color: colors.text }, children: c.body })
|
|
502
512
|
] }, c.id)),
|
|
503
|
-
|
|
513
|
+
VERIFIABLE_STATUSES.has(
|
|
514
|
+
inboxReports.find((r) => r.id === selectedReportId)?.status ?? ""
|
|
515
|
+
) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: s.verifyRow, children: [
|
|
504
516
|
/* @__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, children: "Yes, fixed" }) }),
|
|
505
517
|
/* @__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: "Not fixed" }) })
|
|
506
518
|
] }),
|
|
@@ -876,12 +888,16 @@ function MushiProvider({ children, ...config }) {
|
|
|
876
888
|
resolveReporterTokenReady = resolve;
|
|
877
889
|
})
|
|
878
890
|
);
|
|
879
|
-
|
|
891
|
+
const rawEndpoint = config.apiEndpoint ?? config.endpoint;
|
|
892
|
+
if (rawEndpoint !== void 0 && rawEndpoint.trim() === "") {
|
|
880
893
|
throw new Error(
|
|
881
|
-
"[MushiProvider]
|
|
894
|
+
"[MushiProvider] apiEndpoint is set to an empty string. Set apiEndpoint to your Supabase edge function URL, e.g. https://xyz.supabase.co/functions/v1/api, or omit it to use the cloud default."
|
|
882
895
|
);
|
|
883
896
|
}
|
|
884
|
-
|
|
897
|
+
if (config.endpoint && !config.apiEndpoint && __DEV__) {
|
|
898
|
+
console.warn("[MushiProvider] `endpoint` is deprecated \u2014 use `apiEndpoint` instead.");
|
|
899
|
+
}
|
|
900
|
+
const apiEndpoint = rawEndpoint ?? import_core.DEFAULT_API_ENDPOINT;
|
|
885
901
|
(0, import_react3.useEffect)(() => {
|
|
886
902
|
if (config.capture?.console !== false) {
|
|
887
903
|
consoleRef.current = setupConsoleCapture(config.capture?.maxConsoleEntries);
|
|
@@ -897,7 +913,11 @@ function MushiProvider({ children, ...config }) {
|
|
|
897
913
|
queueRef.current = new AsyncStorageQueue({
|
|
898
914
|
maxSize: config.storage?.maxQueueSize,
|
|
899
915
|
apiEndpoint,
|
|
900
|
-
apiKey: config.apiKey
|
|
916
|
+
apiKey: config.apiKey,
|
|
917
|
+
// `onReportSynced` fires here — when a previously-queued report actually
|
|
918
|
+
// drains to the server — not on the direct-submit path (where it would be
|
|
919
|
+
// indistinguishable from `onReportSubmitted` and thus meaningless).
|
|
920
|
+
onSynced: (reportId) => config.callbacks?.onReportSynced?.(reportId)
|
|
901
921
|
});
|
|
902
922
|
queueRef.current.flush().catch(() => {
|
|
903
923
|
});
|
|
@@ -1031,9 +1051,12 @@ function MushiProvider({ children, ...config }) {
|
|
|
1031
1051
|
const result = await client.submitReport(report);
|
|
1032
1052
|
if (!result.ok) {
|
|
1033
1053
|
await queueRef.current?.enqueue(report);
|
|
1054
|
+
config.callbacks?.onReportQueued?.(report.id);
|
|
1055
|
+
} else {
|
|
1056
|
+
config.callbacks?.onReportSubmitted?.(report.id);
|
|
1034
1057
|
}
|
|
1035
1058
|
},
|
|
1036
|
-
[config.projectId, apiEndpoint]
|
|
1059
|
+
[config.projectId, config.callbacks, apiEndpoint]
|
|
1037
1060
|
);
|
|
1038
1061
|
const userRef = (0, import_react3.useRef)(null);
|
|
1039
1062
|
const metadataRef = (0, import_react3.useRef)({});
|
package/dist/index.d.cts
CHANGED
|
@@ -46,7 +46,18 @@ declare function getDeviceInfo(): DeviceInfo;
|
|
|
46
46
|
interface MushiRNConfig {
|
|
47
47
|
projectId: string;
|
|
48
48
|
apiKey: string;
|
|
49
|
+
/** @deprecated Prefer `apiEndpoint` — kept for backward compatibility */
|
|
49
50
|
endpoint?: string;
|
|
51
|
+
/** Canonical Mushi API base URL (e.g. https://xyz.supabase.co/functions/v1/api) */
|
|
52
|
+
apiEndpoint?: string;
|
|
53
|
+
/** Lifecycle callbacks for host-app integration (replaces polling in HHTP etc.) */
|
|
54
|
+
callbacks?: {
|
|
55
|
+
onReportSubmitted?: (reportId: string) => void;
|
|
56
|
+
onReportQueued?: (reportId: string) => void;
|
|
57
|
+
onReportSynced?: (reportId: string) => void;
|
|
58
|
+
onReporterReply?: (reportId: string, commentId: string) => void;
|
|
59
|
+
onFixStatusChanged?: (reportId: string, status: string) => void;
|
|
60
|
+
};
|
|
50
61
|
widget?: {
|
|
51
62
|
trigger?: 'shake' | 'button' | 'both' | 'manual' | 'auto' | 'edge-tab' | 'hidden' | 'attach';
|
|
52
63
|
shakeThreshold?: number;
|
|
@@ -240,10 +251,13 @@ declare class AsyncStorageQueue {
|
|
|
240
251
|
private maxSize;
|
|
241
252
|
private apiEndpoint;
|
|
242
253
|
private apiKey;
|
|
254
|
+
private onSynced?;
|
|
243
255
|
constructor(config: {
|
|
244
256
|
maxSize?: number;
|
|
245
257
|
apiEndpoint: string;
|
|
246
258
|
apiKey: string;
|
|
259
|
+
/** Fired once per queued report that drains successfully to the server. */
|
|
260
|
+
onSynced?: (reportId: string) => void;
|
|
247
261
|
});
|
|
248
262
|
enqueue(report: object): Promise<void>;
|
|
249
263
|
flush(): Promise<number>;
|
package/dist/index.d.ts
CHANGED
|
@@ -46,7 +46,18 @@ declare function getDeviceInfo(): DeviceInfo;
|
|
|
46
46
|
interface MushiRNConfig {
|
|
47
47
|
projectId: string;
|
|
48
48
|
apiKey: string;
|
|
49
|
+
/** @deprecated Prefer `apiEndpoint` — kept for backward compatibility */
|
|
49
50
|
endpoint?: string;
|
|
51
|
+
/** Canonical Mushi API base URL (e.g. https://xyz.supabase.co/functions/v1/api) */
|
|
52
|
+
apiEndpoint?: string;
|
|
53
|
+
/** Lifecycle callbacks for host-app integration (replaces polling in HHTP etc.) */
|
|
54
|
+
callbacks?: {
|
|
55
|
+
onReportSubmitted?: (reportId: string) => void;
|
|
56
|
+
onReportQueued?: (reportId: string) => void;
|
|
57
|
+
onReportSynced?: (reportId: string) => void;
|
|
58
|
+
onReporterReply?: (reportId: string, commentId: string) => void;
|
|
59
|
+
onFixStatusChanged?: (reportId: string, status: string) => void;
|
|
60
|
+
};
|
|
50
61
|
widget?: {
|
|
51
62
|
trigger?: 'shake' | 'button' | 'both' | 'manual' | 'auto' | 'edge-tab' | 'hidden' | 'attach';
|
|
52
63
|
shakeThreshold?: number;
|
|
@@ -240,10 +251,13 @@ declare class AsyncStorageQueue {
|
|
|
240
251
|
private maxSize;
|
|
241
252
|
private apiEndpoint;
|
|
242
253
|
private apiKey;
|
|
254
|
+
private onSynced?;
|
|
243
255
|
constructor(config: {
|
|
244
256
|
maxSize?: number;
|
|
245
257
|
apiEndpoint: string;
|
|
246
258
|
apiKey: string;
|
|
259
|
+
/** Fired once per queued report that drains successfully to the server. */
|
|
260
|
+
onSynced?: (reportId: string) => void;
|
|
247
261
|
});
|
|
248
262
|
enqueue(report: object): Promise<void>;
|
|
249
263
|
flush(): Promise<number>;
|
package/dist/index.js
CHANGED
|
@@ -142,10 +142,12 @@ var AsyncStorageQueue = class {
|
|
|
142
142
|
maxSize;
|
|
143
143
|
apiEndpoint;
|
|
144
144
|
apiKey;
|
|
145
|
+
onSynced;
|
|
145
146
|
constructor(config) {
|
|
146
147
|
this.maxSize = config.maxSize ?? 50;
|
|
147
148
|
this.apiEndpoint = config.apiEndpoint;
|
|
148
149
|
this.apiKey = config.apiKey;
|
|
150
|
+
this.onSynced = config.onSynced;
|
|
149
151
|
}
|
|
150
152
|
async enqueue(report) {
|
|
151
153
|
const AsyncStorage = await this.getAsyncStorage();
|
|
@@ -167,6 +169,13 @@ var AsyncStorageQueue = class {
|
|
|
167
169
|
const ok = await sendWithRetry(item, this.apiEndpoint, this.apiKey);
|
|
168
170
|
if (ok) {
|
|
169
171
|
flushed++;
|
|
172
|
+
const reportId = item.report.id;
|
|
173
|
+
if (typeof reportId === "string") {
|
|
174
|
+
try {
|
|
175
|
+
this.onSynced?.(reportId);
|
|
176
|
+
} catch {
|
|
177
|
+
}
|
|
178
|
+
}
|
|
170
179
|
} else {
|
|
171
180
|
remaining.push(item);
|
|
172
181
|
break;
|
|
@@ -310,6 +319,7 @@ var CATEGORIES = [
|
|
|
310
319
|
{ key: "confusing", emoji: "\u{1F615}", label: "Confusing" },
|
|
311
320
|
{ key: "other", emoji: "\u{1F4AC}", label: "Other" }
|
|
312
321
|
];
|
|
322
|
+
var VERIFIABLE_STATUSES = /* @__PURE__ */ new Set(["fixed", "resolved", "verified"]);
|
|
313
323
|
var MushiBottomSheet = ({
|
|
314
324
|
visible,
|
|
315
325
|
onClose,
|
|
@@ -331,12 +341,6 @@ var MushiBottomSheet = ({
|
|
|
331
341
|
const [threadComments, setThreadComments] = useState([]);
|
|
332
342
|
const [replyText, setReplyText] = useState("");
|
|
333
343
|
const [screenshotAttached, setScreenshotAttached] = useState(true);
|
|
334
|
-
useEffect(() => {
|
|
335
|
-
if (visible) {
|
|
336
|
-
setScreenshotAttached(true);
|
|
337
|
-
if (sheetTab === "inbox") void loadInbox();
|
|
338
|
-
}
|
|
339
|
-
}, [visible, sheetTab]);
|
|
340
344
|
const loadInbox = useCallback(async () => {
|
|
341
345
|
if (!mushi?.listMyReports) return;
|
|
342
346
|
setInboxLoading(true);
|
|
@@ -347,6 +351,12 @@ var MushiBottomSheet = ({
|
|
|
347
351
|
setInboxLoading(false);
|
|
348
352
|
}
|
|
349
353
|
}, [mushi]);
|
|
354
|
+
useEffect(() => {
|
|
355
|
+
if (visible) {
|
|
356
|
+
setScreenshotAttached(true);
|
|
357
|
+
if (sheetTab === "inbox") void loadInbox();
|
|
358
|
+
}
|
|
359
|
+
}, [visible, sheetTab, loadInbox]);
|
|
350
360
|
const openThread = useCallback(async (reportId) => {
|
|
351
361
|
setSelectedReportId(reportId);
|
|
352
362
|
if (!mushi?.listMyComments) return;
|
|
@@ -491,7 +501,9 @@ var MushiBottomSheet = ({
|
|
|
491
501
|
/* @__PURE__ */ jsx(Text, { style: { color: colors.sub, fontSize: 11 }, children: c.author_kind }),
|
|
492
502
|
/* @__PURE__ */ jsx(Text, { style: { color: colors.text }, children: c.body })
|
|
493
503
|
] }, c.id)),
|
|
494
|
-
|
|
504
|
+
VERIFIABLE_STATUSES.has(
|
|
505
|
+
inboxReports.find((r) => r.id === selectedReportId)?.status ?? ""
|
|
506
|
+
) && /* @__PURE__ */ jsxs(View, { style: s.verifyRow, children: [
|
|
495
507
|
/* @__PURE__ */ jsx(TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.accent }], onPress: () => submitFeedback("confirms"), children: /* @__PURE__ */ jsx(Text, { style: s.submitText, children: "Yes, fixed" }) }),
|
|
496
508
|
/* @__PURE__ */ jsx(TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.border }], onPress: () => submitFeedback("not_fixed"), children: /* @__PURE__ */ jsx(Text, { style: [s.submitText, { color: colors.text }], children: "Not fixed" }) })
|
|
497
509
|
] }),
|
|
@@ -873,12 +885,16 @@ function MushiProvider({ children, ...config }) {
|
|
|
873
885
|
resolveReporterTokenReady = resolve;
|
|
874
886
|
})
|
|
875
887
|
);
|
|
876
|
-
|
|
888
|
+
const rawEndpoint = config.apiEndpoint ?? config.endpoint;
|
|
889
|
+
if (rawEndpoint !== void 0 && rawEndpoint.trim() === "") {
|
|
877
890
|
throw new Error(
|
|
878
|
-
"[MushiProvider]
|
|
891
|
+
"[MushiProvider] apiEndpoint is set to an empty string. Set apiEndpoint to your Supabase edge function URL, e.g. https://xyz.supabase.co/functions/v1/api, or omit it to use the cloud default."
|
|
879
892
|
);
|
|
880
893
|
}
|
|
881
|
-
|
|
894
|
+
if (config.endpoint && !config.apiEndpoint && __DEV__) {
|
|
895
|
+
console.warn("[MushiProvider] `endpoint` is deprecated \u2014 use `apiEndpoint` instead.");
|
|
896
|
+
}
|
|
897
|
+
const apiEndpoint = rawEndpoint ?? DEFAULT_API_ENDPOINT;
|
|
882
898
|
useEffect2(() => {
|
|
883
899
|
if (config.capture?.console !== false) {
|
|
884
900
|
consoleRef.current = setupConsoleCapture(config.capture?.maxConsoleEntries);
|
|
@@ -894,7 +910,11 @@ function MushiProvider({ children, ...config }) {
|
|
|
894
910
|
queueRef.current = new AsyncStorageQueue({
|
|
895
911
|
maxSize: config.storage?.maxQueueSize,
|
|
896
912
|
apiEndpoint,
|
|
897
|
-
apiKey: config.apiKey
|
|
913
|
+
apiKey: config.apiKey,
|
|
914
|
+
// `onReportSynced` fires here — when a previously-queued report actually
|
|
915
|
+
// drains to the server — not on the direct-submit path (where it would be
|
|
916
|
+
// indistinguishable from `onReportSubmitted` and thus meaningless).
|
|
917
|
+
onSynced: (reportId) => config.callbacks?.onReportSynced?.(reportId)
|
|
898
918
|
});
|
|
899
919
|
queueRef.current.flush().catch(() => {
|
|
900
920
|
});
|
|
@@ -1028,9 +1048,12 @@ function MushiProvider({ children, ...config }) {
|
|
|
1028
1048
|
const result = await client.submitReport(report);
|
|
1029
1049
|
if (!result.ok) {
|
|
1030
1050
|
await queueRef.current?.enqueue(report);
|
|
1051
|
+
config.callbacks?.onReportQueued?.(report.id);
|
|
1052
|
+
} else {
|
|
1053
|
+
config.callbacks?.onReportSubmitted?.(report.id);
|
|
1031
1054
|
}
|
|
1032
1055
|
},
|
|
1033
|
-
[config.projectId, apiEndpoint]
|
|
1056
|
+
[config.projectId, config.callbacks, apiEndpoint]
|
|
1034
1057
|
);
|
|
1035
1058
|
const userRef = useRef3(null);
|
|
1036
1059
|
const metadataRef = useRef3({});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mushi-mushi/react-native",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.2",
|
|
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",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@mushi-mushi/core": "^1.
|
|
36
|
+
"@mushi-mushi/core": "^1.12.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/react": "^19.2.14",
|