@mushi-mushi/core 1.30.0 → 1.31.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.ts CHANGED
@@ -1,1888 +1,5 @@
1
- interface MushiConfig {
2
- projectId: string;
3
- apiKey: string;
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
- };
21
- /** Opinionated defaults for common environments. Explicit config wins. */
22
- preset?: MushiPreset;
23
- /**
24
- * Fetch non-secret widget/capture settings from the Mushi project at
25
- * startup. Defaults to true so console changes apply without rebuilding
26
- * host apps. Set false for fully static/offline deployments.
27
- */
28
- runtimeConfig?: boolean | 'auto';
29
- /**
30
- * Product analytics (`Mushi.track()`, Users & Funnels). Enabled by default
31
- * and keyed on the same opaque per-project reporter token as sessions;
32
- * honours DNT / GPC. Set `enabled: false` to opt out, or
33
- * `consent: 'required'` to buffer until `setConsent('granted')`.
34
- * Session tracking passes the same gate: `enabled`, DNT / GPC, bot
35
- * exclusion and consent all apply to it too.
36
- */
37
- analytics?: MushiAnalyticsConfig;
38
- /**
39
- * Session lifecycle tracking for the console's Activity and Users views
40
- * (session start / heartbeat / end, page views). Default true. Runs only
41
- * while the `analytics` gate allows tracking; `false` turns it off even
42
- * then.
43
- */
44
- trackSessions?: boolean;
45
- sentry?: MushiSentryConfig;
46
- widget?: MushiWidgetConfig;
47
- capture?: MushiCaptureConfig;
48
- privacy?: MushiPrivacyConfig;
49
- proactive?: MushiProactiveConfig;
50
- preFilter?: MushiPreFilterConfig;
51
- integrations?: MushiIntegrationsConfig;
52
- offline?: MushiOfflineConfig;
53
- rewards?: MushiRewardsConfig;
54
- /** Page-aware, user-data-aware in-SDK assistant (P5). */
55
- assistant?: MushiAssistantConfig;
56
- debug?: boolean;
57
- enabled?: boolean;
58
- /**
59
- * Host app release identifier stored on `reports.app_version` at ingest.
60
- * Pairs with `environment.buildId` (from `<meta name="mushi:build">`) for
61
- * deploy-level provenance. Falls back to `integrations.vercel.analyticsId`
62
- * when omitted (legacy Vercel Analytics wiring).
63
- */
64
- appVersion?: string;
65
- /**
66
- * Same-origin (or absolute) ingest proxy. When set, every SDK HTTP call
67
- * goes here instead of `apiEndpoint` so ad blockers that drop third-party
68
- * `*.supabase.co/functions` hosts cannot silently eat reports.
69
- * Relative URLs resolve against the page origin — that is the recommended
70
- * form (no CORS preflight; matches Sentry `tunnel`).
71
- *
72
- * @example
73
- * tunnel: '/api/mushi-tunnel'
74
- */
75
- tunnel?: string;
76
- /**
77
- * Drop automatic error reports whose message matches any string (substring)
78
- * or RegExp. Never applied to user-submitted widget feedback.
79
- */
80
- ignoreErrors?: Array<string | RegExp>;
81
- /**
82
- * Drop automatic error reports whose script URL / stack filename matches.
83
- */
84
- denyUrls?: Array<string | RegExp>;
85
- /**
86
- * When set, drop automatic error reports unless the script URL matches
87
- * at least one entry.
88
- */
89
- allowUrls?: Array<string | RegExp>;
90
- /**
91
- * Probabilistic sampling rate for session-replay recording (rrweb/lite).
92
- * Range 0–1, default 1 (record all sessions). The sampling decision is made
93
- * once at session init — a sampled-out session never loads the rrweb chunk,
94
- * reducing bundle cost and CPU for excluded users.
95
- *
96
- * Independent of `sampleRate` (error reporting). A session can have replay
97
- * on but errors sampled, or vice versa.
98
- *
99
- * @example
100
- * replaySampleRate: 0.2 // record replay for ~20% of sessions
101
- */
102
- replaySampleRate?: number;
103
- /**
104
- * When session replay was sampled out, still start the rolling buffer for
105
- * this fraction of sessions (0–1, default 0) so an error/feedback report
106
- * can attach replay. Keep at 0 unless you have accepted the CPU/egress
107
- * cost — do not set to 1 with `capture.replay: 'rrweb'`.
108
- */
109
- replaysOnErrorSampleRate?: number;
110
- /**
111
- * Probabilistic sampling rate for automatic (non-user-initiated) error
112
- * reports. Range 0–1, default 1 (send all). User-initiated feedback reports
113
- * are always sent regardless of this value.
114
- *
115
- * Examples:
116
- * sampleRate: 0.1 → send ~10% of auto-captured errors
117
- * sampleRate: 1 → send all (default)
118
- * sampleRate: 0 → send none (disables automatic capture; feedback unaffected)
119
- *
120
- * When rate limiting or circuit breaker is also active, the stricter of the
121
- * two gates applies. Use sampleRate for sustained high-volume apps; use
122
- * rate limiting for burst protection.
123
- */
124
- sampleRate?: number;
125
- /**
126
- * Hook called before ANY report (error, exception, or user feedback) is
127
- * sent. Return null to cancel the report; return the (possibly modified)
128
- * report to proceed. Async version supported — resolution is awaited before
129
- * submission. Runs AFTER built-in PII scrubbing.
130
- *
131
- * @example
132
- * beforeSend: (report) => {
133
- * if (report.category === 'bug' && report.description.includes('internal')) return null
134
- * return { ...report, description: sanitize(report.description) }
135
- * }
136
- */
137
- beforeSend?: (report: MushiReport) => MushiReport | null | Promise<MushiReport | null>;
138
- /**
139
- * @deprecated Use `beforeSend` instead. `beforeSendFeedback` is kept for
140
- * backwards compatibility and applies only to user-submitted feedback reports.
141
- * `beforeSend` covers all report types and takes precedence when both are set.
142
- */
143
- beforeSendFeedback?: (report: MushiReport) => MushiReport | null | Promise<MushiReport | null>;
144
- /** Called once if the app crashed during the previous session. */
145
- onCrashedLastRun?: (crashed: boolean) => void;
146
- }
147
- interface MushiSentryConfig {
148
- dsn?: string;
149
- consumeUserFeedback?: boolean;
150
- enrichWithSeer?: boolean;
151
- useReplay?: boolean;
152
- }
153
- interface MushiWidgetConfig {
154
- position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
155
- /**
156
- * Raw CSS anchors for app shells with bottom navs/chat composers/cookie
157
- * banners. When set, these values win over `position` + numeric `inset`.
158
- */
159
- anchor?: MushiWidgetAnchor;
160
- theme?: 'auto' | 'light' | 'dark' | 'inherit';
161
- /**
162
- * Override the widget's primary accent colour (default: vermillion #E03C2C).
163
- * Must be a CSS colour value that has sufficient contrast against both light
164
- * and dark widget backgrounds. The widget derives a wash + accessible ink
165
- * colour automatically, so only the base colour is required.
166
- */
167
- accent?: string;
168
- /** Explicit text colour on the accent surface. Auto-computed when omitted. */
169
- accentText?: string;
170
- triggerText?: string;
171
- expandedTitle?: string;
172
- mode?: 'simple' | 'conversational';
173
- locale?: string;
174
- zIndex?: number;
175
- /**
176
- * Controls how, or whether, the default trigger is injected.
177
- * `auto` — historical floating stamp FAB.
178
- * `banner` — slim full-width header strip (recommended default; less obtrusive
179
- * than a FAB and visible even when the SDK launcher is `hide()`'d).
180
- * Pair with `bannerConfig` to customise appearance.
181
- */
182
- trigger?: 'auto' | 'banner' | 'edge-tab' | 'attach' | 'manual' | 'hidden';
183
- /**
184
- * Configuration for the header-banner launcher mode.
185
- * Only applies when `trigger === 'banner'`.
186
- */
187
- bannerConfig?: MushiBannerConfig;
188
- /** CSS selector used when `trigger` is `attach`. */
189
- attachToSelector?: string;
190
- /**
191
- * Per-edge trigger offset in pixels. `auto` clears the corresponding edge.
192
- * Defaults to the historical 24px gutter plus safe-area insets.
193
- */
194
- inset?: MushiWidgetInset;
195
- respectSafeArea?: boolean;
196
- /** Hide the launcher while any matching element exists in the document. */
197
- hideOnSelector?: string;
198
- /** Hide the launcher on matching pathnames. Strings are substring matches. */
199
- hideOnRoutes?: string[];
200
- environments?: Partial<Record<'production' | 'staging' | 'development', 'always' | 'never' | 'manual'>>;
201
- /** Opt-in smart trigger behavior; planned to become the default in a later minor. */
202
- smartHide?: boolean | MushiWidgetSmartHideConfig;
203
- /**
204
- * Allow the FAB to be dragged and repositioned by the user.
205
- * - `true` — drag enabled, persisted to localStorage, snaps to nearest edge on release.
206
- * - `false` — fixed position (default).
207
- * - Object — fine-grained control:
208
- * - `persist` save position per projectId (default true when draggable).
209
- * - `snapToEdge` snap to the nearest left/right edge on release (default true).
210
- * - `axis` constrain movement to one axis (`'x'`, `'y'`, or `'both'` default).
211
- */
212
- draggable?: boolean | {
213
- persist?: boolean;
214
- snapToEdge?: boolean;
215
- axis?: 'both' | 'x' | 'y';
216
- };
217
- /**
218
- * Show the "Bug reports by Mushi" mark at the bottom of the widget panel.
219
- * It links to the Mushi site (`utm_source=widget&utm_medium=powered-by` plus
220
- * an anonymous `ref` derived from a SHA-256 prefix of the project id) and
221
- * feeds the `loop_impression` / `loop_click` analytics events.
222
- *
223
- * Precedence (most specific wins):
224
- * 1. An explicit value here — the MIT SDK config is a hard override and
225
- * beats anything the runtime config sends.
226
- * 2. `widget.brandFooter` from the runtime config (`GET /v1/sdk/config`):
227
- * Mushi Cloud sends `true` for Free Cloud projects and `false` for paid
228
- * plans; self-hosted servers send nothing. Opt out with one toggle in the
229
- * console project settings.
230
- * 3. Default `false`.
231
- */
232
- brandFooter?: boolean;
233
- /**
234
- * How the widget surfaces the "update @mushi-mushi/web" notice. It is a
235
- * developer instruction, so `'auto'` (default) shows it in the widget only on
236
- * a dev host (localhost, loopback, `*.localhost`, `*.local`, `file:`) or with
237
- * `debug: true` — never to an app's end users. `'banner'` always shows it;
238
- * `'console-only'` and `'off'` never render it in the widget.
239
- */
240
- outdatedBanner?: 'auto' | 'banner' | 'console-only' | 'off';
241
- /**
242
- * Privacy nudge shown beside an attached screenshot preview, reminding the
243
- * reporter to remove anything sensitive (balances, PII, tokens) before they
244
- * submit. The widget always renders the captured image as a visible preview
245
- * so the user can see exactly what will be sent and remove it if needed; this
246
- * flag only controls the accompanying caption.
247
- * - `true` (default) — show the localized default caption.
248
- * - string — show this custom caption verbatim.
249
- * - `false` — hide the caption (the preview + remove control still show).
250
- *
251
- * Settable per-host via the SDK config and remotely via the Mushi console
252
- * runtime config (it travels in the `widget` block of `GET /v1/sdk/config`).
253
- */
254
- screenshotSensitiveHint?: boolean | string;
255
- /**
256
- * Beta mode: injects discreet "early access" messaging into the widget panel.
257
- * Shows a beta strip on the category step and a contact footer on the success
258
- * step. Designed to reduce user frustration with in-progress apps while
259
- * actively inviting feedback.
260
- */
261
- betaMode?: MushiBetaModeConfig;
262
- /**
263
- * Absolute base URL of the Mushi admin console (e.g. `https://mushi.example.com`).
264
- * When set, the success step surfaces a one-tap link to the user's own report
265
- * on the console so they can watch the status change in real time. Without
266
- * this the success step still confirms submission but cannot deep-link.
267
- *
268
- * This is intentionally separate from the API endpoint — production apps
269
- * usually have the API on `api.mushi.example.com` and the console on
270
- * `app.mushi.example.com`.
271
- */
272
- dashboardUrl?: string;
273
- /**
274
- * Override the SLA copy shown in the success step's "what happens next"
275
- * line. Defaults to "We aim to review within 48h". Set to an empty string
276
- * to hide the line entirely (e.g. internal-only deployments where SLA
277
- * messaging would be over-promising).
278
- */
279
- responseSlaLabel?: string;
280
- /**
281
- * Show a first-class "Feature request" card at the top of the category
282
- * step. Defaults to true. Set to false for production-only deployments
283
- * where you don't want to invite feature ideas through the widget.
284
- * Internally this maps to `category='other'` with
285
- * `user_category='Feature request'` so no DB migration is needed.
286
- */
287
- featureRequestCard?: boolean;
288
- /** Override the localised label for the feature-request card. */
289
- featureRequestLabel?: string;
290
- /** Override the helper text shown under the feature-request card. */
291
- featureRequestDescription?: string;
292
- /** Minimum description character count before the submit button enables. */
293
- minDescriptionLength?: number;
294
- /**
295
- * CSS selectors of host-app elements that the widget trigger and panel must
296
- * never visually overlap. At render time the widget queries each selector,
297
- * measures the union bounding rect, and nudges `--mushi-top` / `--mushi-bottom`
298
- * so the panel clears every avoided element by at least 8px.
299
- *
300
- * Typical use: avoid a sticky mobile header or a fixed sign-in CTA.
301
- *
302
- * @example
303
- * avoidSelectors: ['[data-mobile-header]', '#sign-in-cta']
304
- */
305
- avoidSelectors?: string[];
306
- /**
307
- * Override the default five-category picker with a custom category list.
308
- * When set, the widget renders these categories instead of the built-in
309
- * `bug / slow / visual / confusing / other` set.
310
- *
311
- * Each custom category maps onto one of the five built-in `MushiReportCategory`
312
- * values via `baseCategory` (defaults to `'other'`). The custom id is
313
- * preserved as `userCategory` on the report so the Mushi console can filter
314
- * by it independently of the LLM-assigned `category`.
315
- *
316
- * Deep-link helpers (`open`, `openWith`, `report`) accept the custom `id`
317
- * in addition to the built-in enum values when this option is set.
318
- *
319
- * When absent, behaviour is identical to the historical defaults (backward-compatible).
320
- */
321
- categories?: MushiCustomCategory[];
322
- }
323
- /**
324
- * Descriptor for a single entry in a host-app custom category list.
325
- * Passed as `widget.categories` to `Mushi.init()`.
326
- */
327
- interface MushiCustomCategory {
328
- /** Unique identifier used in `openWith(id)` / `report({ category: id })`. */
329
- id: string;
330
- /** Human-readable label shown in the category picker step. */
331
- label: string;
332
- /** Optional helper text shown beneath the label. */
333
- description?: string;
334
- /**
335
- * Localised intent options displayed on the second step ("What happened?").
336
- * When omitted, the widget skips the intent step and goes straight to
337
- * the description.
338
- */
339
- intents?: string[];
340
- /**
341
- * Emoji or single-character icon rendered next to the label in the picker.
342
- * Falls back to a neutral bubble when absent.
343
- */
344
- icon?: string;
345
- /**
346
- * Which built-in `MushiReportCategory` value this custom category maps to
347
- * for server-side classification. Defaults to `'other'`.
348
- * The custom `id` is always preserved in `report.userCategory`.
349
- */
350
- baseCategory?: MushiReportCategory;
351
- }
352
- /** Optional flat link in the rich banner action row (admin-console BetaBanner style). */
353
- interface MushiBannerLink {
354
- /** Link label shown in the action row. */
355
- label: string;
356
- /** External URL — opens in a new tab when set. */
357
- href?: string;
358
- /** When `href` is absent, opens the widget in feature-request mode. */
359
- featureRequest?: boolean;
360
- }
361
- /**
362
- * Configuration for the `trigger: 'banner'` header-strip launcher.
363
- *
364
- * The banner renders as a slim, full-width strip pinned to the top of the
365
- * viewport (or bottom if `position === 'bottom'`). It is styled to match the
366
- * app's brand accent and dismissed per-session via a ✕ button.
367
- *
368
- * Variants
369
- * --------
370
- * `neon` — lime / electric-green strip (high contrast, dev / beta tool feel).
371
- * `brand` — uses the Mushi vermillion accent (editorial, app-quality feel).
372
- * `subtle` — near-invisible hairline with muted text (least disruptive).
373
- */
374
- interface MushiBannerConfig {
375
- /** Visual style of the banner strip. Defaults to `'brand'`. */
376
- variant?: 'neon' | 'brand' | 'subtle';
377
- /** 'top' pins the banner below any existing sticky headers; 'bottom' pins above bottom navs. Defaults to 'top'. */
378
- position?: 'top' | 'bottom';
379
- /**
380
- * Body copy on the strip — the lime "Beta" announcement line users see in
381
- * the Mushi admin console. When set, the banner switches to the rich layout
382
- * (pill + message + flat text actions) instead of button-only CTAs.
383
- */
384
- message?: string;
385
- /**
386
- * Pill label shown before `message` (e.g. "Beta"). Defaults to `"Beta"` when
387
- * `message` is set. Pass `false` to hide the pill.
388
- */
389
- label?: string | false;
390
- /** Override the call-to-action text in the banner. Defaults to '🐛 Report a bug'. */
391
- bugCta?: string;
392
- /** Show a "Request a feature" button alongside the bug button. Defaults to true. */
393
- featureCta?: boolean;
394
- /** Override the feature-request button label. */
395
- featureCtaLabel?: string;
396
- /** Extra flat links after the bug/feature CTAs (e.g. "My submissions"). */
397
- links?: MushiBannerLink[];
398
- /** CSS z-index of the banner element. Defaults to the widget's configured zIndex. */
399
- zIndex?: number;
400
- }
401
- interface MushiBetaModeConfig {
402
- enabled?: boolean;
403
- /** Display name of the app shown in the beta strip. Defaults to 'This app'. */
404
- appName?: string;
405
- /** Contact email shown on success step for direct founder/dev reach. */
406
- contactEmail?: string;
407
- /** Override the default beta strip message. */
408
- message?: string;
409
- /**
410
- * Optional perks shown to the user for opting in as a beta tester.
411
- * e.g. ['Early access to new lessons', 'Priority bug fix queue'].
412
- */
413
- perks?: string[];
414
- /**
415
- * Version-tied release notes rendered as a collapsible "What's new in this build"
416
- * row in the widget. Closes the feedback loop — "did you fix what I reported?"
417
- * Only the first entry (latest) is shown by default.
418
- */
419
- changelogItems?: MushiBetaChangelogEntry[];
420
- }
421
- interface MushiBetaChangelogEntry {
422
- version: string;
423
- date?: string;
424
- items: string[];
425
- }
426
- interface MushiWidgetInset {
427
- top?: number | 'auto';
428
- right?: number | 'auto';
429
- bottom?: number | 'auto';
430
- left?: number | 'auto';
431
- }
432
- interface MushiWidgetAnchor {
433
- top?: string;
434
- right?: string;
435
- bottom?: string;
436
- left?: string;
437
- }
438
- type MushiPreset = 'production-calm' | 'beta-loud' | 'internal-debug' | 'manual-only' | 'minimal' | 'standard' | 'full';
439
- interface MushiWidgetSmartHideConfig {
440
- onMobile?: 'edge-tab' | 'hide' | false;
441
- onScroll?: 'shrink' | 'hide' | false;
442
- onIdleMs?: number;
443
- }
444
- interface MushiCaptureConfig {
445
- console?: boolean;
446
- network?: boolean;
447
- /**
448
- * URLs that should never be captured as host-app traffic. Strings are
449
- * substring matches; RegExp values are tested against the fully resolved URL.
450
- */
451
- ignoreUrls?: MushiUrlMatcher[];
452
- performance?: boolean;
453
- screenshot?: 'on-report' | 'auto' | 'off';
454
- /**
455
- * Custom screenshot capture function. When provided, the SDK calls this
456
- * instead of its built-in DOM-snapshot capturer. Return a JPEG/PNG data URI
457
- * on success, or `null` to skip attachment. If the function throws the SDK
458
- * falls back to the built-in capturer.
459
- *
460
- * Primary use-case: Capacitor / WebView hosts that route through a native
461
- * plugin (e.g. `@capawesome/capacitor-screenshot`) to obtain a real pixel-
462
- * accurate screen grab instead of the SVG-foreignObject DOM reconstruction.
463
- *
464
- * @example
465
- * capture: {
466
- * screenshot: 'auto',
467
- * screenshotProvider: async () => {
468
- * const { Screenshot } = await import('@capawesome/capacitor-screenshot');
469
- * const { uri } = await Screenshot.take();
470
- * return uri; // data URI on web, file:// on native (SDK handles both)
471
- * },
472
- * }
473
- */
474
- screenshotProvider?: () => Promise<string | null>;
475
- elementSelector?: boolean;
476
- replay?: 'sentry' | 'rrweb' | 'lite' | 'off';
477
- /**
478
- * How to load rrweb for `replay: 'rrweb'`. A published SDK cannot import
479
- * rrweb itself: its bare `import('rrweb')` is invisible to your bundler, so
480
- * rrweb never makes it into your build. Hand the import over and your
481
- * bundler code-splits it like any other dynamic import. Install `rrweb`
482
- * yourself; the chunk loads only for sessions sampled into replay.
483
- *
484
- * Without a loader the SDK uses a global `rrweb` (the UMD build from a
485
- * script tag) when one exists, and otherwise records lite replay (clicks)
486
- * and warns once in the console. Recording masks every input and every
487
- * text node.
488
- *
489
- * @example
490
- * capture: { replay: 'rrweb', rrweb: () => import('rrweb') }
491
- */
492
- rrweb?: () => Promise<{
493
- record?: unknown;
494
- }>;
495
- /**
496
- * Mushi Mushi v2.1 (whitepaper §6 hybrid mode): passive inventory
497
- * discovery. When enabled the SDK observes navigations and emits a
498
- * tiny payload — `(route, title, testids[], outbound api paths[],
499
- * dom_summary[≤200 chars])` — back to `/v1/sdk/discovery`. The
500
- * server aggregates this over a 30-day rolling window and the
501
- * admin can ask Claude to propose an `inventory.yaml` from it.
502
- *
503
- * Default: off. Recommended: enable in dev/preview/staging from the
504
- * day you install the SDK so the proposer has data when you go to
505
- * generate your first inventory.
506
- *
507
- * What is sent (per navigation, throttled to ≤1/route/min):
508
- * - `location.pathname` template-normalized (`/practice/abc-123`
509
- * → `/practice/[id]` via uuid/numeric/hex heuristics + an
510
- * optional framework hint if the host app sets
511
- * `discoverInventory.routeTemplates`)
512
- * - `document.title`
513
- * - All `[data-testid]` values currently in the DOM
514
- * - Recent fetch/XHR paths the existing network capturer saw
515
- * - The first text run of `<h1>` / `<title>` / `<main>` truncated
516
- * to 200 chars (helps Claude name stories well)
517
- * - Sanitized query-param keys (key names only, never values)
518
- * - A SHA-256 of `userId || sessionId` so the server can dedupe
519
- * distinct users without ever seeing identity
520
- *
521
- * Nothing else. No DOM beyond the summary, no query values, no PII.
522
- */
523
- discoverInventory?: boolean | MushiDiscoverInventoryConfig;
524
- /**
525
- * W3C trace-context propagation for OTel-style frontend→backend correlation.
526
- *
527
- * When enabled, the SDK injects a W3C `traceparent` header and an
528
- * `x-mushi-session` header into every fetch/XHR request whose URL matches
529
- * the `corsUrls` allowlist. The generated trace_id is recorded on each
530
- * captured network entry so a bug report can be correlated with the
531
- * backend span that handled the failing request.
532
- *
533
- * Default: disabled. Enable only for origins you control to avoid CORS issues.
534
- * The backend (node SDK or Supabase edge function) must include
535
- * `traceparent` and `x-mushi-session` in `Access-Control-Allow-Headers`.
536
- *
537
- * @example
538
- * capture: {
539
- * tracePropagation: {
540
- * enabled: true,
541
- * corsUrls: [/api\.myapp\.com/, /localhost:3000/],
542
- * }
543
- * }
544
- */
545
- tracePropagation?: MushiTracePropagationConfig;
546
- }
547
- interface MushiTracePropagationConfig {
548
- /** Enable W3C traceparent injection. Defaults to false. */
549
- enabled?: boolean;
550
- /**
551
- * URL patterns for which the SDK injects `traceparent` + `x-mushi-session`
552
- * headers. Only requests matching at least one pattern are instrumented.
553
- * Strings are substring-matched; RegExp values are tested against the full URL.
554
- * Required when `enabled` is true — an empty allowlist silently disables propagation.
555
- */
556
- corsUrls?: Array<string | RegExp>;
557
- }
558
- /**
559
- * Fine-grained controls for `discoverInventory`. Defaults are tuned
560
- * to be quiet enough for production but dense enough for the proposer
561
- * to produce useful drafts.
562
- */
563
- interface MushiDiscoverInventoryConfig {
564
- enabled?: boolean;
565
- /**
566
- * Minimum gap between two emissions for the same route (ms). Defaults
567
- * to 60_000. Set to a larger value for high-traffic SPAs to keep the
568
- * ingest volume manageable.
569
- */
570
- throttleMs?: number;
571
- /**
572
- * Static route templates the host framework knows about. When set,
573
- * a visit to `/practice/abc-123` matches `/practice/[id]` and gets
574
- * normalized to that template. Without this we fall back to a
575
- * heuristic (uuid / numeric / 24-char-hex segments collapse to
576
- * `[id]`). Provide this when you have a static manifest — Next.js'
577
- * `next.config` route export, React Router's route config, etc.
578
- */
579
- routeTemplates?: string[];
580
- /**
581
- * Override the SHA-256 user-id-hash input. Defaults to
582
- * `mushi.userId || sessionId`. Set to `null` to opt out of distinct-
583
- * user counting entirely.
584
- */
585
- userIdSource?: 'auto' | 'session-only' | 'none';
586
- /**
587
- * If false, the DOM summary (≤200 chars from h1/title/main) is not
588
- * captured. Default true.
589
- */
590
- captureDomSummary?: boolean;
591
- }
592
- interface MushiPrivacyConfig {
593
- /** DOM nodes to visually mask in screenshots before upload. */
594
- maskSelectors?: string[];
595
- /** DOM subtrees to remove from screenshots before upload. */
596
- blockSelectors?: string[];
597
- /**
598
- * CSS selectors whose matching elements are blacked-out (filled with an
599
- * opaque black rectangle) in screenshots before upload. Intended for
600
- * sensitive fields that should never appear in any form — passwords, PII,
601
- * financial data. Applied in addition to `maskSelectors`.
602
- *
603
- * Always redacted, whatever this is set to: `input[type="password"]`,
604
- * `input[autocomplete^="cc-"]`, `[data-private]`, `[data-mushi-mask]`.
605
- * This list is added on top; it defaults to `['[data-mushi-redact]']`,
606
- * and an empty array drops only that default.
607
- */
608
- redactSelectors?: string[];
609
- /** Let reporters remove an attached screenshot before submitting. Defaults to true. */
610
- allowUserRemoveScreenshot?: boolean;
611
- }
612
- interface MushiProactiveConfig {
613
- rageClick?: boolean;
614
- errorBoundary?: boolean;
615
- longTask?: boolean;
616
- apiCascade?: boolean | MushiApiCascadeConfig;
617
- cooldown?: MushiCooldownConfig;
618
- /**
619
- * Beta-mode nudge: fire after the user has been on the same route for
620
- * `thresholdMs` continuous milliseconds (default 5min). Pass `true` to
621
- * accept the default threshold, or a config object to override. Use
622
- * conservatively — set the per-session cap in `cooldown` to avoid
623
- * nag fatigue.
624
- */
625
- pageDwell?: boolean | MushiPageDwellConfig;
626
- /**
627
- * One-shot welcome prompt for first-time visitors. Fires `delayMs` after
628
- * `Mushi.init` (default 45s) and is suppressed permanently after the
629
- * first fire via localStorage. Recommended for beta deployments.
630
- */
631
- firstSession?: boolean | MushiFirstSessionConfig;
632
- }
633
- interface MushiPageDwellConfig {
634
- /** Continuous dwell time before firing. Defaults to 5 minutes. */
635
- thresholdMs?: number;
636
- /**
637
- * Route path prefixes (or glob-style patterns with `*`) that suppress the
638
- * dwell nudge. Auth routes are excluded by default so users aren't prompted
639
- * during login/signup flows.
640
- *
641
- * Default: `['/login', '/logout', '/signup', '/sso/*', '/auth/*']`
642
- */
643
- excludeRoutes?: string[];
644
- }
645
- interface MushiFirstSessionConfig {
646
- /** Delay before firing the welcome nudge. Defaults to 45 seconds. */
647
- delayMs?: number;
648
- /** Override the localStorage key used to mark the user as welcomed. */
649
- storageKey?: string;
650
- }
651
- type MushiUrlMatcher = string | RegExp;
652
- interface MushiApiCascadeConfig {
653
- enabled?: boolean;
654
- /**
655
- * URLs ignored by the API cascade detector. The SDK always ignores its own
656
- * gateway endpoints as well; this hook lets host apps exclude analytics,
657
- * health probes, or third-party scripts that are noisy by design.
658
- */
659
- ignoreUrls?: MushiUrlMatcher[];
660
- }
661
- interface MushiCooldownConfig {
662
- maxProactivePerSession?: number;
663
- dismissCooldownHours?: number;
664
- suppressAfterDismissals?: number;
665
- /**
666
- * Cross-reload re-show cooldown, in minutes (default 30; `0` disables).
667
- *
668
- * The `dismissCooldownHours` window only starts after a clean dismissal is
669
- * recorded (widget `onClose`). A page reload or crash tears down the JS
670
- * context before that, so on a broken/reloading page the proactive panel
671
- * would otherwise re-open on every load. When a prompt is shown the SDK
672
- * persists a timestamp; a fresh session (new JS context) suppresses prompts
673
- * shown within this window. Within a live session the per-session limit
674
- * governs instead, so this never blocks a legitimate second trigger.
675
- */
676
- reshowCooldownMinutes?: number;
677
- }
678
- interface MushiPreFilterConfig {
679
- enabled?: boolean;
680
- blockObviousSpam?: boolean;
681
- minDescriptionLength?: number;
682
- maxDescriptionLength?: number;
683
- /**
684
- * V5.3 §2.12: optional on-device classifier (typically from
685
- * `@mushi-mushi/wasm-classifier`). Consulted before the pattern pre-filter.
686
- * Must conform to the `MushiOnDeviceClassifier` shape.
687
- */
688
- wasmClassifier?: MushiOnDeviceClassifier;
689
- }
690
- interface MushiOnDeviceClassifierInput {
691
- description: string;
692
- category?: string;
693
- url?: string;
694
- hasScreenshot?: boolean;
695
- hasSelectedElement?: boolean;
696
- hasNetworkErrors?: boolean;
697
- hasConsoleErrors?: boolean;
698
- proactiveTrigger?: string;
699
- }
700
- interface MushiOnDeviceClassifierResult {
701
- verdict: 'pass' | 'block' | 'unsure';
702
- confidence: number;
703
- reason: string;
704
- modelId: string;
705
- durationMs: number;
706
- }
707
- interface MushiOnDeviceClassifier {
708
- readonly modelId: string;
709
- classify(input: MushiOnDeviceClassifierInput): Promise<MushiOnDeviceClassifierResult>;
710
- destroy(): void;
711
- }
712
- interface MushiIntegrationsConfig {
713
- opentelemetry?: {
714
- traceContext?: boolean;
715
- };
716
- vercel?: {
717
- analyticsId?: string;
718
- };
719
- custom?: (report: MushiReportBuilder) => void;
720
- }
721
- interface MushiOfflineConfig {
722
- enabled?: boolean;
723
- maxQueueSize?: number;
724
- syncOnReconnect?: boolean;
725
- /**
726
- * Encrypt queued reports at rest (IndexedDB + localStorage) with AES-GCM.
727
- *
728
- * Wave S1 / D-16: on a shared device (kiosks, iPads, support-agent
729
- * laptops) any queued report sits in plaintext until the next online flush.
730
- * With this flag set we generate a non-extractable AES-GCM key at first use,
731
- * stash it in a single tightly-scoped IndexedDB record, and wrap every
732
- * queued report payload under it. The key never leaves the origin's
733
- * IndexedDB; stealing the DB file on disk still requires the OS-level
734
- * Web Crypto keystore to decrypt.
735
- *
736
- * Defaults to `true`. Set false only if you need to inspect raw queue
737
- * contents during local dev.
738
- */
739
- encryptAtRest?: boolean;
740
- }
741
- interface MushiRewardsConfig {
742
- enabled?: boolean;
743
- /**
744
- * P1: when true the SDK auto-tracks route navigations, [data-testid] clicks,
745
- * and session dwell time and flushes them to POST /v1/sdk/activity.
746
- * Default false. Requires opted_in_to_rewards = true from the end user.
747
- */
748
- trackActivity?: boolean;
749
- /**
750
- * Activity batch flush interval in ms. Default 300_000 (5 min).
751
- * Minimum 30_000 (30s) — smaller values are clamped.
752
- */
753
- flushIntervalMs?: number;
754
- /**
755
- * Show a tier + points footer in the SDK widget.
756
- * Default false.
757
- */
758
- showInWidget?: boolean;
759
- /**
760
- * Whether to show a "+X pts" toast notification on each award.
761
- * Default true when enabled.
762
- */
763
- showNotifications?: boolean;
764
- /**
765
- * 'auto' — immediately opt the user in when identify() is called.
766
- * 'explicit' — SDK surfaces a one-time consent prompt. Default 'explicit'.
767
- */
768
- consentMode?: 'auto' | 'explicit';
769
- /**
770
- * P2: callback that returns a host-app JWT for server-side identity
771
- * verification before monetary rewards are issued. Return null to skip
772
- * verification for non-monetary actions.
773
- */
774
- verifyUserToken?: () => Promise<string | null>;
775
- /**
776
- * @deprecated Superseded by server-side reward_webhooks table.
777
- * Kept for backwards compatibility; has no effect from v0.10.0.
778
- */
779
- webhookOnReward?: string;
780
- }
781
- interface MushiReputationResult {
782
- totalPoints: number;
783
- points30d: number;
784
- reputation: number;
785
- confirmedBugs: number;
786
- totalReports: number;
787
- }
788
- interface MushiTierResult {
789
- id: string;
790
- slug: string;
791
- displayName: string;
792
- pointsThreshold: number;
793
- perks: Record<string, unknown>;
794
- }
795
- interface MushiActivityEvent {
796
- action: string;
797
- metadata?: Record<string, unknown>;
798
- }
799
- type MushiReportCategory = 'bug' | 'slow' | 'visual' | 'confusing' | 'other';
800
- type MushiReportStatus = 'pending' | 'submitted' | 'classified' | 'grouped' | 'fixing' | 'fixed' | 'dismissed';
801
- interface MushiReport {
802
- id: string;
803
- projectId: string;
804
- category: MushiReportCategory;
805
- /**
806
- * Custom category identifier set by the host app via `widget.categories`.
807
- * Preserved as `reports.user_category` on the server so the Mushi console
808
- * can filter by it independently of the LLM-assigned `category`.
809
- * Not set when the host uses the default built-in category set.
810
- */
811
- userCategory?: string;
812
- description: string;
813
- userIntent?: string;
814
- environment: MushiEnvironment;
815
- consoleLogs?: MushiConsoleEntry[];
816
- networkLogs?: MushiNetworkEntry[];
817
- performanceMetrics?: MushiPerformanceMetrics;
818
- timeline?: MushiTimelineEntry[];
819
- screenshotDataUrl?: string;
820
- selectedElement?: MushiSelectedElement;
821
- /** rrweb / lite rolling-buffer events attached on submit when capture.replay is enabled. */
822
- replayEvents?: unknown[];
823
- metadata?: Record<string, unknown>;
824
- sessionId?: string;
825
- reporterToken: string;
826
- /**
827
- * §3c — stable per-device hash from `getDeviceFingerprintHash()`.
828
- * Sent so the server can run the cross-account anti-gaming check; falls
829
- * back to IP+UA fingerprinting when omitted.
830
- */
831
- fingerprintHash?: string;
832
- appVersion?: string;
833
- /** SDK package that submitted the report, e.g. `@mushi-mushi/web`. */
834
- sdkPackage?: string;
835
- /** npm package version that submitted the report, e.g. `0.8.0`. */
836
- sdkVersion?: string;
837
- proactiveTrigger?: string;
838
- /**
839
- * Mushi-side breadcrumbs maintained by the SDK in a 50-entry ring buffer.
840
- * Captured automatically (SDK lifecycle events, console errors, route
841
- * changes, `[data-testid]` clicks) and via `Mushi.addBreadcrumb()`.
842
- * Independent of Sentry's breadcrumbs (those land in
843
- * `sentryContext.breadcrumbs`) so a host using Mushi without Sentry
844
- * still gets a timeline.
845
- */
846
- breadcrumbs?: MushiBreadcrumb[];
847
- /**
848
- * Sticky tags set via `Mushi.setTag()` / `Mushi.setTags()`. Mirrors
849
- * the Sentry / DataDog "tag" vocabulary — short string keys with
850
- * scalar values. The Triage LLM treats these as high-signal hints
851
- * ("checkout-flow=redesign-v2" tells the LLM which feature flag the
852
- * report came from). Plumbed through to `reports.metadata.tags`
853
- * server-side until a dedicated `tags` column is added.
854
- */
855
- tags?: Record<string, string | number | boolean>;
856
- /**
857
- * Rich Sentry context captured at report time. Replaces the legacy
858
- * `sentryEventId`/`sentryReplayId` pair (those are kept for
859
- * back-compat — server unifies them). When the host has Sentry
860
- * installed (v7, v8, or v9), every Mushi report carries enough trace
861
- * data for the admin to pivot into Sentry's MCP / web UI without
862
- * a manual paste.
863
- */
864
- sentryContext?: MushiSentryContext;
865
- /** @deprecated use `sentryContext.eventId` — kept for back-compat. */
866
- sentryEventId?: string;
867
- /** @deprecated use `sentryContext.replayId` — kept for back-compat. */
868
- sentryReplayId?: string;
869
- queuedAt?: string;
870
- createdAt: string;
871
- }
872
- /**
873
- * Single breadcrumb entry. Shape follows the Sentry breadcrumb schema
874
- * 1:1 so an admin tooling layer (or the Triage LLM) can treat Mushi
875
- * breadcrumbs and Sentry breadcrumbs interchangeably without a
876
- * normalisation pass.
877
- */
878
- interface MushiBreadcrumb {
879
- /** Unix epoch ms when the breadcrumb fired. */
880
- timestamp: number;
881
- /**
882
- * Coarse bucket for filtering / coloring in the report drawer.
883
- * - `navigation` — route or url change
884
- * - `ui.click` — user clicked a `[data-testid]` element (web SDK)
885
- * - `ui.tap` — user tapped a `UIView` / Android `View` (native SDKs)
886
- * - `console` — `console.error` / `console.warn` callsite
887
- * - `xhr` / `fetch` — network request that errored or 4xx/5xx (web SDK)
888
- * - `network` — network failure on iOS / Android (native SDKs)
889
- * - `lifecycle` — Mushi SDK init / open / submit / queue
890
- * - `custom` — host called `Mushi.addBreadcrumb()`
891
- *
892
- * Admin tooling that filters by interaction should treat
893
- * `ui.click` ∪ `ui.tap` as one bucket and `xhr` ∪ `fetch` ∪ `network`
894
- * as one bucket. Native enums are platform-idiomatic (`tap` on touch
895
- * devices, `network` because iOS/Android don't expose `XHR` / `fetch`
896
- * separately) — every wire string is documented in the native READMEs.
897
- */
898
- category: 'navigation' | 'ui.click' | 'ui.tap' | 'console' | 'xhr' | 'fetch' | 'network' | 'lifecycle' | 'custom';
899
- /**
900
- * Severity — `info` is the default. `warning` / `error` map to a
901
- * coloured pill in the drawer; the Triage LLM uses these to decide
902
- * which breadcrumbs to feature in the "what happened" summary.
903
- */
904
- level: 'debug' | 'info' | 'warning' | 'error';
905
- /** Free-form short summary, capped at 500 chars at submit time. */
906
- message: string;
907
- /** Optional structured payload — kept small to keep ingest cheap. */
908
- data?: Record<string, unknown>;
909
- /**
910
- * Correlation ID linking this breadcrumb to the `MushiNetworkEntry` and
911
- * `MushiConsoleEntry` entries emitted during the same network request's
912
- * lifetime (Phase 3b). Set for `fetch` / `xhr` category crumbs and for
913
- * console entries captured while a request was in-flight.
914
- */
915
- correlationId?: string;
916
- }
917
- /**
918
- * Snapshot of Sentry's current scope at report submission. Captured by
919
- * `captureSentryContext()` in the web SDK; designed to be cheap to
920
- * serialise and exhaustively useful when the admin pivots into Sentry
921
- * MCP via `find_organizations` → `search_issues` → `get_event_attachment`.
922
- *
923
- * Every field is optional so a host without Sentry installed (and a
924
- * Sentry SDK that exposes only a subset of these globals) still
925
- * produces a partial — but useful — payload.
926
- */
927
- interface MushiSentryContext {
928
- /** Sentry SDK version family detected at capture time. */
929
- sdk?: 'v7' | 'v8' | 'v9' | 'unknown';
930
- /** `Sentry.lastEventId()` (v8+) / `getLastEventId()` (v7). */
931
- eventId?: string;
932
- /** Replay session id from `Sentry.getReplay()?.getReplayId()`. */
933
- replayId?: string;
934
- /** Distributed-tracing trace id (32 hex). */
935
- traceId?: string;
936
- /** Active span id at capture time (16 hex). */
937
- spanId?: string;
938
- /** `transaction` field from the active scope, e.g. `GET /checkout`. */
939
- transactionName?: string;
940
- /** Build identifier set via `Sentry.init({ release })`. */
941
- release?: string;
942
- /** Logical environment, e.g. `production`. */
943
- environment?: string;
944
- /** Session id when Sentry session-tracking is enabled. */
945
- sessionId?: string;
946
- /** User context from Sentry's scope (id/email/username/ip). */
947
- user?: {
948
- id?: string;
949
- email?: string;
950
- username?: string;
951
- ip_address?: string;
952
- };
953
- /** Tags attached to Sentry's current scope. */
954
- tags?: Record<string, string | number | boolean>;
955
- /**
956
- * Last N Sentry breadcrumbs (default cap = 30). Already-formatted
957
- * Sentry breadcrumbs, not Mushi's — the two are surfaced side by
958
- * side in the admin drawer so users can correlate.
959
- */
960
- breadcrumbs?: Array<{
961
- timestamp?: number;
962
- category?: string;
963
- level?: string;
964
- message?: string;
965
- type?: string;
966
- data?: Record<string, unknown>;
967
- }>;
968
- /**
969
- * Issue url (deeplink) when the SDK can derive it from the event id
970
- * + DSN. Lets the admin jump straight to the Sentry issue page
971
- * without the user pasting a link.
972
- */
973
- issueUrl?: string;
974
- }
975
- interface MushiReportBuilder {
976
- addMetadata(key: string, value: unknown): void;
977
- setCategory(category: MushiReportCategory): void;
978
- setDescription(description: string): void;
979
- }
980
- interface MushiEnvironment {
981
- userAgent: string;
982
- platform: string;
983
- language: string;
984
- viewport: {
985
- width: number;
986
- height: number;
987
- };
988
- url: string;
989
- referrer: string;
990
- timestamp: string;
991
- timezone: string;
992
- connection?: {
993
- effectiveType?: string;
994
- downlink?: number;
995
- rtt?: number;
996
- };
997
- deviceMemory?: number;
998
- hardwareConcurrency?: number;
999
- /**
1000
- * v2 inventory hints (whitepaper §4.7).
1001
- *
1002
- * `route` — the bare pathname (no query / hash). Pinned to the
1003
- * inventory's `Page.path` so the Triage LLM can shortcut from a
1004
- * freeform "the streak counter is broken" report to the right page.
1005
- *
1006
- * `nearestTestid` — the closest ancestor of the active element with
1007
- * a `data-testid`, captured at widget-open time. This pins the
1008
- * report to one Action node when more than one page has the same
1009
- * page path (e.g. a shared "Buy Pro" CTA on landing + dashboard).
1010
- *
1011
- * Both are best-effort; freeform reports with no active element will
1012
- * have `route` only.
1013
- */
1014
- route?: string;
1015
- nearestTestid?: string;
1016
- /**
1017
- * Native-shell detection (best-effort, present only when a native bridge is
1018
- * detected). Lets triage distinguish a Capacitor/Cordova/React-Native WebView
1019
- * report from a plain browser one, and lets the SDK gate DOM-only behaviour.
1020
- */
1021
- native?: {
1022
- capacitor?: boolean;
1023
- cordova?: boolean;
1024
- reactNative?: boolean;
1025
- };
1026
- /**
1027
- * SDK boost (2026-05-07): richer per-report context so the Triage LLM
1028
- * and the admin /reports detail drawer have something to reason about
1029
- * beyond `userAgent`. Every field is optional so legacy SDKs and
1030
- * non-browser callers (CLI, server-to-server) keep validating.
1031
- */
1032
- /**
1033
- * Parsed UA-CH (User-Agent Client Hints) high-entropy values when the
1034
- * browser supports `navigator.userAgentData.getHighEntropyValues`.
1035
- * This is the modern, reliable way to identify Chromium browsers — UA
1036
- * sniffing is unreliable post-Chrome 100 because the UA string was
1037
- * frozen for privacy. Safari + Firefox don't expose UA-CH so we still
1038
- * fall back to UA parsing for those (handled server-side).
1039
- */
1040
- userAgentData?: {
1041
- /** Best-effort browser brand (e.g. "Chrome", "Edge", "Brave"). */
1042
- browser?: string;
1043
- /** Browser version (full semver where available, e.g. "131.0.6778.86"). */
1044
- browserVersion?: string;
1045
- /** OS family (e.g. "macOS", "Windows", "Android", "iOS"). */
1046
- os?: string;
1047
- /** OS version when the browser exposes it (e.g. "14.5.0"). */
1048
- osVersion?: string;
1049
- /** Whether the device self-identifies as mobile (UA-CH `mobile`). */
1050
- mobile?: boolean;
1051
- /** Device model when the OS exposes it (Android only, e.g. "Pixel 8"). */
1052
- model?: string;
1053
- /** CPU architecture (e.g. "x86", "arm"). */
1054
- architecture?: string;
1055
- /** CPU bitness ("32" or "64"). */
1056
- bitness?: string;
1057
- };
1058
- /**
1059
- * Physical device pixels behind the viewport. `viewport` already
1060
- * captures the CSS pixel box; this lets us tell a 1080p MacBook from a
1061
- * Retina iPhone and explain "looks fine on my screen, broken on
1062
- * theirs" by surfacing devicePixelRatio mismatches.
1063
- */
1064
- screen?: {
1065
- /** `screen.width` — outer device width in CSS px. */
1066
- width?: number;
1067
- /** `screen.height` — outer device height in CSS px. */
1068
- height?: number;
1069
- /** `window.devicePixelRatio` — physical / CSS px ratio. */
1070
- devicePixelRatio?: number;
1071
- /** `screen.colorDepth` — bits per pixel (typically 24/30). */
1072
- colorDepth?: number;
1073
- /** Active orientation type from `screen.orientation`. */
1074
- orientation?: 'portrait-primary' | 'portrait-secondary' | 'landscape-primary' | 'landscape-secondary' | string;
1075
- };
1076
- /**
1077
- * Accessibility / display preferences resolved via media queries.
1078
- * These are reproduction hints — a bug that only repros under
1079
- * `prefers-reduced-motion: reduce` or `forced-colors: active` is one
1080
- * the developer would otherwise spend hours hunting for.
1081
- */
1082
- prefersColorScheme?: 'dark' | 'light' | 'no-preference';
1083
- prefersReducedMotion?: boolean;
1084
- prefersReducedData?: boolean;
1085
- prefersContrast?: 'more' | 'less' | 'no-preference' | 'custom';
1086
- forcedColors?: boolean;
1087
- /** `navigator.onLine` at capture time. False = the report was filed offline. */
1088
- online?: boolean;
1089
- /**
1090
- * `(display-mode: standalone | minimal-ui | fullscreen | browser)`
1091
- * resolved via media queries. Tells us whether the user filed the
1092
- * report from a regular browser tab, an installed PWA, or a TWA — a
1093
- * different code path on iOS Safari for each.
1094
- */
1095
- displayMode?: 'browser' | 'minimal-ui' | 'standalone' | 'fullscreen';
1096
- /** `document.title` at capture time. Surface for "what page were they on?". */
1097
- documentTitle?: string;
1098
- /**
1099
- * Optional opt-in build identifier from `<meta name="mushi:build" content="...">`.
1100
- * Hosts that already expose a git SHA / build number to their HTML
1101
- * (e.g. `<meta name="mushi:build" content="abc123def">`) get it
1102
- * threaded through automatically — no SDK config required. Pairs with
1103
- * `appVersion` to pin reports to a specific deploy.
1104
- */
1105
- buildId?: string;
1106
- /**
1107
- * Snapshot of the Navigation Timing entry. Reports that come in
1108
- * during a slow page load look very different from steady-state
1109
- * reports, and the LLM can't tell the difference from a stack alone.
1110
- */
1111
- pageLoadTiming?: {
1112
- /** `domContentLoadedEventEnd - startTime` in ms. */
1113
- domContentLoadedMs?: number;
1114
- /** `loadEventEnd - startTime` in ms. */
1115
- loadCompleteMs?: number;
1116
- /** `responseStart - startTime` in ms (TTFB). */
1117
- timeToFirstByteMs?: number;
1118
- /** Navigation type (`navigate`, `reload`, `back_forward`, `prerender`). */
1119
- navigationType?: string;
1120
- };
1121
- }
1122
- interface MushiConsoleEntry {
1123
- level: 'log' | 'warn' | 'error' | 'info' | 'debug';
1124
- message: string;
1125
- timestamp: number;
1126
- stack?: string;
1127
- /**
1128
- * Correlation ID linking this console entry to the network request that was
1129
- * active when this log was emitted (e.g. the fetch whose catch block called
1130
- * console.error). Matches `MushiNetworkEntry.correlationId`. Set by the SDK's
1131
- * active-request tracker (Phase 3b).
1132
- */
1133
- correlationId?: string;
1134
- }
1135
- interface MushiNetworkEntry {
1136
- method: string;
1137
- url: string;
1138
- status: number;
1139
- duration: number;
1140
- timestamp: number;
1141
- requestHeaders?: Record<string, string>;
1142
- responseHeaders?: Record<string, string>;
1143
- error?: string;
1144
- /**
1145
- * W3C trace ID (32-char lowercase hex) injected by the SDK's trace propagation
1146
- * feature. Present only when `capture.tracePropagation.enabled` is true AND
1147
- * the request URL matched the `corsUrls` allowlist.
1148
- * Used to correlate this network entry with a backend span in the admin console.
1149
- */
1150
- traceId?: string;
1151
- /**
1152
- * Whether this entry was captured by the fetch interceptor or the XHR interceptor
1153
- * (Phase 3a). Used for row-level provenance badges in the console UI.
1154
- */
1155
- captureMethod?: 'fetch' | 'xhr';
1156
- /**
1157
- * Correlation ID shared with `MushiConsoleEntry.correlationId` and
1158
- * `MushiBreadcrumb.correlationId` for entries emitted during this request's
1159
- * lifetime (Phase 3b). Enables "highlight all logs/crumbs from this request."
1160
- */
1161
- correlationId?: string;
1162
- }
1163
- interface MushiPerformanceMetrics {
1164
- fcp?: number;
1165
- lcp?: number;
1166
- cls?: number;
1167
- fid?: number;
1168
- inp?: number;
1169
- ttfb?: number;
1170
- longTasks?: number;
1171
- inpAttribution?: {
1172
- eventType?: string;
1173
- targetSelector?: string;
1174
- inputDelay?: number;
1175
- processingDuration?: number;
1176
- presentationDelay?: number;
1177
- };
1178
- }
1179
- interface MushiSelectedElement {
1180
- tagName: string;
1181
- id?: string;
1182
- className?: string;
1183
- textContent?: string;
1184
- xpath?: string;
1185
- rect?: {
1186
- x: number;
1187
- y: number;
1188
- width: number;
1189
- height: number;
1190
- };
1191
- /**
1192
- * `data-testid` of the closest ancestor that has one. Mushi v2 uses this
1193
- * to map a report → Action node in the bidirectional graph (whitepaper §4.7).
1194
- * Falls back to `undefined` when no ancestor declares a testid — the v2
1195
- * Triage LLM still classifies these reports, just without the inventory
1196
- * grounding shortcut.
1197
- */
1198
- nearestTestid?: string;
1199
- /** Path of the page the user reported from (`window.location.pathname`).
1200
- * Combined with `nearestTestid` it pins a report to one Action even when
1201
- * the same testid exists on multiple pages. */
1202
- route?: string;
1203
- }
1204
- type MushiTimelineKind = 'route' | 'click' | 'request' | 'log' | 'screen';
1205
- interface MushiTimelineEntry {
1206
- ts: number;
1207
- kind: MushiTimelineKind;
1208
- payload: Record<string, unknown>;
1209
- }
1210
- type MushiEventType = 'report:submitted' | 'report:queued' | 'report:sent' | 'report:failed' | 'widget:opened' | 'widget:closed' | 'proactive:triggered' | 'proactive:dismissed' | 'report:dispatched';
1211
- type MushiEventHandler = (event: {
1212
- type: MushiEventType;
1213
- data?: unknown;
1214
- }) => void;
1215
- interface MushiDiagnosticsResult {
1216
- apiEndpointReachable: boolean;
1217
- cspAllowsEndpoint: boolean;
1218
- widgetMounted: boolean;
1219
- shadowDomAvailable: boolean;
1220
- dialogSupported: boolean;
1221
- runtimeConfigLoaded: boolean;
1222
- captureScreenshotAvailable: boolean;
1223
- captureNetworkIntercepting: boolean;
1224
- sdkVersion: string;
1225
- /**
1226
- * True when the widget host element has `pointer-events: none` and
1227
- * zero width/height — i.e. it cannot act as a touch blocker over host UI.
1228
- * False when the SDK has not yet mounted, or when a consumer has overridden
1229
- * the host styles without restoring the pass-through contract.
1230
- */
1231
- widgetHostPointerSafe: boolean;
1232
- /**
1233
- * Bounding rect of the widget host element (`offsetWidth × offsetHeight`).
1234
- * Should be `{ width: 0, height: 0 }` for a healthy SDK — the host is
1235
- * zero-sized with `overflow: visible` so the shadow internals extend
1236
- * outward without creating a hit-test surface. `null` when not mounted.
1237
- */
1238
- widgetHostBounds: {
1239
- width: number;
1240
- height: number;
1241
- } | null;
1242
- /**
1243
- * True when the widget is currently suppressed: `hideOnSelector` matched an
1244
- * element, `hideOnRoutes` matched the current pathname, or `hide()` was
1245
- * called. A suppressed widget renders nothing and removes the body nudge.
1246
- */
1247
- widgetSuppressed: boolean;
1248
- /**
1249
- * True when `trigger: 'banner'` is active and the banner is currently
1250
- * rendered in the shadow DOM (not dismissed, not suppressed).
1251
- */
1252
- bannerRendered: boolean;
1253
- }
1254
- /**
1255
- * Page-aware assistant (P5). The host app publishes a structured snapshot of
1256
- * what the current screen is showing; the SDK forwards only this narrow,
1257
- * server-validated subset so a malicious page cannot inject arbitrary prompt
1258
- * fields. Ported from the admin console's page-context registry.
1259
- */
1260
- interface MushiPageContext {
1261
- /** Current route/path (e.g. '/activity'). */
1262
- route: string;
1263
- /** Human title of the screen. */
1264
- title?: string;
1265
- /** One-line description of what is on screen. */
1266
- summary?: string;
1267
- /** Active filters as a flat key/value map. */
1268
- filters?: Record<string, string | number | boolean | null | undefined>;
1269
- /** The focused/selected entity, if any. */
1270
- selection?: {
1271
- kind: string;
1272
- id: string;
1273
- label?: string;
1274
- } | null;
1275
- }
1276
- interface MushiAssistantConfig {
1277
- /**
1278
- * Enable the in-SDK assistant tab. Defaults to false; the console can also
1279
- * enable it via runtime config so it can be turned on without a rebuild.
1280
- */
1281
- enabled?: boolean;
1282
- /** Tab label (default: "Ask"). */
1283
- label?: string;
1284
- /** Greeting shown on an empty assistant thread. */
1285
- greeting?: string;
1286
- /** Suggested starter questions shown on an empty thread. */
1287
- suggestions?: string[];
1288
- }
1289
- interface MushiAssistantStep {
1290
- label: string;
1291
- detail?: string;
1292
- }
1293
- interface MushiAssistantReply {
1294
- /** 'answer' resolves the turn; 'clarify' asks the user a follow-up. */
1295
- kind: 'answer' | 'clarify';
1296
- text?: string;
1297
- steps?: MushiAssistantStep[];
1298
- /** For 'clarify' replies. */
1299
- question?: string;
1300
- options?: string[];
1301
- /** Server-assigned thread id so the next turn continues the conversation. */
1302
- threadId?: string;
1303
- }
1304
- interface MushiSDKInstance {
1305
- /**
1306
- * Open the reporter widget. With no options, opens to the category
1307
- * picker so the user can choose between bug categories and the
1308
- * feature-request shortcut. Pass `{ category }` to deep-link into a
1309
- * specific bug intent, or `{ featureRequest: true }` to deep-link into
1310
- * the feature-request description step (skips intent picker).
1311
- *
1312
- * When `widget.categories` is configured, `category` also accepts a
1313
- * custom category `id` from that list.
1314
- */
1315
- report(options?: {
1316
- category?: MushiReportCategory | string;
1317
- featureRequest?: boolean;
1318
- }): void;
1319
- on(event: MushiEventType, handler: MushiEventHandler): () => void;
1320
- setUser(user: {
1321
- id: string;
1322
- email?: string;
1323
- name?: string;
1324
- }): void;
1325
- setMetadata(key: string, value: unknown): void;
1326
- setScreen(screen: {
1327
- name: string;
1328
- route?: string;
1329
- feature?: string;
1330
- }): void;
1331
- isOpen(): boolean;
1332
- open(): void;
1333
- /**
1334
- * Open the widget deep-linked to a specific category. Accepts a built-in
1335
- * `MushiReportCategory` value or a custom category `id` when
1336
- * `widget.categories` is configured.
1337
- */
1338
- openWith(category: MushiReportCategory | string): void;
1339
- show(): void;
1340
- hide(): void;
1341
- attachTo(selectorOrElement: string | Element, options?: MushiWidgetConfig): () => void;
1342
- setTrigger(trigger: NonNullable<MushiWidgetConfig['trigger']>): void;
1343
- /** Open the widget directly to the reporter's "My reports" history view. */
1344
- openReporter(): void;
1345
- close(): void;
1346
- destroy(): void;
1347
- updateConfig(config: MushiRuntimeSdkConfig): void;
1348
- diagnose(): Promise<MushiDiagnosticsResult>;
1349
- /**
1350
- * Wave G4 — unified `captureEvent` API. Submits a bug report
1351
- * programmatically without opening the widget. Useful for adapters
1352
- * that translate errors from Datadog / Honeycomb / Sentry /
1353
- * Grafana into Mushi reports.
1354
- *
1355
- * Returns the server-assigned report id when the submit succeeds.
1356
- */
1357
- captureEvent(event: MushiCaptureEventInput): Promise<string | null>;
1358
- /**
1359
- * 2026-05-07 — `try/catch`-friendly sugar over `captureEvent`. Pass
1360
- * a thrown value directly and Mushi normalises it (any exotic
1361
- * throw shape: `Error`, string, plain object, `null`) into a report
1362
- * with category `bug`, severity `high` (overridable), and the
1363
- * stack trace folded into both `description` (compact) and
1364
- * `metadata.error.stack` (full).
1365
- *
1366
- * Pairs with Sentry: when `config.sentry` is present, the same
1367
- * call-site can flush to Sentry (`Sentry.captureException(err)`)
1368
- * and Mushi (`Mushi.captureException(err)`) — the two reports get
1369
- * cross-linked via `sentryContext.eventId` automatically.
1370
- */
1371
- captureException(error: unknown, options?: MushiCaptureExceptionOptions): Promise<string | null>;
1372
- /**
1373
- * Wave G4 — sugar alias for `setUser()`. Name mirrors the
1374
- * identify/track/capture vocabulary that PostHog/Segment/Mixpanel
1375
- * users already know.
1376
- */
1377
- identify(userId: string, traits?: {
1378
- email?: string;
1379
- name?: string;
1380
- [k: string]: unknown;
1381
- }): void;
1382
- /**
1383
- * Identify the current end user with a signed Mushi identity JWT minted by
1384
- * the host app's server (see `@mushi-mushi/node`'s `mintMushiIdentityToken`).
1385
- * This is the trust anchor for secure "My Reports", rewards-to-membership
1386
- * grants, and the per-user assistant data index — the backend re-verifies
1387
- * the signature against the project's identity secret. Unlike `identify()`,
1388
- * which is spoofable, claims from this token are trusted server-side.
1389
- *
1390
- * Pass `null` (or call on logout) to clear the identity and fall back to the
1391
- * anonymous reporter token.
1392
- */
1393
- identifyWithToken(token: string | null): void;
1394
- /**
1395
- * Publish the current screen's context so the in-SDK assistant can answer
1396
- * page-aware questions. Call on every route/selection change. Pass `null`
1397
- * to clear (e.g. on unmount). Only a narrow subset is sent to the server.
1398
- */
1399
- publishPageContext(context: MushiPageContext | null): void;
1400
- /** Open the widget on the assistant ("Ask") tab. */
1401
- openAssistant(): void;
1402
- /**
1403
- * Sentry-grade observability surface (2026-05-07).
1404
- *
1405
- * Hosts can drop a breadcrumb on every meaningful state change in
1406
- * their app — feature-flag toggles, route transitions, optimistic
1407
- * UI commits, server reconciliation — and the buffer's last 50
1408
- * entries automatically attach to every report. Useful even when
1409
- * Sentry isn't installed; when it is, Mushi reports also carry
1410
- * Sentry's breadcrumbs alongside Mushi's own.
1411
- */
1412
- addBreadcrumb(crumb: Omit<MushiBreadcrumb, 'timestamp'> & {
1413
- timestamp?: number;
1414
- }): void;
1415
- /** Snapshot of the current breadcrumb ring buffer (oldest first). */
1416
- getBreadcrumbs(): MushiBreadcrumb[];
1417
- /**
1418
- * Set a sticky tag that lands on every subsequent report. Numeric
1419
- * and boolean values are accepted; they're coerced to strings on
1420
- * the wire so the Triage LLM can read them without type juggling.
1421
- */
1422
- setTag(key: string, value: string | number | boolean): void;
1423
- /** Bulk variant of `setTag`. Replaces existing values for shared keys. */
1424
- setTags(tags: Record<string, string | number | boolean>): void;
1425
- /** Remove a single tag, or all tags when called with no argument. */
1426
- clearTag(key?: string): void;
1427
- /**
1428
- * Returns the current user's reputation + legacy point totals from the
1429
- * reporter_reputation table. Available even when the rewards program is
1430
- * disabled (legacy surface).
1431
- */
1432
- getReputation(): Promise<MushiReputationResult | null>;
1433
- /**
1434
- * Returns the current user's tier from the rewards program.
1435
- * Returns null when the user has not yet been identified or the project
1436
- * has rewards_enabled = false.
1437
- */
1438
- getTier(): Promise<MushiTierResult | null>;
1439
- /**
1440
- * Manually record a host-defined activity event (e.g. 'lesson_completed').
1441
- * The SDK batches these and flushes to POST /v1/sdk/activity.
1442
- * No-op when rewards are disabled or the user has not opted in.
1443
- * For product analytics (funnels, paths, people) use `track()` instead.
1444
- */
1445
- recordActivity(action: string, metadata?: Record<string, unknown>): void;
1446
- /**
1447
- * Record a product-analytics event, e.g. `track('checkout_started', { plan: 'pro' })`.
1448
- * Names must match `^[a-z][a-z0-9_]{1,63}$`; properties are flat
1449
- * (string | number | boolean | null), PII-looking keys are dropped, and
1450
- * every string value runs through the PII scrubber. Batched to
1451
- * POST /v1/sdk/events. No-op under DNT/GPC, `analytics.enabled: false`,
1452
- * or before consent when `analytics.consent === 'required'`.
1453
- * Returns true when the event was queued.
1454
- */
1455
- track(event: string, properties?: Record<string, MushiPropertyValue>): boolean;
1456
- /** Grant or deny analytics consent (persisted per project in localStorage). */
1457
- setConsent(state: 'granted' | 'denied'): void;
1458
- /** The anonymous id analytics events are keyed on, or null when tracking is off. */
1459
- getAnonymousId(): string | null;
1460
- /**
1461
- * Briefly animate the bug-report trigger button to draw the user's
1462
- * attention without opening the full widget. Ideal for subtle "feedback
1463
- * welcome" nudges (first-session, beta-onboarding).
1464
- */
1465
- pulseTrigger(): void;
1466
- /**
1467
- * Returns the signed-in reporter's own report history.
1468
- * Keyed to the persistent `reporterToken` stored in localStorage /
1469
- * AsyncStorage. Returns an empty array when no token exists yet.
1470
- */
1471
- listMyReports(): Promise<MushiReporterReport[]>;
1472
- /**
1473
- * Returns the comment thread for a given report. Only returns comments
1474
- * visible to the reporter (their own comments + team replies).
1475
- */
1476
- listMyComments(reportId: string): Promise<MushiReporterComment[]>;
1477
- /**
1478
- * Post a follow-up comment on one of the reporter's own reports.
1479
- * Returns the newly created comment, or null on failure.
1480
- */
1481
- replyToReport(reportId: string, body: string): Promise<MushiReporterComment | null>;
1482
- /**
1483
- * Submit a structured feedback chip (confirms / not_fixed / …) on a report.
1484
- * Drives the verify/reopen lifecycle when the report is in a fixed state.
1485
- */
1486
- submitFeedbackSignal(reportId: string, signal: string, note?: string): Promise<Record<string, unknown> | null>;
1487
- /**
1488
- * Reporter-initiated regression reopen with an optional note.
1489
- */
1490
- reopenReport(reportId: string, note?: string): Promise<Record<string, unknown> | null>;
1491
- /**
1492
- * Open the reporter inbox ("my reports") view in the widget.
1493
- */
1494
- openMyReports(): void;
1495
- /**
1496
- * Returns the global contributor hall-of-fame ranked by total points.
1497
- * Safe to call without an authenticated user; uses public endpoint.
1498
- * @param limit Maximum entries to return (default 20).
1499
- */
1500
- getHallOfFame(limit?: number): Promise<MushiHallOfFameEntry[]>;
1501
- }
1502
- interface MushiCaptureExceptionOptions {
1503
- /** Override the default `'bug'` category (e.g. `'slow'` for timeouts). */
1504
- category?: MushiReportCategory;
1505
- /** Default `'high'`. Use `'critical'` for boot-time errors, `'low'` for known recoverables. */
1506
- severity?: 'critical' | 'high' | 'medium' | 'low';
1507
- /** Affected component / page area, surfaces in the admin reports list. */
1508
- component?: string;
1509
- /** Optional human-readable summary that overrides the auto-derived one. */
1510
- description?: string;
1511
- /** Per-call tags merged with sticky tags. */
1512
- tags?: Record<string, string | number | boolean>;
1513
- /** Free-form metadata folded into `reports.metadata`. */
1514
- metadata?: Record<string, unknown>;
1515
- /** Source label — defaults to `'captureException'`. */
1516
- source?: string;
1517
- }
1518
- interface MushiCaptureEventInput {
1519
- /** Human-readable summary; becomes `reports.description`. */
1520
- description: string;
1521
- category?: MushiReportCategory;
1522
- severity?: 'critical' | 'high' | 'medium' | 'low';
1523
- component?: string;
1524
- /** Arbitrary tags merged into `reports.metadata.tags`. */
1525
- tags?: Record<string, string | number | boolean>;
1526
- /** Source-of-truth adapter that produced this event (e.g. `'datadog'`). */
1527
- source?: string;
1528
- /** Optional error payload (name/message/stack) captured from the host app. */
1529
- error?: {
1530
- name?: string;
1531
- message?: string;
1532
- stack?: string;
1533
- };
1534
- metadata?: Record<string, unknown>;
1535
- }
1536
- interface MushiApiClient {
1537
- submitReport(report: MushiReport): Promise<MushiApiResponse<{
1538
- reportId: string;
1539
- }>>;
1540
- getReportStatus(reportId: string): Promise<MushiApiResponse<{
1541
- status: MushiReportStatus;
1542
- }>>;
1543
- getSdkConfig(): Promise<MushiApiResponse<MushiRuntimeSdkConfig>>;
1544
- /**
1545
- * Send one assistant turn. Forwards the page context + thread id; the
1546
- * end-user identity token (when set) travels on the X-Mushi-User-Token
1547
- * header so the backend can scope retrieval to the verified user.
1548
- */
1549
- askAssistant(input: {
1550
- message: string;
1551
- threadId?: string | null;
1552
- context?: MushiPageContext | null;
1553
- }): Promise<MushiApiResponse<MushiAssistantReply>>;
1554
- getLatestSdkVersion(packageName: string): Promise<MushiApiResponse<MushiSdkVersionInfo>>;
1555
- /**
1556
- * Mushi v2.1: ship a single passive-discovery observation (route +
1557
- * testids + outbound APIs + DOM summary). Best-effort fire-and-forget;
1558
- * the caller should not block on the response. The server rate-limits
1559
- * per (project, route) to keep ingest cheap, so it's fine for clients
1560
- * to over-emit on the throttle window — the server picks the freshest.
1561
- */
1562
- postDiscoveryEvent(event: MushiDiscoveryEventPayload): Promise<MushiApiResponse<{
1563
- accepted: boolean;
1564
- }>>;
1565
- /** POST /v1/sdk/session — lightweight session lifecycle event (best-effort). */
1566
- postSessionEvent(payload: MushiSessionEventPayload): Promise<MushiApiResponse<{
1567
- accepted: boolean;
1568
- }>>;
1569
- /** POST /v1/sdk/events — batched product-analytics events (Mushi.track()). */
1570
- postProductEvents(payload: MushiProductEventPayload): Promise<MushiApiResponse<{
1571
- accepted: number;
1572
- dropped: number;
1573
- }>>;
1574
- listReporterReports(reporterToken: string): Promise<MushiApiResponse<{
1575
- reports: MushiReporterReport[];
1576
- }>>;
1577
- listReporterComments(reportId: string, reporterToken: string): Promise<MushiApiResponse<{
1578
- comments: MushiReporterComment[];
1579
- }>>;
1580
- replyToReporterReport(reportId: string, reporterToken: string, body: string, feedbackSignal?: string): Promise<MushiApiResponse<{
1581
- comment: MushiReporterComment;
1582
- feedback?: Record<string, unknown>;
1583
- }>>;
1584
- reopenReporterReport(reportId: string, reporterToken: string, note?: string): Promise<MushiApiResponse<{
1585
- outcome: Record<string, unknown>;
1586
- }>>;
1587
- /** List in-app notifications for the authenticated reporter. */
1588
- listNotifications(reporterToken: string, opts?: {
1589
- since?: string;
1590
- limit?: number;
1591
- }): Promise<MushiApiResponse<{
1592
- notifications: Array<Record<string, unknown>>;
1593
- }>>;
1594
- /** Mark a single reporter notification as read. */
1595
- markNotificationRead(notificationId: string, reporterToken: string): Promise<MushiApiResponse<{
1596
- ok: boolean;
1597
- }>>;
1598
- /** List the reporter-facing feature board (public roadmap tickets). */
1599
- listReporterFeatureBoard(reporterToken: string): Promise<MushiApiResponse<{
1600
- tickets: Array<Record<string, unknown>>;
1601
- }>>;
1602
- /** Toggle the reporter's vote on a feature-board ticket. */
1603
- voteReporterFeatureBoard(requestId: string, reporterToken: string): Promise<MushiApiResponse<{
1604
- voted: boolean;
1605
- action: string;
1606
- }>>;
1607
- /**
1608
- * Submit a batch of activity events for the current user.
1609
- * Requires rewards to be enabled on the project.
1610
- */
1611
- submitActivity(userId: string, events: MushiActivityEvent[], opts?: {
1612
- userTraits?: {
1613
- email?: string;
1614
- name?: string;
1615
- provider?: string;
1616
- };
1617
- reporterTokenHash?: string;
1618
- optedIn?: boolean;
1619
- /** P2: host-app JWT; when present the server attempts verifyHostJwt
1620
- * and updates end_users.jwt_verified_at if valid. Required for
1621
- * monetary payout eligibility. */
1622
- hostJwt?: string;
1623
- }): Promise<MushiApiResponse<{
1624
- accepted: number;
1625
- total: number;
1626
- }>>;
1627
- /** Fetch the current user's point totals (requires userId). */
1628
- getMyPoints(userId: string): Promise<MushiApiResponse<{
1629
- total_points: number;
1630
- points_30d: number;
1631
- points_lifetime: number;
1632
- tier: MushiTierResult | null;
1633
- }>>;
1634
- /** Fetch the current user's tier (requires userId). */
1635
- getMyTier(userId: string): Promise<MushiApiResponse<MushiTierResult | null>>;
1636
- /** Fetch the current user's activity history (requires userId). */
1637
- getMyHistory(userId: string, opts?: {
1638
- limit?: number;
1639
- }): Promise<MushiApiResponse<{
1640
- items: unknown[];
1641
- total: number;
1642
- }>>;
1643
- /** Fetch the project's public leaderboard (top contributors). */
1644
- getHallOfFame(limit?: number): Promise<MushiApiResponse<{
1645
- data: Array<{
1646
- display_name: string;
1647
- email_hash: string | null;
1648
- tier_slug: string | null;
1649
- tier_name: string | null;
1650
- points_30d: number;
1651
- total_points: number;
1652
- }>;
1653
- meta: {
1654
- project_name: string;
1655
- };
1656
- }>>;
1657
- /** Link the anonymous reporter_token_hash to the caller's mushi_testers row. */
1658
- sendMagicLink(email: string): Promise<MushiApiResponse<{
1659
- ok: boolean;
1660
- }>>;
1661
- linkReporterToken(reporterTokenHash: string, jwt: string): Promise<MushiApiResponse<{
1662
- ok: boolean;
1663
- linked: number;
1664
- }>>;
1665
- /** All reports filed by the signed-in tester, across all projects. */
1666
- getCrossAppReports(jwt: string, opts?: {
1667
- limit?: number;
1668
- offset?: number;
1669
- }): Promise<MushiApiResponse<{
1670
- reports: MushiCrossAppReport[];
1671
- }>>;
1672
- /** The signed-in tester's global rank + points. */
1673
- getMyReputation(jwt: string): Promise<MushiApiResponse<{
1674
- reputation: MushiTesterReputation | null;
1675
- }>>;
1676
- /** Top-N global tester leaderboard (no auth required). */
1677
- getPublicLeaderboard(limit?: number): Promise<MushiApiResponse<{
1678
- leaderboard: MushiLeaderboardEntry[];
1679
- }>>;
1680
- /** Whether the caller has a mushi_testers row. */
1681
- getTesterStatus(jwt: string): Promise<MushiApiResponse<{
1682
- is_tester: boolean;
1683
- tester_id: string | null;
1684
- public_handle: string | null;
1685
- display_name: string | null;
1686
- }>>;
1687
- }
1688
- /**
1689
- * Wire shape of a single discovery event sent by the SDK to
1690
- * `POST /v1/sdk/discovery`. Mirrored server-side in
1691
- * `_shared/schemas.ts::discoveryEventSchema`.
1692
- */
1693
- interface MushiDiscoveryEventPayload {
1694
- route: string;
1695
- page_title?: string | null;
1696
- dom_summary?: string | null;
1697
- testids: string[];
1698
- network_paths: string[];
1699
- query_param_keys: string[];
1700
- user_id_hash?: string | null;
1701
- sdk_version?: string;
1702
- observed_at: string;
1703
- }
1704
- /** Payload for /v1/sdk/session — lightweight session lifecycle tracking.
1705
- * Best-effort, no offline queue. Privacy-safe: no PII by default;
1706
- * `user_id_hash` is the same device-fingerprint hash used elsewhere. */
1707
- interface MushiSessionEventPayload {
1708
- /** Lifecycle event kind. */
1709
- kind: 'session_start' | 'session_heartbeat' | 'session_end' | 'page_view';
1710
- session_id: string;
1711
- /** ISO timestamp of the event. */
1712
- ts: string;
1713
- /** Entry route for session_start; current route for page_view. */
1714
- route?: string | null;
1715
- /** document.referrer on session_start. */
1716
- referrer?: string | null;
1717
- /** Total page views in this session so far (updated on heartbeat/end). */
1718
- page_view_count?: number;
1719
- /** Device fingerprint hash — same token used in reports. */
1720
- reporter_token_hash?: string | null;
1721
- /** user_id_hash when the host app called Mushi.identify(). */
1722
- user_id_hash?: string | null;
1723
- user_agent?: string | null;
1724
- sdk_version?: string;
1725
- }
1726
- type MushiPropertyValue = string | number | boolean | null;
1727
- /** Configuration for `Mushi.track()` product analytics. */
1728
- interface MushiAnalyticsConfig {
1729
- /** Master switch (default true). */
1730
- enabled?: boolean;
1731
- /** 'implied' (default) sends immediately; 'required' buffers until setConsent('granted'). */
1732
- consent?: 'implied' | 'required';
1733
- /** 0..1, decided once per person (default 1). */
1734
- sampleRate?: number;
1735
- /** Honour navigator.doNotTrack / globalPrivacyControl (default true). */
1736
- respectDoNotTrack?: boolean;
1737
- /**
1738
- * Skip tracking in WebDriver-controlled browsers (Playwright, Puppeteer,
1739
- * Selenium), headless Chrome, Lighthouse and crawler user agents, so test
1740
- * runs and bots never count as users (default true). Set false to exercise
1741
- * analytics from an end-to-end test.
1742
- */
1743
- excludeBots?: boolean;
1744
- /** Emit `pageview` on history navigation (default false; sessions already record page views). */
1745
- autoPageviews?: boolean;
1746
- /** Flush cadence in ms (default 5000, min 1000). */
1747
- flushIntervalMs?: number;
1748
- /** Property keys allowed through the PII key filter. */
1749
- propertyAllowlist?: string[];
1750
- /** Which surface these events come from (default 'web'). */
1751
- surface?: 'web' | 'console' | 'docs' | 'cli' | 'mcp' | 'server' | 'mobile';
1752
- }
1753
- /** Wire shape for POST /v1/sdk/events. */
1754
- interface MushiProductEventPayload {
1755
- anon_id?: string | null;
1756
- user_id?: string | null;
1757
- user_traits?: Record<string, unknown> | null;
1758
- session_id?: string | null;
1759
- sdk_version?: string | null;
1760
- surface?: MushiAnalyticsConfig['surface'];
1761
- events: Array<{
1762
- name: string;
1763
- ts?: string;
1764
- properties?: Record<string, MushiPropertyValue>;
1765
- dedup_key?: string;
1766
- }>;
1767
- }
1768
- interface MushiApiResponse<T> {
1769
- ok: boolean;
1770
- data?: T;
1771
- /** `status` is the HTTP status when the server answered; absent for network errors. */
1772
- error?: {
1773
- code: string;
1774
- message: string;
1775
- status?: number;
1776
- };
1777
- }
1778
- interface MushiRuntimeSdkConfig {
1779
- enabled?: boolean;
1780
- version?: string | null;
1781
- widget?: MushiWidgetConfig;
1782
- capture?: MushiCaptureConfig;
1783
- native?: {
1784
- triggerMode?: 'shake' | 'button' | 'both' | 'none';
1785
- minDescriptionLength?: number;
1786
- };
1787
- /** When false, the widget skips background reporter-inbox polling. Default true. */
1788
- reporterNotificationsEnabled?: boolean;
1789
- }
1790
- interface MushiSdkVersionInfo {
1791
- package: string;
1792
- latest: string | null;
1793
- current?: string;
1794
- deprecated: boolean;
1795
- deprecationMessage?: string | null;
1796
- releasedAt?: string | null;
1797
- }
1798
- interface MushiReporterReport {
1799
- id: string;
1800
- status: string;
1801
- /** @deprecated No longer sent to reporters (Plan 018); internal triage only. */
1802
- category?: string;
1803
- /** @deprecated No longer sent to reporters (Plan 018); internal triage only. */
1804
- severity?: string | null;
1805
- /** Reporter-safe title (the summary, or the first line of the description). */
1806
- title?: string | null;
1807
- /** The type the reporter picked (`user_category`), if any. */
1808
- user_category?: string | null;
1809
- /** Page path the report was filed on. */
1810
- page?: string | null;
1811
- app_version?: string | null;
1812
- /** Signed, short-lived thumbnail URL; null without a screenshot. */
1813
- screenshot_thumb_url?: string | null;
1814
- /** Bucketed duplicate count: never a raw number. */
1815
- group_bucket?: 'none' | 'few' | 'many';
1816
- closed_reason?: string | null;
1817
- fixed_in_version?: string | null;
1818
- /** The developer asked a question and is waiting on the reporter. */
1819
- awaiting_reporter?: boolean;
1820
- /** True when this row is a report the reporter follows (theirs was a duplicate of it). */
1821
- followed?: boolean;
1822
- last_event_at?: string | null;
1823
- /** Template-rendered (or verbatim developer) text of the latest event. */
1824
- last_event_preview?: string | null;
1825
- summary?: string | null;
1826
- description?: string | null;
1827
- created_at: string;
1828
- last_admin_reply_at?: string | null;
1829
- last_reporter_reply_at?: string | null;
1830
- parent_report_id?: string | null;
1831
- verified_at?: string | null;
1832
- reopened_at?: string | null;
1833
- regression_count?: number;
1834
- unread_count?: number;
1835
- }
1836
- interface MushiReporterComment {
1837
- id: number;
1838
- author_kind: 'admin' | 'reporter';
1839
- author_name?: string | null;
1840
- body: string;
1841
- visible_to_reporter?: boolean;
1842
- created_at: string;
1843
- }
1844
- interface MushiHallOfFameEntry {
1845
- display_name: string;
1846
- email_hash: string | null;
1847
- tier_slug: string | null;
1848
- tier_name: string | null;
1849
- points_30d: number;
1850
- total_points: number;
1851
- }
1852
- /** A report filed by the current tester, across any project. */
1853
- interface MushiCrossAppReport {
1854
- id: string;
1855
- short_id: string | null;
1856
- title: string | null;
1857
- category: string;
1858
- status: string;
1859
- created_at: string;
1860
- updated_at: string;
1861
- project_id: string | null;
1862
- app_name: string | null;
1863
- app_slug: string | null;
1864
- /** Hostname from latest SDK heartbeat — used for favicon in cross-app list. */
1865
- app_domain?: string | null;
1866
- }
1867
- /** A single entry in the global tester leaderboard. */
1868
- interface MushiLeaderboardEntry {
1869
- tester_id: string;
1870
- public_handle: string | null;
1871
- display_name: string | null;
1872
- rank: number;
1873
- points_30d: number;
1874
- total_points: number;
1875
- badge_slug?: string | null;
1876
- }
1877
- /** The caller's global reputation snapshot. */
1878
- interface MushiTesterReputation {
1879
- tester_id: string;
1880
- public_handle: string | null;
1881
- display_name: string | null;
1882
- rank: number | null;
1883
- points_30d: number;
1884
- total_points: number;
1885
- }
1
+ import { M as MushiApiClient, a as MushiConfig, b as MushiPreFilterConfig, c as MushiReport, d as MushiOfflineConfig, e as MushiEnvironment, f as MushiAnalyticsConfig, g as MushiPropertyValue, h as MushiBreadcrumb } from './types-0j5BJ3aC.js';
2
+ export { i as MushiActivityEvent, j as MushiApiCascadeConfig, k as MushiApiResponse, l as MushiAssistantConfig, m as MushiAssistantReply, n as MushiAssistantStep, o as MushiBannerConfig, p as MushiBannerLink, q as MushiBetaChangelogEntry, r as MushiBetaModeConfig, s as MushiCaptureConfig, t as MushiCaptureEventInput, u as MushiCaptureExceptionOptions, v as MushiConsoleEntry, w as MushiCooldownConfig, x as MushiCrossAppReport, y as MushiCustomCategory, z as MushiDiagnosticsResult, A as MushiDiscoverInventoryConfig, B as MushiDiscoveryEventPayload, C as MushiEventHandler, D as MushiEventType, E as MushiHallOfFameEntry, F as MushiIntegrationsConfig, G as MushiLeaderboardEntry, H as MushiNetworkEntry, I as MushiNotificationsConfig, J as MushiOnDeviceClassifier, K as MushiOnDeviceClassifierInput, L as MushiOnDeviceClassifierResult, N as MushiPageContext, O as MushiPerformanceMetrics, P as MushiPreset, Q as MushiPrivacyConfig, R as MushiProactiveConfig, S as MushiProductEventPayload, T as MushiPushSubscriptionJSON, U as MushiReportBuilder, V as MushiReportCategory, W as MushiReportStatus, X as MushiReporterChannelUnavailable, Y as MushiReporterComment, Z as MushiReporterNotificationPrefs, _ as MushiReporterPrefsUpdate, $ as MushiReporterReport, a0 as MushiReporterReportDetail, a1 as MushiReporterTimelineItem, a2 as MushiReporterUpdates, a3 as MushiReputationResult, a4 as MushiRewardsConfig, a5 as MushiRuntimeSdkConfig, a6 as MushiSDKInstance, a7 as MushiSdkVersionInfo, a8 as MushiSelectedElement, a9 as MushiSentryConfig, aa as MushiSentryContext, ab as MushiSessionEventPayload, ac as MushiTesterReputation, ad as MushiTierResult, ae as MushiTimelineEntry, af as MushiTimelineKind, ag as MushiTracePropagationConfig, ah as MushiUrlMatcher, ai as MushiWidgetAnchor, aj as MushiWidgetConfig } from './types-0j5BJ3aC.js';
1886
3
 
