@mushi-mushi/core 1.20.2 → 1.22.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
@@ -2,6 +2,22 @@ interface MushiConfig {
2
2
  projectId: string;
3
3
  apiKey: string;
4
4
  apiEndpoint?: string;
5
+ /** Per-request timeout in ms (default 10000). Raise on slow mobile networks. */
6
+ timeout?: number;
7
+ /** Max retries for transient (network / 5xx) failures (default 2). */
8
+ maxRetries?: number;
9
+ /**
10
+ * Endpoint circuit breaker. After `threshold` consecutive unreachable
11
+ * failures the client fast-fails for `cooldownMs` (then half-opens) instead
12
+ * of hammering a down endpoint; fast-failed reports still hit the offline
13
+ * queue. Set `enabled: false` to opt out. Defaults: enabled, threshold 4,
14
+ * cooldown 30000ms.
15
+ */
16
+ circuitBreaker?: {
17
+ enabled?: boolean;
18
+ threshold?: number;
19
+ cooldownMs?: number;
20
+ };
5
21
  /** Opinionated defaults for common environments. Explicit config wins. */
6
22
  preset?: MushiPreset;
7
23
  /**
@@ -23,6 +39,13 @@ interface MushiConfig {
23
39
  assistant?: MushiAssistantConfig;
24
40
  debug?: boolean;
25
41
  enabled?: boolean;
42
+ /**
43
+ * Host app release identifier stored on `reports.app_version` at ingest.
44
+ * Pairs with `environment.buildId` (from `<meta name="mushi:build">`) for
45
+ * deploy-level provenance. Falls back to `integrations.vercel.analyticsId`
46
+ * when omitted (legacy Vercel Analytics wiring).
47
+ */
48
+ appVersion?: string;
26
49
  /** Hook called before a report is sent. Return null to cancel, or return the (possibly modified) report. */
27
50
  beforeSendFeedback?: (report: MushiReport) => MushiReport | null | Promise<MushiReport | null>;
28
51
  /** Called once if the app crashed during the previous session. */
@@ -851,6 +874,16 @@ interface MushiEnvironment {
851
874
  */
852
875
  route?: string;
853
876
  nearestTestid?: string;
877
+ /**
878
+ * Native-shell detection (best-effort, present only when a native bridge is
879
+ * detected). Lets triage distinguish a Capacitor/Cordova/React-Native WebView
880
+ * report from a plain browser one, and lets the SDK gate DOM-only behaviour.
881
+ */
882
+ native?: {
883
+ capacitor?: boolean;
884
+ cordova?: boolean;
885
+ reactNative?: boolean;
886
+ };
854
887
  /**
855
888
  * SDK boost (2026-05-07): richer per-report context so the Triage LLM
856
889
  * and the admin /reports detail drawer have something to reason about
@@ -1504,6 +1537,8 @@ interface MushiRuntimeSdkConfig {
1504
1537
  triggerMode?: 'shake' | 'button' | 'both' | 'none';
1505
1538
  minDescriptionLength?: number;
1506
1539
  };
1540
+ /** When false, the widget skips background reporter-inbox polling. Default true. */
1541
+ reporterNotificationsEnabled?: boolean;
1507
1542
  }
1508
1543
  interface MushiSdkVersionInfo {
1509
1544
  package: string;
@@ -1606,6 +1641,19 @@ interface ApiClientOptions {
1606
1641
  apiEndpoint?: string;
1607
1642
  timeout?: number;
1608
1643
  maxRetries?: number;
1644
+ /**
1645
+ * Circuit breaker for the endpoint. After `threshold` consecutive
1646
+ * unreachable failures (network errors / exhausted 5xx) the client
1647
+ * fast-fails for `cooldownMs` instead of hammering a down endpoint, then
1648
+ * half-opens (one trial request). Fast-failed requests return a transient
1649
+ * error so the offline queue still captures the report. Set
1650
+ * `enabled: false` to opt out. Defaults: enabled, threshold 4, cooldown 30s.
1651
+ */
1652
+ circuitBreaker?: {
1653
+ enabled?: boolean;
1654
+ threshold?: number;
1655
+ cooldownMs?: number;
1656
+ };
1609
1657
  /** When set, sent on every request so heartbeats record the running SDK version. */
1610
1658
  sdkPackage?: string;
1611
1659
  sdkVersion?: string;
@@ -1620,6 +1668,8 @@ declare const DEFAULT_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/f
1620
1668
  declare const MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
1621
1669
  declare const MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
1622
1670
  type MushiInternalRequestKind = 'sdk-config' | 'report-submit' | 'report-status' | 'reporter-poll' | 'diagnose' | 'discovery' | 'community';
1671
+ declare const DEFAULT_TIMEOUT = 10000;
1672
+ declare const DEFAULT_MAX_RETRIES = 2;
1623
1673
  declare function createApiClient(options: ApiClientOptions): MushiApiClient;
1624
1674
 
1625
1675
  /**
@@ -1730,7 +1780,59 @@ declare function createOfflineQueue(config?: MushiOfflineConfig): OfflineQueue;
1730
1780
  */
1731
1781
  declare function captureEnvironment(): MushiEnvironment;
1732
1782
 
1733
- declare function getReporterToken(): string;
1783
+ /**
1784
+ * FILE: reporter-token.ts
1785
+ * PURPOSE: Stable, project-scoped anonymous reporter identity for the My Reports inbox.
1786
+ *
1787
+ * OVERVIEW:
1788
+ * - Each Mushi project gets its own localStorage key so multi-project hosts on the
1789
+ * same origin (e.g. kensaur.us/glot-it vs /other-app) never share a token.
1790
+ * - One-time migration copies the legacy global `mushi_reporter_token` into the
1791
+ * first projectId requested, preserving existing inbox history for that project.
1792
+ *
1793
+ * USAGE:
1794
+ * - `getReporterToken(projectId)` from web/RN/Capacitor SDK before submit or inbox calls.
1795
+ */
1796
+ /**
1797
+ * Return a stable reporter token scoped to `projectId`.
1798
+ * Legacy callers without a projectId still work but should migrate — the global
1799
+ * key is read once and re-homed into the namespaced slot.
1800
+ */
1801
+ declare function getReporterToken(projectId?: string): string;
1802
+
1803
+ /**
1804
+ * FILE: packages/core/src/digest.ts
1805
+ * PURPOSE: SHA-256 and HMAC-SHA-256 helpers that work in every JS runtime —
1806
+ * including Hermes (React Native) which has no global `crypto` object.
1807
+ *
1808
+ * OVERVIEW:
1809
+ * Fast path: when `globalThis.crypto?.subtle` is available (browser, Deno,
1810
+ * Bun, Node ≥ 20 where Web Crypto is exposed globally, React Native with a
1811
+ * crypto polyfill) we delegate to the native Web Crypto API which is
1812
+ * hardware-accelerated and produces identical output.
1813
+ *
1814
+ * Fallback: `@noble/hashes` — pure-JS, audited, zero-dependency implementation
1815
+ * of SHA-256 and HMAC used when native crypto is absent (Hermes cold start
1816
+ * before any polyfill loads, worker environments without crypto, SSR edge runtimes).
1817
+ *
1818
+ * Both paths are spec-identical (same test vectors) and are exercised by
1819
+ * `digest.test.ts`.
1820
+ *
1821
+ * USAGE:
1822
+ * import { sha256Hex, hmacSha256Hex } from './digest';
1823
+ * const hash = await sha256Hex('hello');
1824
+ * const sig = await hmacSha256Hex('secret', 'message');
1825
+ */
1826
+ /**
1827
+ * SHA-256 of `value`, returned as a lowercase hex string.
1828
+ * Uses Web Crypto when available, falls back to @noble/hashes.
1829
+ */
1830
+ declare function sha256Hex(value: string): Promise<string>;
1831
+ /**
1832
+ * HMAC-SHA-256 of `value` with `secret`, returned as a lowercase hex string.
1833
+ * Uses Web Crypto when available, falls back to @noble/hashes.
1834
+ */
1835
+ declare function hmacSha256Hex(secret: string, value: string): Promise<string>;
1734
1836
 
1735
1837
  /**
1736
1838
  * RFC-4122 v4 UUID generator with a capability ladder so it works in every
@@ -1996,8 +2098,8 @@ declare const noopLogger: Logger;
1996
2098
  *
1997
2099
  * Colour values mirror the historical washi/vermillion palette previously
1998
2100
  * inlined in `@mushi-mushi/web`'s styles.ts so the visual identity is
1999
- * unchanged; the difference is that RN and Capacitor now share the exact
2000
- * same constants instead of re-deriving their own.
2101
+ * unchanged; `@mushi-mushi/web` imports mushiPalette() + MUSHI_* here
2102
+ * instead of duplicating hex literals.
2001
2103
  */
2002
2104
  type MushiThemeMode = 'light' | 'dark';
2003
2105
  interface MushiColorPalette {
@@ -2032,6 +2134,41 @@ interface MushiColorPalette {
2032
2134
  declare const MUSHI_COLORS_LIGHT: MushiColorPalette;
2033
2135
  /** Dark-mode palette. */
2034
2136
  declare const MUSHI_COLORS_DARK: MushiColorPalette;
2137
+ /** Reward tier accent colours — editorial palette, not Tailwind defaults. */
2138
+ declare const MUSHI_TIER_COLORS: {
2139
+ readonly free: string;
2140
+ readonly explorer: "#2563EB";
2141
+ readonly contributor: "#7C3AED";
2142
+ readonly champion: "#D97706";
2143
+ readonly default: string;
2144
+ };
2145
+ /** Neon beta banner — web `.mushi-banner.neon` + RN sheet header parity. */
2146
+ declare const MUSHI_BANNER_NEON: {
2147
+ readonly bg: "#0FFF50";
2148
+ readonly fg: "#0a1a0a";
2149
+ readonly border: "#00C43A";
2150
+ };
2151
+ /** On-accent button text (hanko stamp, submit CTA). */
2152
+ declare const MUSHI_ON_ACCENT = "#FAF7F0";
2153
+ /** Pure white for assistant bubbles on accent backgrounds. */
2154
+ declare const MUSHI_INVERSE = "#ffffff";
2155
+ /** Submit-button depth shadow (accent ink, mode-specific). */
2156
+ declare const MUSHI_ACCENT_SHADOW: {
2157
+ readonly light: "#9A2A1E";
2158
+ readonly dark: "#7A1F15";
2159
+ };
2160
+ /** Brand banner border under vermillion strip. */
2161
+ declare const MUSHI_BANNER_BRAND_BORDER: {
2162
+ readonly light: "#B52F1F";
2163
+ readonly dark: "#C4321E";
2164
+ };
2165
+ /** Reporter inbox status chip colours (fg / bg / border). */
2166
+ interface MushiReporterStatusTone {
2167
+ fg: string;
2168
+ bg: string;
2169
+ border: string;
2170
+ }
2171
+ declare const MUSHI_REPORTER_STATUS: Record<MushiThemeMode, Record<'sent' | 'review' | 'fixing' | 'fixed', MushiReporterStatusTone>>;
2035
2172
  /** Resolve the palette for a theme mode. */
2036
2173
  declare function mushiPalette(mode: MushiThemeMode): MushiColorPalette;
2037
2174
  /**
@@ -2093,20 +2230,35 @@ declare const MUSHI_MOTION: {
2093
2230
  declare const MUSHI_GEOMETRY: {
2094
2231
  readonly bannerHeight: 36;
2095
2232
  readonly fabSize: 52;
2096
- readonly edgeTabWidth: 28;
2233
+ /** edge-tab launcher width (px) */
2234
+ readonly edgeTabWidth: 32;
2097
2235
  /** default gutter from the screen edge (added on top of safe-area insets) */
2098
2236
  readonly gutter: 24;
2099
- readonly panelWidth: 384;
2237
+ /** Web panel width (px) — matches shipped Shadow DOM widget */
2238
+ readonly panelWidth: 360;
2239
+ /** max panel height before keyboard inset (px) */
2240
+ readonly panelMaxHeight: 480;
2100
2241
  /** below this viewport width the panel becomes a full-width bottom sheet */
2101
2242
  readonly panelSheetBreakpoint: 480;
2102
2243
  };
2244
+ /** Safe hex validator for user-supplied accent overrides (Shadow DOM CSS injection guard). */
2245
+ declare function safeWidgetHex(v: string): string;
2246
+ /**
2247
+ * Resolve widget accent colours, honouring optional host overrides while
2248
+ * falling back to the canonical palette from mushiPalette().
2249
+ */
2250
+ declare function resolveWidgetAccent(mode: MushiThemeMode, accent?: string, accentText?: string): {
2251
+ accent: string;
2252
+ accentWash: string;
2253
+ accentInk: string;
2254
+ };
2103
2255
  /**
2104
2256
  * Default user-facing copy. Centralised so apps stop drifting on the banner
2105
2257
  * label / CTA wording (seen as inconsistent across the four host apps).
2106
2258
  */
2107
2259
  declare const MUSHI_COPY: {
2108
2260
  readonly bannerLabel: "Beta";
2109
- readonly bannerMessage: "Help us improve — your feedback shapes what we ship.";
2261
+ readonly bannerMessage: "Found a bug? Tap to report it.";
2110
2262
  readonly bugCta: "Report a bug";
2111
2263
  readonly featureCta: "Feature request";
2112
2264
  readonly triggerText: "🐛";
@@ -2233,4 +2385,4 @@ declare function projectInitialsThemeIndex(projectId: string): number;
2233
2385
  */
2234
2386
  declare function readPageFaviconHref(): string | null;
2235
2387
 
2236
- export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_MOTION, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type MushiBetaChangelogEntry, type MushiBetaModeConfig, type MushiBreadcrumb, type MushiCaptureConfig, type MushiCaptureEventInput, type MushiCaptureExceptionOptions, type MushiColorPalette, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiCrossAppReport, type MushiCustomCategory, type MushiDiagnosticsResult, type MushiDiscoverInventoryConfig, type MushiDiscoveryEventPayload, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiHallOfFameEntry, type MushiIdentityClaims, type MushiIntegrationsConfig, type MushiInternalRequestKind, type MushiLeaderboardEntry, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPageContext, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiPreset, type MushiPrivacyConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiReporterComment, type MushiReporterReport, type MushiReputationResult, type MushiRewardsConfig, type MushiRuntimeSdkConfig, type MushiSDKInstance, type MushiSdkVersionInfo, type MushiSelectedElement, type MushiSentryConfig, type MushiSentryContext, type MushiTesterReputation, type MushiThemeMode, type MushiTierResult, type MushiTimelineEntry, type MushiTimelineKind, type MushiTokenSnapshot, type MushiTracePropagationConfig, type MushiUrlMatcher, type MushiWidgetAnchor, type MushiWidgetConfig, type NormalisedException, type OfflineQueue, type PayloadGuardResult, type PiiScrubberConfig, type PreFilterResult, type ProjectFaviconSource, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, scrubPii };
2388
+ export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type MushiBetaChangelogEntry, type MushiBetaModeConfig, type MushiBreadcrumb, type MushiCaptureConfig, type MushiCaptureEventInput, type MushiCaptureExceptionOptions, type MushiColorPalette, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiCrossAppReport, type MushiCustomCategory, type MushiDiagnosticsResult, type MushiDiscoverInventoryConfig, type MushiDiscoveryEventPayload, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiHallOfFameEntry, type MushiIdentityClaims, type MushiIntegrationsConfig, type MushiInternalRequestKind, type MushiLeaderboardEntry, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPageContext, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiPreset, type MushiPrivacyConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiReporterComment, type MushiReporterReport, type MushiReputationResult, type MushiRewardsConfig, type MushiRuntimeSdkConfig, type MushiSDKInstance, type MushiSdkVersionInfo, type MushiSelectedElement, type MushiSentryConfig, type MushiSentryContext, type MushiTesterReputation, type MushiThemeMode, type MushiTierResult, type MushiTimelineEntry, type MushiTimelineKind, type MushiTokenSnapshot, type MushiTracePropagationConfig, type MushiUrlMatcher, type MushiWidgetAnchor, type MushiWidgetConfig, type NormalisedException, type OfflineQueue, type PayloadGuardResult, type PiiScrubberConfig, type PreFilterResult, type ProjectFaviconSource, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, sha256Hex };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,22 @@ interface MushiConfig {
2
2
  projectId: string;
3
3
  apiKey: string;
4
4
  apiEndpoint?: string;
5
+ /** Per-request timeout in ms (default 10000). Raise on slow mobile networks. */
6
+ timeout?: number;
7
+ /** Max retries for transient (network / 5xx) failures (default 2). */
8
+ maxRetries?: number;
9
+ /**
10
+ * Endpoint circuit breaker. After `threshold` consecutive unreachable
11
+ * failures the client fast-fails for `cooldownMs` (then half-opens) instead
12
+ * of hammering a down endpoint; fast-failed reports still hit the offline
13
+ * queue. Set `enabled: false` to opt out. Defaults: enabled, threshold 4,
14
+ * cooldown 30000ms.
15
+ */
16
+ circuitBreaker?: {
17
+ enabled?: boolean;
18
+ threshold?: number;
19
+ cooldownMs?: number;
20
+ };
5
21
  /** Opinionated defaults for common environments. Explicit config wins. */
6
22
  preset?: MushiPreset;
7
23
  /**
@@ -23,6 +39,13 @@ interface MushiConfig {
23
39
  assistant?: MushiAssistantConfig;
24
40
  debug?: boolean;
25
41
  enabled?: boolean;
42
+ /**
43
+ * Host app release identifier stored on `reports.app_version` at ingest.
44
+ * Pairs with `environment.buildId` (from `<meta name="mushi:build">`) for
45
+ * deploy-level provenance. Falls back to `integrations.vercel.analyticsId`
46
+ * when omitted (legacy Vercel Analytics wiring).
47
+ */
48
+ appVersion?: string;
26
49
  /** Hook called before a report is sent. Return null to cancel, or return the (possibly modified) report. */
27
50
  beforeSendFeedback?: (report: MushiReport) => MushiReport | null | Promise<MushiReport | null>;
28
51
  /** Called once if the app crashed during the previous session. */
@@ -851,6 +874,16 @@ interface MushiEnvironment {
851
874
  */
852
875
  route?: string;
853
876
  nearestTestid?: string;
877
+ /**
878
+ * Native-shell detection (best-effort, present only when a native bridge is
879
+ * detected). Lets triage distinguish a Capacitor/Cordova/React-Native WebView
880
+ * report from a plain browser one, and lets the SDK gate DOM-only behaviour.
881
+ */
882
+ native?: {
883
+ capacitor?: boolean;
884
+ cordova?: boolean;
885
+ reactNative?: boolean;
886
+ };
854
887
  /**
855
888
  * SDK boost (2026-05-07): richer per-report context so the Triage LLM
856
889
  * and the admin /reports detail drawer have something to reason about
@@ -1504,6 +1537,8 @@ interface MushiRuntimeSdkConfig {
1504
1537
  triggerMode?: 'shake' | 'button' | 'both' | 'none';
1505
1538
  minDescriptionLength?: number;
1506
1539
  };
1540
+ /** When false, the widget skips background reporter-inbox polling. Default true. */
1541
+ reporterNotificationsEnabled?: boolean;
1507
1542
  }
1508
1543
  interface MushiSdkVersionInfo {
1509
1544
  package: string;
@@ -1606,6 +1641,19 @@ interface ApiClientOptions {
1606
1641
  apiEndpoint?: string;
1607
1642
  timeout?: number;
1608
1643
  maxRetries?: number;
1644
+ /**
1645
+ * Circuit breaker for the endpoint. After `threshold` consecutive
1646
+ * unreachable failures (network errors / exhausted 5xx) the client
1647
+ * fast-fails for `cooldownMs` instead of hammering a down endpoint, then
1648
+ * half-opens (one trial request). Fast-failed requests return a transient
1649
+ * error so the offline queue still captures the report. Set
1650
+ * `enabled: false` to opt out. Defaults: enabled, threshold 4, cooldown 30s.
1651
+ */
1652
+ circuitBreaker?: {
1653
+ enabled?: boolean;
1654
+ threshold?: number;
1655
+ cooldownMs?: number;
1656
+ };
1609
1657
  /** When set, sent on every request so heartbeats record the running SDK version. */
1610
1658
  sdkPackage?: string;
1611
1659
  sdkVersion?: string;
@@ -1620,6 +1668,8 @@ declare const DEFAULT_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/f
1620
1668
  declare const MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
1621
1669
  declare const MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
1622
1670
  type MushiInternalRequestKind = 'sdk-config' | 'report-submit' | 'report-status' | 'reporter-poll' | 'diagnose' | 'discovery' | 'community';
1671
+ declare const DEFAULT_TIMEOUT = 10000;
1672
+ declare const DEFAULT_MAX_RETRIES = 2;
1623
1673
  declare function createApiClient(options: ApiClientOptions): MushiApiClient;
1624
1674
 
1625
1675
  /**
@@ -1730,7 +1780,59 @@ declare function createOfflineQueue(config?: MushiOfflineConfig): OfflineQueue;
1730
1780
  */
1731
1781
  declare function captureEnvironment(): MushiEnvironment;
1732
1782
 
1733
- declare function getReporterToken(): string;
1783
+ /**
1784
+ * FILE: reporter-token.ts
1785
+ * PURPOSE: Stable, project-scoped anonymous reporter identity for the My Reports inbox.
1786
+ *
1787
+ * OVERVIEW:
1788
+ * - Each Mushi project gets its own localStorage key so multi-project hosts on the
1789
+ * same origin (e.g. kensaur.us/glot-it vs /other-app) never share a token.
1790
+ * - One-time migration copies the legacy global `mushi_reporter_token` into the
1791
+ * first projectId requested, preserving existing inbox history for that project.
1792
+ *
1793
+ * USAGE:
1794
+ * - `getReporterToken(projectId)` from web/RN/Capacitor SDK before submit or inbox calls.
1795
+ */
1796
+ /**
1797
+ * Return a stable reporter token scoped to `projectId`.
1798
+ * Legacy callers without a projectId still work but should migrate — the global
1799
+ * key is read once and re-homed into the namespaced slot.
1800
+ */
1801
+ declare function getReporterToken(projectId?: string): string;
1802
+
1803
+ /**
1804
+ * FILE: packages/core/src/digest.ts
1805
+ * PURPOSE: SHA-256 and HMAC-SHA-256 helpers that work in every JS runtime —
1806
+ * including Hermes (React Native) which has no global `crypto` object.
1807
+ *
1808
+ * OVERVIEW:
1809
+ * Fast path: when `globalThis.crypto?.subtle` is available (browser, Deno,
1810
+ * Bun, Node ≥ 20 where Web Crypto is exposed globally, React Native with a
1811
+ * crypto polyfill) we delegate to the native Web Crypto API which is
1812
+ * hardware-accelerated and produces identical output.
1813
+ *
1814
+ * Fallback: `@noble/hashes` — pure-JS, audited, zero-dependency implementation
1815
+ * of SHA-256 and HMAC used when native crypto is absent (Hermes cold start
1816
+ * before any polyfill loads, worker environments without crypto, SSR edge runtimes).
1817
+ *
1818
+ * Both paths are spec-identical (same test vectors) and are exercised by
1819
+ * `digest.test.ts`.
1820
+ *
1821
+ * USAGE:
1822
+ * import { sha256Hex, hmacSha256Hex } from './digest';
1823
+ * const hash = await sha256Hex('hello');
1824
+ * const sig = await hmacSha256Hex('secret', 'message');
1825
+ */
1826
+ /**
1827
+ * SHA-256 of `value`, returned as a lowercase hex string.
1828
+ * Uses Web Crypto when available, falls back to @noble/hashes.
1829
+ */
1830
+ declare function sha256Hex(value: string): Promise<string>;
1831
+ /**
1832
+ * HMAC-SHA-256 of `value` with `secret`, returned as a lowercase hex string.
1833
+ * Uses Web Crypto when available, falls back to @noble/hashes.
1834
+ */
1835
+ declare function hmacSha256Hex(secret: string, value: string): Promise<string>;
1734
1836
 
1735
1837
  /**
1736
1838
  * RFC-4122 v4 UUID generator with a capability ladder so it works in every
@@ -1996,8 +2098,8 @@ declare const noopLogger: Logger;
1996
2098
  *
1997
2099
  * Colour values mirror the historical washi/vermillion palette previously
1998
2100
  * inlined in `@mushi-mushi/web`'s styles.ts so the visual identity is
1999
- * unchanged; the difference is that RN and Capacitor now share the exact
2000
- * same constants instead of re-deriving their own.
2101
+ * unchanged; `@mushi-mushi/web` imports mushiPalette() + MUSHI_* here
2102
+ * instead of duplicating hex literals.
2001
2103
  */
2002
2104
  type MushiThemeMode = 'light' | 'dark';
2003
2105
  interface MushiColorPalette {
@@ -2032,6 +2134,41 @@ interface MushiColorPalette {
2032
2134
  declare const MUSHI_COLORS_LIGHT: MushiColorPalette;
2033
2135
  /** Dark-mode palette. */
2034
2136
  declare const MUSHI_COLORS_DARK: MushiColorPalette;
2137
+ /** Reward tier accent colours — editorial palette, not Tailwind defaults. */
2138
+ declare const MUSHI_TIER_COLORS: {
2139
+ readonly free: string;
2140
+ readonly explorer: "#2563EB";
2141
+ readonly contributor: "#7C3AED";
2142
+ readonly champion: "#D97706";
2143
+ readonly default: string;
2144
+ };
2145
+ /** Neon beta banner — web `.mushi-banner.neon` + RN sheet header parity. */
2146
+ declare const MUSHI_BANNER_NEON: {
2147
+ readonly bg: "#0FFF50";
2148
+ readonly fg: "#0a1a0a";
2149
+ readonly border: "#00C43A";
2150
+ };
2151
+ /** On-accent button text (hanko stamp, submit CTA). */
2152
+ declare const MUSHI_ON_ACCENT = "#FAF7F0";
2153
+ /** Pure white for assistant bubbles on accent backgrounds. */
2154
+ declare const MUSHI_INVERSE = "#ffffff";
2155
+ /** Submit-button depth shadow (accent ink, mode-specific). */
2156
+ declare const MUSHI_ACCENT_SHADOW: {
2157
+ readonly light: "#9A2A1E";
2158
+ readonly dark: "#7A1F15";
2159
+ };
2160
+ /** Brand banner border under vermillion strip. */
2161
+ declare const MUSHI_BANNER_BRAND_BORDER: {
2162
+ readonly light: "#B52F1F";
2163
+ readonly dark: "#C4321E";
2164
+ };
2165
+ /** Reporter inbox status chip colours (fg / bg / border). */
2166
+ interface MushiReporterStatusTone {
2167
+ fg: string;
2168
+ bg: string;
2169
+ border: string;
2170
+ }
2171
+ declare const MUSHI_REPORTER_STATUS: Record<MushiThemeMode, Record<'sent' | 'review' | 'fixing' | 'fixed', MushiReporterStatusTone>>;
2035
2172
  /** Resolve the palette for a theme mode. */
2036
2173
  declare function mushiPalette(mode: MushiThemeMode): MushiColorPalette;
2037
2174
  /**
@@ -2093,20 +2230,35 @@ declare const MUSHI_MOTION: {
2093
2230
  declare const MUSHI_GEOMETRY: {
2094
2231
  readonly bannerHeight: 36;
2095
2232
  readonly fabSize: 52;
2096
- readonly edgeTabWidth: 28;
2233
+ /** edge-tab launcher width (px) */
2234
+ readonly edgeTabWidth: 32;
2097
2235
  /** default gutter from the screen edge (added on top of safe-area insets) */
2098
2236
  readonly gutter: 24;
2099
- readonly panelWidth: 384;
2237
+ /** Web panel width (px) — matches shipped Shadow DOM widget */
2238
+ readonly panelWidth: 360;
2239
+ /** max panel height before keyboard inset (px) */
2240
+ readonly panelMaxHeight: 480;
2100
2241
  /** below this viewport width the panel becomes a full-width bottom sheet */
2101
2242
  readonly panelSheetBreakpoint: 480;
2102
2243
  };
2244
+ /** Safe hex validator for user-supplied accent overrides (Shadow DOM CSS injection guard). */
2245
+ declare function safeWidgetHex(v: string): string;
2246
+ /**
2247
+ * Resolve widget accent colours, honouring optional host overrides while
2248
+ * falling back to the canonical palette from mushiPalette().
2249
+ */
2250
+ declare function resolveWidgetAccent(mode: MushiThemeMode, accent?: string, accentText?: string): {
2251
+ accent: string;
2252
+ accentWash: string;
2253
+ accentInk: string;
2254
+ };
2103
2255
  /**
2104
2256
  * Default user-facing copy. Centralised so apps stop drifting on the banner
2105
2257
  * label / CTA wording (seen as inconsistent across the four host apps).
2106
2258
  */
2107
2259
  declare const MUSHI_COPY: {
2108
2260
  readonly bannerLabel: "Beta";
2109
- readonly bannerMessage: "Help us improve — your feedback shapes what we ship.";
2261
+ readonly bannerMessage: "Found a bug? Tap to report it.";
2110
2262
  readonly bugCta: "Report a bug";
2111
2263
  readonly featureCta: "Feature request";
2112
2264
  readonly triggerText: "🐛";
@@ -2233,4 +2385,4 @@ declare function projectInitialsThemeIndex(projectId: string): number;
2233
2385
  */
2234
2386
  declare function readPageFaviconHref(): string | null;
2235
2387
 
2236
- export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_MOTION, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type MushiBetaChangelogEntry, type MushiBetaModeConfig, type MushiBreadcrumb, type MushiCaptureConfig, type MushiCaptureEventInput, type MushiCaptureExceptionOptions, type MushiColorPalette, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiCrossAppReport, type MushiCustomCategory, type MushiDiagnosticsResult, type MushiDiscoverInventoryConfig, type MushiDiscoveryEventPayload, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiHallOfFameEntry, type MushiIdentityClaims, type MushiIntegrationsConfig, type MushiInternalRequestKind, type MushiLeaderboardEntry, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPageContext, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiPreset, type MushiPrivacyConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiReporterComment, type MushiReporterReport, type MushiReputationResult, type MushiRewardsConfig, type MushiRuntimeSdkConfig, type MushiSDKInstance, type MushiSdkVersionInfo, type MushiSelectedElement, type MushiSentryConfig, type MushiSentryContext, type MushiTesterReputation, type MushiThemeMode, type MushiTierResult, type MushiTimelineEntry, type MushiTimelineKind, type MushiTokenSnapshot, type MushiTracePropagationConfig, type MushiUrlMatcher, type MushiWidgetAnchor, type MushiWidgetConfig, type NormalisedException, type OfflineQueue, type PayloadGuardResult, type PiiScrubberConfig, type PreFilterResult, type ProjectFaviconSource, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, scrubPii };
2388
+ export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type MushiBetaChangelogEntry, type MushiBetaModeConfig, type MushiBreadcrumb, type MushiCaptureConfig, type MushiCaptureEventInput, type MushiCaptureExceptionOptions, type MushiColorPalette, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiCrossAppReport, type MushiCustomCategory, type MushiDiagnosticsResult, type MushiDiscoverInventoryConfig, type MushiDiscoveryEventPayload, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiHallOfFameEntry, type MushiIdentityClaims, type MushiIntegrationsConfig, type MushiInternalRequestKind, type MushiLeaderboardEntry, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPageContext, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiPreset, type MushiPrivacyConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiReporterComment, type MushiReporterReport, type MushiReputationResult, type MushiRewardsConfig, type MushiRuntimeSdkConfig, type MushiSDKInstance, type MushiSdkVersionInfo, type MushiSelectedElement, type MushiSentryConfig, type MushiSentryContext, type MushiTesterReputation, type MushiThemeMode, type MushiTierResult, type MushiTimelineEntry, type MushiTimelineKind, type MushiTokenSnapshot, type MushiTracePropagationConfig, type MushiUrlMatcher, type MushiWidgetAnchor, type MushiWidgetConfig, type NormalisedException, type OfflineQueue, type PayloadGuardResult, type PiiScrubberConfig, type PreFilterResult, type ProjectFaviconSource, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, sha256Hex };