@mushi-mushi/react-native 0.23.0 → 0.24.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/dist/index.d.cts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, FC, ReactElement } from 'react';
3
- import { MushiAnalyticsConfig, MushiRewardsConfig, MushiPageContext, MushiBreadcrumb, MushiReporterReport, MushiReporterComment, MushiHallOfFameEntry, MushiPropertyValue, MushiTierResult, MushiReputationResult, MushiAssistantReply } from '@mushi-mushi/core';
3
+ import { MushiAnalyticsConfig, MushiRewardsConfig, MushiPageContext, MushiBreadcrumb, MushiReporterReport, MushiReporterComment, MushiApiResponse, MushiHallOfFameEntry, MushiPropertyValue, MushiTierResult, MushiReputationResult, MushiAssistantReply } from '@mushi-mushi/core';
4
4
  export { MushiHallOfFameEntry, MushiReporterComment, MushiReporterReport } from '@mushi-mushi/core';
5
+ import { MushiReporterUpdates, MushiReporterNotificationPrefs, MushiReporterPrefsUpdate, MushiReporterReportDetail } from '@mushi-mushi/core/reporter-channels';
5
6
 
6
7
  interface ConsoleEntry {
7
8
  level: 'log' | 'warn' | 'error';
@@ -158,6 +159,32 @@ interface MushiRNConfig {
158
159
  * `accent` is set, the text on it is chosen for contrast.
159
160
  */
160
161
  theme?: Partial<MushiRNTheme>;
162
+ /**
163
+ * Characters needed before Send enables. Default 8 (Plan 018 §1.1); an
164
+ * attached screenshot lowers it to 0.
165
+ */
166
+ minDescriptionLength?: number;
167
+ };
168
+ /**
169
+ * Optional native modules, passed in instead of loaded. When set, the SDK
170
+ * uses them and never loads that package itself — the safest option for
171
+ * Metro configs that disallow optional requires. Each one is also picked up
172
+ * automatically when installed.
173
+ * - `netInfo`: `@react-native-community/netinfo` — resend queued reports when the network returns.
174
+ * - `viewShot`: `react-native-view-shot` — attach a screenshot.
175
+ * - `expoSensors`: `expo-sensors` — shake to report.
176
+ */
177
+ netInfo?: unknown;
178
+ viewShot?: unknown;
179
+ expoSensors?: unknown;
180
+ /** How reporters hear back outside the sheet (Plan 018 §4). No native push. */
181
+ notifications?: {
182
+ /** One "the developer replied" / "your bug is fixed" toast when the app returns to the foreground. Default true. */
183
+ toast?: boolean;
184
+ /** Offer "Get updates by email" after sending, when the project offers email. Default true. */
185
+ email?: boolean;
186
+ /** Prefill that email box from `setUser({ email })`. Default false; the box is never pre-ticked. */
187
+ emailFromIdentity?: boolean;
161
188
  };
162
189
  assistant?: {
163
190
  enabled?: boolean;
@@ -218,6 +245,8 @@ interface MushiRNInstance {
218
245
  submitReport(data: {
219
246
  description: string;
220
247
  category: string;
248
+ /** Host / chip sub-label, e.g. 'feature' for the Idea chip. */
249
+ userCategory?: string;
221
250
  screenshotDataUrl?: string;
222
251
  }): Promise<{
223
252
  ok: boolean;
@@ -275,6 +304,33 @@ interface MushiRNInstance {
275
304
  loadMyThread(reportId: string): Promise<MushiReporterComment[] | null>;
276
305
  /** Mark this device's unread notifications for a report as read. Resolves the number marked (0 on failure). */
277
306
  markReportRead(reportId: string): Promise<number>;
307
+ /** Unread count and the newest unread updates on this device's reports (null on failure). */
308
+ getReporterUpdates(): Promise<MushiReporterUpdates | null>;
309
+ /**
310
+ * Fires with the unread count and newest updates when you subscribe and
311
+ * each time the app comes back to the foreground, so the host can draw its
312
+ * own badge (a feedback band, a tab dot). Returns an unsubscribe function.
313
+ */
314
+ onReporterUpdate(cb: (updates: MushiReporterUpdates) => void): () => void;
315
+ /** This reporter's email choices; the address comes back masked (null on failure). */
316
+ getNotificationPrefs(): Promise<MushiReporterNotificationPrefs | null>;
317
+ /**
318
+ * Ask for email updates (`{ email }` sends a confirmation email first) or
319
+ * change channels. Only when the reporter asked — never pre-tick an opt-in.
320
+ * Resolves the server's answer, including `EMAIL_NOT_AVAILABLE` when this
321
+ * app does not offer email. (No native push on React Native.)
322
+ */
323
+ setNotificationPrefs(update: MushiReporterPrefsUpdate): Promise<MushiApiResponse<MushiReporterNotificationPrefs>>;
324
+ /**
325
+ * One report with its timeline (GET /v1/reporter/reports/:id). Resolves
326
+ * null when it could not be loaded (show Retry) and 'unsupported' when the
327
+ * server predates the route (fall back to `loadMyThread`).
328
+ */
329
+ loadMyReportDetail(reportId: string): Promise<MushiReporterReportDetail | null | 'unsupported'>;
330
+ /** The address to prefill in the email opt-in box, only with `notifications.emailFromIdentity`. */
331
+ emailPrefill(): string | null;
332
+ /** Open the sheet on "Your reports". */
333
+ openMyReports(): void;
278
334
  /** Post a reporter reply on a report thread. Returns the new comment or null on failure. */
279
335
  replyToReport(reportId: string, body: string): Promise<MushiReporterComment | null>;
280
336
  /** Record a reporter feedback signal (e.g. `confirms`, `not_fixed`) on a report. Returns the outcome or null. */
@@ -328,7 +384,9 @@ declare function useMushiWidget(): {
328
384
  *
329
385
  * OVERVIEW:
330
386
  * - Slide-up modal built entirely on RN built-ins (Modal, Animated, PanResponder)
331
- * - Conversational flow: category → description → submit → confirmation
387
+ * - One screen, free text first: optional type chips, Send once there are a
388
+ * few words (8 by default) or a screenshot, then a receipt in place with
389
+ * Track it / Done and an optional, never pre-ticked email opt-in
332
390
  * - Drag-to-dismiss via PanResponder on the handle area
333
391
  * - Host-adaptive theme (`widget.theme`, see ../theme.ts) over light/dark
334
392
  * - "Your reports": statuses come from the shared core table
@@ -345,13 +403,17 @@ declare function useMushiWidget(): {
345
403
  * TECHNICAL DETAILS:
346
404
  * - PanResponder threshold: 80 px downward drag dismisses
347
405
  * - Animated.spring for slide-up, Animated.timing for backdrop
348
- * - Success confirmation auto-closes after 1.4 s
349
- * - Thread loads show a skeleton, then Retry on failure; a failed reply keeps
350
- * its text and offers Retry. Opening a thread marks it read.
406
+ * - Reduce Motion (AccessibilityInfo) makes open / close instant
407
+ * - The thread is the report's v2 timeline (GET /v1/reporter/reports/:id):
408
+ * pipeline events render from the shared core templates in the reporter's
409
+ * locale, replies as bubbles. Loads show a skeleton, then Retry on failure;
410
+ * a failed reply keeps its text and offers Retry. Opening a thread marks it
411
+ * read. An older server without the route falls back to the comment list.
351
412
  *
352
413
  * NOTES:
353
414
  * - KeyboardAvoidingView wraps the sheet so the text input stays visible
354
- * - Categories match the web SDK: bug, slow, visual, confusing, other
415
+ * - Chips come from core's REPORTER_CATEGORIES (bug, slow, visual, confusing,
416
+ * idea); "Idea" files a feature request
355
417
  * - accessibilityViewIsModal is iOS-only; RN's Modal is its own window on
356
418
  * Android, which keeps TalkBack focus inside the sheet there.
357
419
  */
@@ -379,6 +441,10 @@ interface MushiBottomSheetProps {
379
441
  inboxPollIntervalMs?: number;
380
442
  /** Theme tokens (`widget.theme`); unset tokens use the neutral defaults. */
381
443
  theme?: Partial<MushiRNTheme>;
444
+ /** Characters needed before Send enables (`widget.minDescriptionLength`, default 8). */
445
+ minDescriptionLength?: number;
446
+ /** Offer "Get updates by email" on the receipt when the project offers email (`notifications.email`). */
447
+ emailOptIn?: boolean;
382
448
  }
383
449
  declare const MushiBottomSheet: FC<MushiBottomSheetProps>;
384
450
 
@@ -502,4 +568,46 @@ declare class AsyncStorageQueue {
502
568
  private getAsyncStorage;
503
569
  }
504
570
 
505
- export { AsyncStorageQueue, type ConsoleEntry, type DeviceInfo, MUSHI_BANNER_DEFAULT_HEIGHT, MushiBanner, type MushiBannerProps, MushiBottomSheet, type MushiBottomSheetProps, MushiFloatingButton, type MushiFloatingButtonProps, MushiProvider, type MushiRNConfig, type MushiRNInstance, MushiTrigger, type MushiTriggerProps, type NavigationEntry, type NetworkEntry, type RNAnalyticsConfig, getDeviceInfo, setupConsoleCapture, setupNetworkCapture, useMushi, useMushiReport, useMushiWidget, useNavigationCapture };
571
+ /**
572
+ * FILE: optional-modules.ts
573
+ * PURPOSE: The SDK's three optional native peers (network-aware delivery,
574
+ * screenshots, shake-to-report), loaded without crashing the app.
575
+ *
576
+ * Order for each one:
577
+ * 1. A module the host passed in config (`netInfo`, `viewShot`, `expoSensors`).
578
+ * No dynamic loading at all — the safest path.
579
+ * 2. A literal `require('<module>')` inside try/catch. Metro resolves a literal
580
+ * require at bundle time and treats one inside try/catch as optional
581
+ * (`transformer.allowOptionalDependencies`, on in Expo and React Native's
582
+ * default Metro config).
583
+ *
584
+ * Why the build matters: esbuild's ESM output rewrites `require('x')` to its
585
+ * `__require('x')` interop shim. Metro can't resolve a module name handed to
586
+ * the shim, so it called its own require with a string at runtime and crashed
587
+ * the app (reportFatalError) — the try/catch never saw it (0.21–0.23).
588
+ * tsup.config.ts restores literal `require(...)` in dist and fails the build
589
+ * if any `__require(` is left (src/bundling/preserve-optional-requires.ts).
590
+ */
591
+ interface MushiNetInfoModule {
592
+ addEventListener(listener: (state: {
593
+ isConnected: boolean | null;
594
+ isInternetReachable: boolean | null;
595
+ }) => void): () => void;
596
+ }
597
+ interface MushiViewShotModule {
598
+ captureScreen(options: Record<string, unknown>): Promise<string>;
599
+ }
600
+ interface MushiExpoSensorsModule {
601
+ Accelerometer: {
602
+ setUpdateInterval(ms: number): void;
603
+ addListener(listener: (event: {
604
+ x: number;
605
+ y: number;
606
+ z: number;
607
+ }) => void): {
608
+ remove(): void;
609
+ };
610
+ };
611
+ }
612
+
613
+ export { AsyncStorageQueue, type ConsoleEntry, type DeviceInfo, MUSHI_BANNER_DEFAULT_HEIGHT, MushiBanner, type MushiBannerProps, MushiBottomSheet, type MushiBottomSheetProps, type MushiExpoSensorsModule, MushiFloatingButton, type MushiFloatingButtonProps, type MushiNetInfoModule, MushiProvider, type MushiRNConfig, type MushiRNInstance, MushiTrigger, type MushiTriggerProps, type MushiViewShotModule, type NavigationEntry, type NetworkEntry, type RNAnalyticsConfig, getDeviceInfo, setupConsoleCapture, setupNetworkCapture, useMushi, useMushiReport, useMushiWidget, useNavigationCapture };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, FC, ReactElement } from 'react';
3
- import { MushiAnalyticsConfig, MushiRewardsConfig, MushiPageContext, MushiBreadcrumb, MushiReporterReport, MushiReporterComment, MushiHallOfFameEntry, MushiPropertyValue, MushiTierResult, MushiReputationResult, MushiAssistantReply } from '@mushi-mushi/core';
3
+ import { MushiAnalyticsConfig, MushiRewardsConfig, MushiPageContext, MushiBreadcrumb, MushiReporterReport, MushiReporterComment, MushiApiResponse, MushiHallOfFameEntry, MushiPropertyValue, MushiTierResult, MushiReputationResult, MushiAssistantReply } from '@mushi-mushi/core';
4
4
  export { MushiHallOfFameEntry, MushiReporterComment, MushiReporterReport } from '@mushi-mushi/core';
5
+ import { MushiReporterUpdates, MushiReporterNotificationPrefs, MushiReporterPrefsUpdate, MushiReporterReportDetail } from '@mushi-mushi/core/reporter-channels';
5
6
 
6
7
  interface ConsoleEntry {
7
8
  level: 'log' | 'warn' | 'error';
@@ -158,6 +159,32 @@ interface MushiRNConfig {
158
159
  * `accent` is set, the text on it is chosen for contrast.
159
160
  */
160
161
  theme?: Partial<MushiRNTheme>;
162
+ /**
163
+ * Characters needed before Send enables. Default 8 (Plan 018 §1.1); an
164
+ * attached screenshot lowers it to 0.
165
+ */
166
+ minDescriptionLength?: number;
167
+ };
168
+ /**
169
+ * Optional native modules, passed in instead of loaded. When set, the SDK
170
+ * uses them and never loads that package itself — the safest option for
171
+ * Metro configs that disallow optional requires. Each one is also picked up
172
+ * automatically when installed.
173
+ * - `netInfo`: `@react-native-community/netinfo` — resend queued reports when the network returns.
174
+ * - `viewShot`: `react-native-view-shot` — attach a screenshot.
175
+ * - `expoSensors`: `expo-sensors` — shake to report.
176
+ */
177
+ netInfo?: unknown;
178
+ viewShot?: unknown;
179
+ expoSensors?: unknown;
180
+ /** How reporters hear back outside the sheet (Plan 018 §4). No native push. */
181
+ notifications?: {
182
+ /** One "the developer replied" / "your bug is fixed" toast when the app returns to the foreground. Default true. */
183
+ toast?: boolean;
184
+ /** Offer "Get updates by email" after sending, when the project offers email. Default true. */
185
+ email?: boolean;
186
+ /** Prefill that email box from `setUser({ email })`. Default false; the box is never pre-ticked. */
187
+ emailFromIdentity?: boolean;
161
188
  };
162
189
  assistant?: {
163
190
  enabled?: boolean;
@@ -218,6 +245,8 @@ interface MushiRNInstance {
218
245
  submitReport(data: {
219
246
  description: string;
220
247
  category: string;
248
+ /** Host / chip sub-label, e.g. 'feature' for the Idea chip. */
249
+ userCategory?: string;
221
250
  screenshotDataUrl?: string;
222
251
  }): Promise<{
223
252
  ok: boolean;
@@ -275,6 +304,33 @@ interface MushiRNInstance {
275
304
  loadMyThread(reportId: string): Promise<MushiReporterComment[] | null>;
276
305
  /** Mark this device's unread notifications for a report as read. Resolves the number marked (0 on failure). */
277
306
  markReportRead(reportId: string): Promise<number>;
307
+ /** Unread count and the newest unread updates on this device's reports (null on failure). */
308
+ getReporterUpdates(): Promise<MushiReporterUpdates | null>;
309
+ /**
310
+ * Fires with the unread count and newest updates when you subscribe and
311
+ * each time the app comes back to the foreground, so the host can draw its
312
+ * own badge (a feedback band, a tab dot). Returns an unsubscribe function.
313
+ */
314
+ onReporterUpdate(cb: (updates: MushiReporterUpdates) => void): () => void;
315
+ /** This reporter's email choices; the address comes back masked (null on failure). */
316
+ getNotificationPrefs(): Promise<MushiReporterNotificationPrefs | null>;
317
+ /**
318
+ * Ask for email updates (`{ email }` sends a confirmation email first) or
319
+ * change channels. Only when the reporter asked — never pre-tick an opt-in.
320
+ * Resolves the server's answer, including `EMAIL_NOT_AVAILABLE` when this
321
+ * app does not offer email. (No native push on React Native.)
322
+ */
323
+ setNotificationPrefs(update: MushiReporterPrefsUpdate): Promise<MushiApiResponse<MushiReporterNotificationPrefs>>;
324
+ /**
325
+ * One report with its timeline (GET /v1/reporter/reports/:id). Resolves
326
+ * null when it could not be loaded (show Retry) and 'unsupported' when the
327
+ * server predates the route (fall back to `loadMyThread`).
328
+ */
329
+ loadMyReportDetail(reportId: string): Promise<MushiReporterReportDetail | null | 'unsupported'>;
330
+ /** The address to prefill in the email opt-in box, only with `notifications.emailFromIdentity`. */
331
+ emailPrefill(): string | null;
332
+ /** Open the sheet on "Your reports". */
333
+ openMyReports(): void;
278
334
  /** Post a reporter reply on a report thread. Returns the new comment or null on failure. */
279
335
  replyToReport(reportId: string, body: string): Promise<MushiReporterComment | null>;
280
336
  /** Record a reporter feedback signal (e.g. `confirms`, `not_fixed`) on a report. Returns the outcome or null. */
@@ -328,7 +384,9 @@ declare function useMushiWidget(): {
328
384
  *
329
385
  * OVERVIEW:
330
386
  * - Slide-up modal built entirely on RN built-ins (Modal, Animated, PanResponder)
331
- * - Conversational flow: category → description → submit → confirmation
387
+ * - One screen, free text first: optional type chips, Send once there are a
388
+ * few words (8 by default) or a screenshot, then a receipt in place with
389
+ * Track it / Done and an optional, never pre-ticked email opt-in
332
390
  * - Drag-to-dismiss via PanResponder on the handle area
333
391
  * - Host-adaptive theme (`widget.theme`, see ../theme.ts) over light/dark
334
392
  * - "Your reports": statuses come from the shared core table
@@ -345,13 +403,17 @@ declare function useMushiWidget(): {
345
403
  * TECHNICAL DETAILS:
346
404
  * - PanResponder threshold: 80 px downward drag dismisses
347
405
  * - Animated.spring for slide-up, Animated.timing for backdrop
348
- * - Success confirmation auto-closes after 1.4 s
349
- * - Thread loads show a skeleton, then Retry on failure; a failed reply keeps
350
- * its text and offers Retry. Opening a thread marks it read.
406
+ * - Reduce Motion (AccessibilityInfo) makes open / close instant
407
+ * - The thread is the report's v2 timeline (GET /v1/reporter/reports/:id):
408
+ * pipeline events render from the shared core templates in the reporter's
409
+ * locale, replies as bubbles. Loads show a skeleton, then Retry on failure;
410
+ * a failed reply keeps its text and offers Retry. Opening a thread marks it
411
+ * read. An older server without the route falls back to the comment list.
351
412
  *
352
413
  * NOTES:
353
414
  * - KeyboardAvoidingView wraps the sheet so the text input stays visible
354
- * - Categories match the web SDK: bug, slow, visual, confusing, other
415
+ * - Chips come from core's REPORTER_CATEGORIES (bug, slow, visual, confusing,
416
+ * idea); "Idea" files a feature request
355
417
  * - accessibilityViewIsModal is iOS-only; RN's Modal is its own window on
356
418
  * Android, which keeps TalkBack focus inside the sheet there.
357
419
  */
@@ -379,6 +441,10 @@ interface MushiBottomSheetProps {
379
441
  inboxPollIntervalMs?: number;
380
442
  /** Theme tokens (`widget.theme`); unset tokens use the neutral defaults. */
381
443
  theme?: Partial<MushiRNTheme>;
444
+ /** Characters needed before Send enables (`widget.minDescriptionLength`, default 8). */
445
+ minDescriptionLength?: number;
446
+ /** Offer "Get updates by email" on the receipt when the project offers email (`notifications.email`). */
447
+ emailOptIn?: boolean;
382
448
  }
383
449
  declare const MushiBottomSheet: FC<MushiBottomSheetProps>;
384
450
 
@@ -502,4 +568,46 @@ declare class AsyncStorageQueue {
502
568
  private getAsyncStorage;
503
569
  }
504
570
 
505
- export { AsyncStorageQueue, type ConsoleEntry, type DeviceInfo, MUSHI_BANNER_DEFAULT_HEIGHT, MushiBanner, type MushiBannerProps, MushiBottomSheet, type MushiBottomSheetProps, MushiFloatingButton, type MushiFloatingButtonProps, MushiProvider, type MushiRNConfig, type MushiRNInstance, MushiTrigger, type MushiTriggerProps, type NavigationEntry, type NetworkEntry, type RNAnalyticsConfig, getDeviceInfo, setupConsoleCapture, setupNetworkCapture, useMushi, useMushiReport, useMushiWidget, useNavigationCapture };
571
+ /**
572
+ * FILE: optional-modules.ts
573
+ * PURPOSE: The SDK's three optional native peers (network-aware delivery,
574
+ * screenshots, shake-to-report), loaded without crashing the app.
575
+ *
576
+ * Order for each one:
577
+ * 1. A module the host passed in config (`netInfo`, `viewShot`, `expoSensors`).
578
+ * No dynamic loading at all — the safest path.
579
+ * 2. A literal `require('<module>')` inside try/catch. Metro resolves a literal
580
+ * require at bundle time and treats one inside try/catch as optional
581
+ * (`transformer.allowOptionalDependencies`, on in Expo and React Native's
582
+ * default Metro config).
583
+ *
584
+ * Why the build matters: esbuild's ESM output rewrites `require('x')` to its
585
+ * `__require('x')` interop shim. Metro can't resolve a module name handed to
586
+ * the shim, so it called its own require with a string at runtime and crashed
587
+ * the app (reportFatalError) — the try/catch never saw it (0.21–0.23).
588
+ * tsup.config.ts restores literal `require(...)` in dist and fails the build
589
+ * if any `__require(` is left (src/bundling/preserve-optional-requires.ts).
590
+ */
591
+ interface MushiNetInfoModule {
592
+ addEventListener(listener: (state: {
593
+ isConnected: boolean | null;
594
+ isInternetReachable: boolean | null;
595
+ }) => void): () => void;
596
+ }
597
+ interface MushiViewShotModule {
598
+ captureScreen(options: Record<string, unknown>): Promise<string>;
599
+ }
600
+ interface MushiExpoSensorsModule {
601
+ Accelerometer: {
602
+ setUpdateInterval(ms: number): void;
603
+ addListener(listener: (event: {
604
+ x: number;
605
+ y: number;
606
+ z: number;
607
+ }) => void): {
608
+ remove(): void;
609
+ };
610
+ };
611
+ }
612
+
613
+ export { AsyncStorageQueue, type ConsoleEntry, type DeviceInfo, MUSHI_BANNER_DEFAULT_HEIGHT, MushiBanner, type MushiBannerProps, MushiBottomSheet, type MushiBottomSheetProps, type MushiExpoSensorsModule, MushiFloatingButton, type MushiFloatingButtonProps, type MushiNetInfoModule, MushiProvider, type MushiRNConfig, type MushiRNInstance, MushiTrigger, type MushiTriggerProps, type MushiViewShotModule, type NavigationEntry, type NetworkEntry, type RNAnalyticsConfig, getDeviceInfo, setupConsoleCapture, setupNetworkCapture, useMushi, useMushiReport, useMushiWidget, useNavigationCapture };