1887
4
  /** Replay the last POST via keepalive/beacon during pagehide. */
1888
5
  declare function flushLastOutboundOnUnload(): boolean;
@@ -2490,6 +607,22 @@ declare const MUSHI_EVENTS: {
2490
607
  readonly surface: "server";
2491
608
  readonly required: readonly ["project_id", "plan"];
2492
609
  };
610
+ readonly repo_digest_created: {
611
+ readonly surface: "server";
612
+ readonly required: readonly ["project_id"];
613
+ };
614
+ readonly repo_diagram_generated: {
615
+ readonly surface: "server";
616
+ readonly required: readonly ["project_id"];
617
+ };
618
+ readonly repo_diagram_published: {
619
+ readonly surface: "server";
620
+ readonly required: readonly ["project_id"];
621
+ };
622
+ readonly public_diagram_viewed: {
623
+ readonly surface: "server";
624
+ readonly required: readonly ["project_id"];
625
+ };
2493
626
  readonly loop_impression: {
2494
627
  readonly surface: "web";
2495
628
  readonly required: readonly [];
@@ -3214,4 +1347,4 @@ declare function projectInitialsThemeIndex(projectId: string): number;
3214
1347
  */
3215
1348
  declare function readPageFaviconHref(): string | null;
3216
1349
 
3217
- export { ACTIVATION_EVENT, type AnalyticsBlockReason, type AnalyticsConsentState, type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, EVENT_NAME_RE, EVENT_PROPERTY_LIMITS, type EnvConfigDiagnostics, type EnvNearMiss, type EventTrackerOptions, HABIT_EVENTS, 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_BEACON_MAX_BYTES, MUSHI_BORDER, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_CONTROL_DISABLED, MUSHI_COPY, MUSHI_DURATION, MUSHI_EVENTS, MUSHI_EVENT_NAMES, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_LETTER_SPACING, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_OPACITY, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SHADOW_INK, MUSHI_SPACING, MUSHI_SURFACES, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiAnalyticsConfig, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type MushiBeaconEnvelope, 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 MushiErrorFilter, type MushiEventHandler, type MushiEventName, type MushiEventProperties, 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 MushiProductEventPayload, type MushiPropertyValue, 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 MushiSessionEventPayload, type MushiSurface, 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, type SessionTrackerOptions, analyticsBlockReason, buildBeaconEnvelope, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroyEventTracker, destroySessionTracker, diagnoseEnvConfig, dntActive, estimateJsonBytes, expandPreset, extractTunnelPath, faviconUrlCandidates, flushEvents, flushLastOutboundOnUnload, formatBytes, getBackoffDelay, getDeviceFingerprintHash, getEventAnonymousId, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initEventTracker, initSessionTracker, isAutomatedBrowser, isEventTrackingActive, isLikelyGenericFavicon, isMushiBeaconEnvelope, isPageUnloading, isSameOriginOrRelative, isUntrustedFaviconUrl, isValidEventName, markPageUnloading, matchesErrorFilter, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, onAnalyticsConsentChange, originToDomain, parseIdentityToken, parseRetryAfter, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, propertiesWithinByteLimit, readPageFaviconHref, resolveAnalyticsConsent, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveRequestBaseUrl, resolveWidgetAccent, safeWidgetHex, sanitizeEventProperties, scrubPii, scrubUrl, sendOnUnload, setAnalyticsConsent, setEventConsent, sha256Hex, shouldDropCapturedError, trackEvent, trackPageView, updateEventIdentity, updateSessionIdentity, validateConfig };
1350
+ export { ACTIVATION_EVENT, type AnalyticsBlockReason, type AnalyticsConsentState, type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, EVENT_NAME_RE, EVENT_PROPERTY_LIMITS, type EnvConfigDiagnostics, type EnvNearMiss, type EventTrackerOptions, HABIT_EVENTS, 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_BEACON_MAX_BYTES, MUSHI_BORDER, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_CONTROL_DISABLED, MUSHI_COPY, MUSHI_DURATION, MUSHI_EVENTS, MUSHI_EVENT_NAMES, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_LETTER_SPACING, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_OPACITY, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SHADOW_INK, MUSHI_SPACING, MUSHI_SURFACES, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, MushiAnalyticsConfig, MushiApiClient, type MushiBeaconEnvelope, MushiBreadcrumb, type MushiColorPalette, MushiConfig, MushiEnvironment, type MushiErrorFilter, type MushiEventName, type MushiEventProperties, type MushiIdentityClaims, type MushiInternalRequestKind, MushiOfflineConfig, MushiPreFilterConfig, MushiPropertyValue, type MushiRegion, MushiReport, type MushiSurface, type MushiThemeMode, type MushiTokenSnapshot, type NormalisedException, type OfflineQueue, type PayloadGuardResult, type PiiScrubberConfig, type PreFilterResult, type ProjectFaviconSource, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, type SessionTrackerOptions, analyticsBlockReason, buildBeaconEnvelope, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroyEventTracker, destroySessionTracker, diagnoseEnvConfig, dntActive, estimateJsonBytes, expandPreset, extractTunnelPath, faviconUrlCandidates, flushEvents, flushLastOutboundOnUnload, formatBytes, getBackoffDelay, getDeviceFingerprintHash, getEventAnonymousId, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initEventTracker, initSessionTracker, isAutomatedBrowser, isEventTrackingActive, isLikelyGenericFavicon, isMushiBeaconEnvelope, isPageUnloading, isSameOriginOrRelative, isUntrustedFaviconUrl, isValidEventName, markPageUnloading, matchesErrorFilter, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, onAnalyticsConsentChange, originToDomain, parseIdentityToken, parseRetryAfter, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, propertiesWithinByteLimit, readPageFaviconHref, resolveAnalyticsConsent, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveRequestBaseUrl, resolveWidgetAccent, safeWidgetHex, sanitizeEventProperties, scrubPii, scrubUrl, sendOnUnload, setAnalyticsConsent, setEventConsent, sha256Hex, shouldDropCapturedError, trackEvent, trackPageView, updateEventIdentity, updateSessionIdentity, validateConfig };