@mushi-mushi/core 1.28.0 → 1.29.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/README.md +1 -1
- package/dist/index.cjs +558 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +432 -8
- package/dist/index.d.ts +432 -8
- package/dist/index.js +535 -55
- package/dist/index.js.map +1 -1
- package/package.json +5 -13
- package/CODE_OF_CONDUCT.md +0 -51
- package/CONTRIBUTING.md +0 -226
- package/SECURITY.md +0 -359
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,22 @@ interface MushiConfig {
|
|
|
26
26
|
* host apps. Set false for fully static/offline deployments.
|
|
27
27
|
*/
|
|
28
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;
|
|
29
45
|
sentry?: MushiSentryConfig;
|
|
30
46
|
widget?: MushiWidgetConfig;
|
|
31
47
|
capture?: MushiCaptureConfig;
|
|
@@ -198,7 +214,21 @@ interface MushiWidgetConfig {
|
|
|
198
214
|
snapToEdge?: boolean;
|
|
199
215
|
axis?: 'both' | 'x' | 'y';
|
|
200
216
|
};
|
|
201
|
-
/**
|
|
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
|
+
*/
|
|
202
232
|
brandFooter?: boolean;
|
|
203
233
|
/** How the widget should surface SDK freshness warnings. Defaults to auto. */
|
|
204
234
|
outdatedBanner?: 'auto' | 'banner' | 'console-only' | 'off';
|
|
@@ -438,6 +468,24 @@ interface MushiCaptureConfig {
|
|
|
438
468
|
screenshotProvider?: () => Promise<string | null>;
|
|
439
469
|
elementSelector?: boolean;
|
|
440
470
|
replay?: 'sentry' | 'rrweb' | 'lite' | 'off';
|
|
471
|
+
/**
|
|
472
|
+
* How to load rrweb for `replay: 'rrweb'`. A published SDK cannot import
|
|
473
|
+
* rrweb itself: its bare `import('rrweb')` is invisible to your bundler, so
|
|
474
|
+
* rrweb never makes it into your build. Hand the import over and your
|
|
475
|
+
* bundler code-splits it like any other dynamic import. Install `rrweb`
|
|
476
|
+
* yourself; the chunk loads only for sessions sampled into replay.
|
|
477
|
+
*
|
|
478
|
+
* Without a loader the SDK uses a global `rrweb` (the UMD build from a
|
|
479
|
+
* script tag) when one exists, and otherwise records lite replay (clicks)
|
|
480
|
+
* and warns once in the console. Recording masks every input and every
|
|
481
|
+
* text node.
|
|
482
|
+
*
|
|
483
|
+
* @example
|
|
484
|
+
* capture: { replay: 'rrweb', rrweb: () => import('rrweb') }
|
|
485
|
+
*/
|
|
486
|
+
rrweb?: () => Promise<{
|
|
487
|
+
record?: unknown;
|
|
488
|
+
}>;
|
|
441
489
|
/**
|
|
442
490
|
* Mushi Mushi v2.1 (whitepaper §6 hybrid mode): passive inventory
|
|
443
491
|
* discovery. When enabled the SDK observes navigations and emits a
|
|
@@ -1385,8 +1433,23 @@ interface MushiSDKInstance {
|
|
|
1385
1433
|
* Manually record a host-defined activity event (e.g. 'lesson_completed').
|
|
1386
1434
|
* The SDK batches these and flushes to POST /v1/sdk/activity.
|
|
1387
1435
|
* No-op when rewards are disabled or the user has not opted in.
|
|
1436
|
+
* For product analytics (funnels, paths, people) use `track()` instead.
|
|
1388
1437
|
*/
|
|
1389
1438
|
recordActivity(action: string, metadata?: Record<string, unknown>): void;
|
|
1439
|
+
/**
|
|
1440
|
+
* Record a product-analytics event, e.g. `track('checkout_started', { plan: 'pro' })`.
|
|
1441
|
+
* Names must match `^[a-z][a-z0-9_]{1,63}$`; properties are flat
|
|
1442
|
+
* (string | number | boolean | null), PII-looking keys are dropped, and
|
|
1443
|
+
* every string value runs through the PII scrubber. Batched to
|
|
1444
|
+
* POST /v1/sdk/events. No-op under DNT/GPC, `analytics.enabled: false`,
|
|
1445
|
+
* or before consent when `analytics.consent === 'required'`.
|
|
1446
|
+
* Returns true when the event was queued.
|
|
1447
|
+
*/
|
|
1448
|
+
track(event: string, properties?: Record<string, MushiPropertyValue>): boolean;
|
|
1449
|
+
/** Grant or deny analytics consent (persisted per project in localStorage). */
|
|
1450
|
+
setConsent(state: 'granted' | 'denied'): void;
|
|
1451
|
+
/** The anonymous id analytics events are keyed on, or null when tracking is off. */
|
|
1452
|
+
getAnonymousId(): string | null;
|
|
1390
1453
|
/**
|
|
1391
1454
|
* Briefly animate the bug-report trigger button to draw the user's
|
|
1392
1455
|
* attention without opening the full widget. Ideal for subtle "feedback
|
|
@@ -1496,6 +1559,11 @@ interface MushiApiClient {
|
|
|
1496
1559
|
postSessionEvent(payload: MushiSessionEventPayload): Promise<MushiApiResponse<{
|
|
1497
1560
|
accepted: boolean;
|
|
1498
1561
|
}>>;
|
|
1562
|
+
/** POST /v1/sdk/events — batched product-analytics events (Mushi.track()). */
|
|
1563
|
+
postProductEvents(payload: MushiProductEventPayload): Promise<MushiApiResponse<{
|
|
1564
|
+
accepted: number;
|
|
1565
|
+
dropped: number;
|
|
1566
|
+
}>>;
|
|
1499
1567
|
listReporterReports(reporterToken: string): Promise<MushiApiResponse<{
|
|
1500
1568
|
reports: MushiReporterReport[];
|
|
1501
1569
|
}>>;
|
|
@@ -1648,12 +1716,56 @@ interface MushiSessionEventPayload {
|
|
|
1648
1716
|
user_agent?: string | null;
|
|
1649
1717
|
sdk_version?: string;
|
|
1650
1718
|
}
|
|
1719
|
+
type MushiPropertyValue = string | number | boolean | null;
|
|
1720
|
+
/** Configuration for `Mushi.track()` product analytics. */
|
|
1721
|
+
interface MushiAnalyticsConfig {
|
|
1722
|
+
/** Master switch (default true). */
|
|
1723
|
+
enabled?: boolean;
|
|
1724
|
+
/** 'implied' (default) sends immediately; 'required' buffers until setConsent('granted'). */
|
|
1725
|
+
consent?: 'implied' | 'required';
|
|
1726
|
+
/** 0..1, decided once per person (default 1). */
|
|
1727
|
+
sampleRate?: number;
|
|
1728
|
+
/** Honour navigator.doNotTrack / globalPrivacyControl (default true). */
|
|
1729
|
+
respectDoNotTrack?: boolean;
|
|
1730
|
+
/**
|
|
1731
|
+
* Skip tracking in WebDriver-controlled browsers (Playwright, Puppeteer,
|
|
1732
|
+
* Selenium), headless Chrome, Lighthouse and crawler user agents, so test
|
|
1733
|
+
* runs and bots never count as users (default true). Set false to exercise
|
|
1734
|
+
* analytics from an end-to-end test.
|
|
1735
|
+
*/
|
|
1736
|
+
excludeBots?: boolean;
|
|
1737
|
+
/** Emit `pageview` on history navigation (default false; sessions already record page views). */
|
|
1738
|
+
autoPageviews?: boolean;
|
|
1739
|
+
/** Flush cadence in ms (default 5000, min 1000). */
|
|
1740
|
+
flushIntervalMs?: number;
|
|
1741
|
+
/** Property keys allowed through the PII key filter. */
|
|
1742
|
+
propertyAllowlist?: string[];
|
|
1743
|
+
/** Which surface these events come from (default 'web'). */
|
|
1744
|
+
surface?: 'web' | 'console' | 'docs' | 'cli' | 'mcp' | 'server' | 'mobile';
|
|
1745
|
+
}
|
|
1746
|
+
/** Wire shape for POST /v1/sdk/events. */
|
|
1747
|
+
interface MushiProductEventPayload {
|
|
1748
|
+
anon_id?: string | null;
|
|
1749
|
+
user_id?: string | null;
|
|
1750
|
+
user_traits?: Record<string, unknown> | null;
|
|
1751
|
+
session_id?: string | null;
|
|
1752
|
+
sdk_version?: string | null;
|
|
1753
|
+
surface?: MushiAnalyticsConfig['surface'];
|
|
1754
|
+
events: Array<{
|
|
1755
|
+
name: string;
|
|
1756
|
+
ts?: string;
|
|
1757
|
+
properties?: Record<string, MushiPropertyValue>;
|
|
1758
|
+
dedup_key?: string;
|
|
1759
|
+
}>;
|
|
1760
|
+
}
|
|
1651
1761
|
interface MushiApiResponse<T> {
|
|
1652
1762
|
ok: boolean;
|
|
1653
1763
|
data?: T;
|
|
1764
|
+
/** `status` is the HTTP status when the server answered; absent for network errors. */
|
|
1654
1765
|
error?: {
|
|
1655
1766
|
code: string;
|
|
1656
1767
|
message: string;
|
|
1768
|
+
status?: number;
|
|
1657
1769
|
};
|
|
1658
1770
|
}
|
|
1659
1771
|
interface MushiRuntimeSdkConfig {
|
|
@@ -2159,31 +2271,62 @@ declare function getSessionId(): string;
|
|
|
2159
2271
|
* no offline queue, fire-and-forget after visibility-change.
|
|
2160
2272
|
*
|
|
2161
2273
|
* Privacy:
|
|
2274
|
+
* - Passes the same gate as product events (analytics-gate.ts): nothing is
|
|
2275
|
+
* sent when `analytics.enabled` is false, under DNT / GPC, in automation
|
|
2276
|
+
* or crawler browsers, or before consent is granted. A later
|
|
2277
|
+
* setConsent('granted') starts the session; 'denied' stops it mid-page.
|
|
2162
2278
|
* - No PII by default. `reporter_token_hash` is the same opaque device
|
|
2163
2279
|
* fingerprint already used in reports. `user_id_hash` is only set when
|
|
2164
|
-
* the host app
|
|
2280
|
+
* the host app identifies the user.
|
|
2281
|
+
* - Routes are sent as the pathname only and the referrer as its origin, so
|
|
2282
|
+
* query strings (reset tokens, emails in links) never leave the page.
|
|
2165
2283
|
* - Respects the SDK-level `trackSessions: false` opt-out option.
|
|
2166
|
-
*
|
|
2167
|
-
*
|
|
2284
|
+
*
|
|
2285
|
+
* SPA page views:
|
|
2286
|
+
* The history patch below decides push-vs-replace at wrap time (comparing
|
|
2287
|
+
* against `history.pushState` inside the wrapper never matches, because by
|
|
2288
|
+
* then that property is the wrapper). Hosts that already own a history
|
|
2289
|
+
* patch (`@mushi-mushi/web`'s shared one) pass `patchHistory: false` and
|
|
2290
|
+
* call `trackPageView()` themselves — a second wrapper assigned to
|
|
2291
|
+
* `history.pushState` silently discards this one, which is how the web SDK
|
|
2292
|
+
* recorded zero SPA page views across >1,000 sessions per project.
|
|
2168
2293
|
*/
|
|
2169
2294
|
|
|
2170
2295
|
interface SessionTrackerOptions {
|
|
2171
2296
|
client: MushiApiClient;
|
|
2172
2297
|
sdkVersion?: string;
|
|
2298
|
+
/** The raw per-project reporter token; the server stores only its sha256. */
|
|
2299
|
+
reporterToken?: string | null;
|
|
2300
|
+
/** @deprecated Renamed to `reporterToken` (it always carried the raw token, never a hash). */
|
|
2173
2301
|
reporterTokenHash?: string | null;
|
|
2174
2302
|
userIdHash?: string | null;
|
|
2303
|
+
/**
|
|
2304
|
+
* Install the built-in `history.pushState` / `popstate` patch that emits
|
|
2305
|
+
* `page_view` events. Default `true`. Pass `false` when the host already
|
|
2306
|
+
* owns a history patch and will call `trackPageView()` itself — stacking a
|
|
2307
|
+
* second wrapper on `history.pushState` is exactly how this tracker's page
|
|
2308
|
+
* views got overwritten and silently dropped in `@mushi-mushi/web`.
|
|
2309
|
+
*/
|
|
2310
|
+
patchHistory?: boolean;
|
|
2311
|
+
/** Project the stored analytics consent is keyed on (the SDK passes its projectId). */
|
|
2312
|
+
projectId?: string;
|
|
2313
|
+
/** The SDK's `analytics` block: sessions pass the same gate as product events. */
|
|
2314
|
+
analytics?: MushiAnalyticsConfig;
|
|
2175
2315
|
}
|
|
2176
2316
|
/**
|
|
2177
2317
|
* Initialise the session tracker. Call once at SDK init for web environments.
|
|
2178
2318
|
* Subsequent calls on the same page are no-ops (idempotent).
|
|
2179
2319
|
*
|
|
2180
|
-
* Emits: session_start
|
|
2181
|
-
* visibilitychange/pagehide, and page_view on history
|
|
2320
|
+
* Emits, once the analytics gate allows it: session_start, heartbeats every
|
|
2321
|
+
* minute, session_end on visibilitychange/pagehide, and page_view on history
|
|
2322
|
+
* API navigation. Under `consent: 'required'` nothing is sent until
|
|
2323
|
+
* setConsent('granted').
|
|
2182
2324
|
*/
|
|
2183
2325
|
declare function initSessionTracker(opts: SessionTrackerOptions): void;
|
|
2184
2326
|
/**
|
|
2185
2327
|
* Record a page view manually — call from framework router hooks where the
|
|
2186
|
-
* history patch may fire too early (e.g. React Router v7 loader transitions)
|
|
2328
|
+
* history patch may fire too early (e.g. React Router v7 loader transitions),
|
|
2329
|
+
* or from a host that initialised with `patchHistory: false`.
|
|
2187
2330
|
*/
|
|
2188
2331
|
declare function trackPageView(route?: string): void;
|
|
2189
2332
|
/** Update the user identity after a Mushi.identify() call. */
|
|
@@ -2191,6 +2334,287 @@ declare function updateSessionIdentity(userIdHash: string | null): void;
|
|
|
2191
2334
|
/** Tear down timers (e.g. in tests or SSR environments). */
|
|
2192
2335
|
declare function destroySessionTracker(): void;
|
|
2193
2336
|
|
|
2337
|
+
/**
|
|
2338
|
+
* FILE: packages/core/src/analytics-taxonomy.ts
|
|
2339
|
+
* PURPOSE: Single source of truth for Mushi's product-analytics vocabulary —
|
|
2340
|
+
* the events Mushi emits about its OWN funnel (dogfooding the SDK on
|
|
2341
|
+
* the landing site, docs, console, CLI and MCP) plus the validation
|
|
2342
|
+
* rules every `Mushi.track()` call obeys, for every project.
|
|
2343
|
+
*
|
|
2344
|
+
* Naming: `object_verb`, snake_case, past tense for completions, `_view` for
|
|
2345
|
+
* exposure, `_click` for intent. Every event carries `$surface`.
|
|
2346
|
+
*
|
|
2347
|
+
* Mirror: packages/server/supabase/functions/_shared/analytics-taxonomy.generated.ts
|
|
2348
|
+
* is generated from this file by `node scripts/gen-analytics-taxonomy.mjs`
|
|
2349
|
+
* (CI runs `--check`). Edge functions cannot import workspace packages.
|
|
2350
|
+
*/
|
|
2351
|
+
|
|
2352
|
+
/** Event names: lowercase, start with a letter, 2–64 chars. */
|
|
2353
|
+
declare const EVENT_NAME_RE: RegExp;
|
|
2354
|
+
/** Hard caps applied client- and server-side. */
|
|
2355
|
+
declare const EVENT_PROPERTY_LIMITS: {
|
|
2356
|
+
readonly maxKeys: 40;
|
|
2357
|
+
readonly maxKeyLength: 64;
|
|
2358
|
+
readonly maxValueLength: 256;
|
|
2359
|
+
readonly maxBytes: 8192;
|
|
2360
|
+
/** Client batch size before an immediate flush. */
|
|
2361
|
+
readonly maxClientBatch: 20;
|
|
2362
|
+
/** Server-side per-request ceiling. */
|
|
2363
|
+
readonly maxServerBatch: 50;
|
|
2364
|
+
/** Distinct event names per project before the server returns 422. */
|
|
2365
|
+
readonly maxEventNamesPerProject: 200;
|
|
2366
|
+
};
|
|
2367
|
+
declare const MUSHI_SURFACES: readonly ["web", "console", "docs", "cli", "mcp", "server", "mobile"];
|
|
2368
|
+
type MushiSurface = (typeof MUSHI_SURFACES)[number];
|
|
2369
|
+
/**
|
|
2370
|
+
* Mushi's own funnel vocabulary. One entry per line — the generator parses
|
|
2371
|
+
* this block line by line, so keep the `name: { surface: '…', required: […] }`
|
|
2372
|
+
* shape. An event with more than one emitter lists every surface:
|
|
2373
|
+
* `surface: ['console', 'mcp']`.
|
|
2374
|
+
*/
|
|
2375
|
+
declare const MUSHI_EVENTS: {
|
|
2376
|
+
readonly page_view: {
|
|
2377
|
+
readonly surface: readonly ["web", "docs", "console"];
|
|
2378
|
+
readonly required: readonly [];
|
|
2379
|
+
};
|
|
2380
|
+
readonly docs_page_view: {
|
|
2381
|
+
readonly surface: "docs";
|
|
2382
|
+
readonly required: readonly ["route"];
|
|
2383
|
+
};
|
|
2384
|
+
readonly landing_view: {
|
|
2385
|
+
readonly surface: "docs";
|
|
2386
|
+
readonly required: readonly [];
|
|
2387
|
+
};
|
|
2388
|
+
readonly cta_click: {
|
|
2389
|
+
readonly surface: "docs";
|
|
2390
|
+
readonly required: readonly ["cta_id", "location"];
|
|
2391
|
+
};
|
|
2392
|
+
readonly quickstart_view: {
|
|
2393
|
+
readonly surface: "docs";
|
|
2394
|
+
readonly required: readonly [];
|
|
2395
|
+
};
|
|
2396
|
+
readonly pricing_view: {
|
|
2397
|
+
readonly surface: "docs";
|
|
2398
|
+
readonly required: readonly [];
|
|
2399
|
+
};
|
|
2400
|
+
readonly connect_demo_click: {
|
|
2401
|
+
readonly surface: "docs";
|
|
2402
|
+
readonly required: readonly ["href"];
|
|
2403
|
+
};
|
|
2404
|
+
readonly signup_click: {
|
|
2405
|
+
readonly surface: "docs";
|
|
2406
|
+
readonly required: readonly ["href"];
|
|
2407
|
+
};
|
|
2408
|
+
readonly signup_completed: {
|
|
2409
|
+
readonly surface: "console";
|
|
2410
|
+
readonly required: readonly ["signup_source"];
|
|
2411
|
+
};
|
|
2412
|
+
readonly report_opened: {
|
|
2413
|
+
readonly surface: readonly ["console", "mcp"];
|
|
2414
|
+
readonly required: readonly ["report_id"];
|
|
2415
|
+
};
|
|
2416
|
+
readonly fix_context_pulled: {
|
|
2417
|
+
readonly surface: readonly ["console", "mcp"];
|
|
2418
|
+
readonly required: readonly ["report_id"];
|
|
2419
|
+
};
|
|
2420
|
+
readonly fix_dispatched: {
|
|
2421
|
+
readonly surface: readonly ["console", "mcp"];
|
|
2422
|
+
readonly required: readonly ["report_id", "agent"];
|
|
2423
|
+
};
|
|
2424
|
+
readonly invite_sent: {
|
|
2425
|
+
readonly surface: "console";
|
|
2426
|
+
readonly required: readonly [];
|
|
2427
|
+
};
|
|
2428
|
+
readonly upgrade_clicked: {
|
|
2429
|
+
readonly surface: "console";
|
|
2430
|
+
readonly required: readonly ["plan"];
|
|
2431
|
+
};
|
|
2432
|
+
readonly test_report_sent: {
|
|
2433
|
+
readonly surface: "console";
|
|
2434
|
+
readonly required: readonly ["project_id"];
|
|
2435
|
+
};
|
|
2436
|
+
readonly project_created: {
|
|
2437
|
+
readonly surface: "server";
|
|
2438
|
+
readonly required: readonly ["project_id"];
|
|
2439
|
+
};
|
|
2440
|
+
readonly key_minted: {
|
|
2441
|
+
readonly surface: "server";
|
|
2442
|
+
readonly required: readonly ["project_id"];
|
|
2443
|
+
};
|
|
2444
|
+
readonly first_report_received: {
|
|
2445
|
+
readonly surface: "server";
|
|
2446
|
+
readonly required: readonly ["project_id"];
|
|
2447
|
+
};
|
|
2448
|
+
readonly fix_merged: {
|
|
2449
|
+
readonly surface: "server";
|
|
2450
|
+
readonly required: readonly ["project_id"];
|
|
2451
|
+
};
|
|
2452
|
+
readonly upgrade_completed: {
|
|
2453
|
+
readonly surface: "server";
|
|
2454
|
+
readonly required: readonly ["project_id", "plan"];
|
|
2455
|
+
};
|
|
2456
|
+
readonly loop_impression: {
|
|
2457
|
+
readonly surface: "web";
|
|
2458
|
+
readonly required: readonly [];
|
|
2459
|
+
};
|
|
2460
|
+
readonly loop_click: {
|
|
2461
|
+
readonly surface: "web";
|
|
2462
|
+
readonly required: readonly [];
|
|
2463
|
+
};
|
|
2464
|
+
readonly loop_signup: {
|
|
2465
|
+
readonly surface: "console";
|
|
2466
|
+
readonly required: readonly ["ref"];
|
|
2467
|
+
};
|
|
2468
|
+
};
|
|
2469
|
+
type MushiEventName = keyof typeof MUSHI_EVENTS;
|
|
2470
|
+
declare const MUSHI_EVENT_NAMES: MushiEventName[];
|
|
2471
|
+
/** The aha event: a project receives its first SDK-originated report. */
|
|
2472
|
+
declare const ACTIVATION_EVENT: MushiEventName;
|
|
2473
|
+
/**
|
|
2474
|
+
* Any of these in a week counts as "diagnosis consumed" for the habit metric
|
|
2475
|
+
* (docs/plan-gtm.md: report opened, fix context pulled or fix dispatched, from
|
|
2476
|
+
* the console or an MCP client). company_funnel_weekly counts the same set.
|
|
2477
|
+
*/
|
|
2478
|
+
declare const HABIT_EVENTS: readonly MushiEventName[];
|
|
2479
|
+
type MushiEventProperties = Record<string, MushiPropertyValue>;
|
|
2480
|
+
declare function isValidEventName(name: unknown): name is string;
|
|
2481
|
+
interface SanitizedProperties {
|
|
2482
|
+
properties: MushiEventProperties;
|
|
2483
|
+
dropped: string[];
|
|
2484
|
+
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Enforce the property contract: depth 1, ≤ maxKeys, values ≤ maxValueLength,
|
|
2487
|
+
* PII-looking keys dropped unless allowlisted, `$`-prefixed keys dropped unless
|
|
2488
|
+
* `allowReserved` (the SDK sets those itself). Never throws.
|
|
2489
|
+
*/
|
|
2490
|
+
declare function sanitizeEventProperties(input: unknown, opts?: {
|
|
2491
|
+
allowlist?: readonly string[];
|
|
2492
|
+
allowReserved?: boolean;
|
|
2493
|
+
scrub?: (s: string) => string;
|
|
2494
|
+
}): SanitizedProperties;
|
|
2495
|
+
/** Approximate serialized size guard (UTF-16 length is a fine upper bound here). */
|
|
2496
|
+
declare function propertiesWithinByteLimit(properties: MushiEventProperties): boolean;
|
|
2497
|
+
|
|
2498
|
+
/**
|
|
2499
|
+
* FILE: packages/core/src/event-tracker.ts
|
|
2500
|
+
* PURPOSE: Client-side product-analytics tracker behind `Mushi.track()`.
|
|
2501
|
+
*
|
|
2502
|
+
* Batches named events and flushes them to POST /v1/sdk/events. Modelled on
|
|
2503
|
+
* session-tracker.ts (module state, idempotent init) but with a batch buffer,
|
|
2504
|
+
* an interval flush, a pagehide flush (the API client already switches to
|
|
2505
|
+
* keepalive during unload) and a small localStorage spill for unsent batches.
|
|
2506
|
+
*
|
|
2507
|
+
* Privacy:
|
|
2508
|
+
* - `anon_id` is the same opaque per-project reporter token the SDK already
|
|
2509
|
+
* uses for reports and sessions; identify() attaches the host's user id.
|
|
2510
|
+
* - Everything passes the shared gate in analytics-gate.ts (also used by the
|
|
2511
|
+
* session tracker): analytics.enabled, DNT / GPC, automation, consent.
|
|
2512
|
+
* - Nothing leaves the page until consent is 'granted'. That covers the
|
|
2513
|
+
* identify marker and a previous page's spill, not just track() events.
|
|
2514
|
+
* - `consent: 'required'` buffers up to 50 events in memory until
|
|
2515
|
+
* setConsent('granted'); 'denied' drops the buffer, the pending identify
|
|
2516
|
+
* and the spill, and disables tracking.
|
|
2517
|
+
* - Every string property runs through the caller-supplied PII scrubber and
|
|
2518
|
+
* the shared property contract in analytics-taxonomy.ts.
|
|
2519
|
+
* - `sampleRate` is decided once per person (hash of anon_id), never per
|
|
2520
|
+
* event, so funnels stay consistent.
|
|
2521
|
+
*/
|
|
2522
|
+
|
|
2523
|
+
interface EventTrackerOptions {
|
|
2524
|
+
client: MushiApiClient;
|
|
2525
|
+
projectId: string;
|
|
2526
|
+
/**
|
|
2527
|
+
* Anonymous id to key events on. Omit it: the tracker then uses its own
|
|
2528
|
+
* random per-project id, stored only after consent. Do not pass the reporter
|
|
2529
|
+
* token — it is a credential for the end user's report threads.
|
|
2530
|
+
*/
|
|
2531
|
+
anonId?: string | null;
|
|
2532
|
+
sdkVersion?: string;
|
|
2533
|
+
userId?: string | null;
|
|
2534
|
+
config?: MushiAnalyticsConfig;
|
|
2535
|
+
/** PII scrubber for string values (the SDK passes createPiiScrubber().scrub). */
|
|
2536
|
+
scrub?: (s: string) => string;
|
|
2537
|
+
/** Optional session id resolver (the SDK passes getSessionId). */
|
|
2538
|
+
getSessionId?: () => string;
|
|
2539
|
+
}
|
|
2540
|
+
/**
|
|
2541
|
+
* True when tracking is active for this person (enabled, consented, sampled
|
|
2542
|
+
* in, no DNT / GPC, not automation). The gate leaves the tracker
|
|
2543
|
+
* uninitialised when it blocks, so `_initialized` covers the first part.
|
|
2544
|
+
*/
|
|
2545
|
+
declare function isEventTrackingActive(): boolean;
|
|
2546
|
+
/** The anonymous id events are keyed on, or null when tracking is off. */
|
|
2547
|
+
declare function getEventAnonymousId(): string | null;
|
|
2548
|
+
/**
|
|
2549
|
+
* Initialise the tracker. Idempotent per page. Safe to call in SSR (no-op).
|
|
2550
|
+
*/
|
|
2551
|
+
declare function initEventTracker(opts: EventTrackerOptions): void;
|
|
2552
|
+
/**
|
|
2553
|
+
* Record a named event. Invalid names are dropped; properties are sanitised
|
|
2554
|
+
* per analytics-taxonomy.ts. Returns true when the event was queued.
|
|
2555
|
+
*/
|
|
2556
|
+
declare function trackEvent(name: string, properties?: Record<string, unknown>, opts?: {
|
|
2557
|
+
dedupKey?: string;
|
|
2558
|
+
ts?: string;
|
|
2559
|
+
reserved?: MushiEventProperties;
|
|
2560
|
+
}): boolean;
|
|
2561
|
+
/**
|
|
2562
|
+
* Grant or deny consent. Persisted per project and broadcast through the
|
|
2563
|
+
* shared gate, so the session tracker follows the same decision. Granting
|
|
2564
|
+
* releases the pending buffer and identify; denying drops them.
|
|
2565
|
+
*/
|
|
2566
|
+
declare function setEventConsent(state: 'granted' | 'denied'): void;
|
|
2567
|
+
/**
|
|
2568
|
+
* Called from identify(): stitches anonymous history to the person. The
|
|
2569
|
+
* identify marker is held until consent is granted and dropped on denial.
|
|
2570
|
+
*/
|
|
2571
|
+
declare function updateEventIdentity(userId: string | null, traits?: Record<string, unknown> | null): void;
|
|
2572
|
+
/** Flush immediately (tests, before navigation). */
|
|
2573
|
+
declare function flushEvents(): Promise<void>;
|
|
2574
|
+
/** Tear down timers (tests / SSR). */
|
|
2575
|
+
declare function destroyEventTracker(): void;
|
|
2576
|
+
|
|
2577
|
+
/**
|
|
2578
|
+
* FILE: packages/core/src/analytics-gate.ts
|
|
2579
|
+
* PURPOSE: The one privacy gate every analytics surface in the browser SDK
|
|
2580
|
+
* passes through: product events (`Mushi.track()`, `identify()`) and
|
|
2581
|
+
* session lifecycle tracking alike.
|
|
2582
|
+
*
|
|
2583
|
+
* A surface may send only when all of these hold:
|
|
2584
|
+
* - `analytics.enabled` is not false;
|
|
2585
|
+
* - Do Not Track / Global Privacy Control is off, or the host opted out of
|
|
2586
|
+
* honouring it (`respectDoNotTrack: false`);
|
|
2587
|
+
* - the browser is not automation or a crawler (`excludeBots: false` opts
|
|
2588
|
+
* back in, e.g. to exercise analytics from Playwright);
|
|
2589
|
+
* - consent resolves to 'granted'. 'implied' mode grants unless the visitor
|
|
2590
|
+
* stored a denial; 'required' mode waits for `setConsent('granted')`.
|
|
2591
|
+
*
|
|
2592
|
+
* The first three are fixed for the page, so `analyticsBlockReason()` is read
|
|
2593
|
+
* once at tracker init. Consent can change at any time, so trackers resolve it
|
|
2594
|
+
* from storage at init (the storage is the source of truth, which keeps the
|
|
2595
|
+
* result independent of which tracker starts first) and then follow
|
|
2596
|
+
* `onAnalyticsConsentChange()`.
|
|
2597
|
+
*/
|
|
2598
|
+
|
|
2599
|
+
type AnalyticsConsentState = 'granted' | 'denied' | 'pending';
|
|
2600
|
+
type AnalyticsBlockReason = 'disabled' | 'dnt' | 'automation';
|
|
2601
|
+
type ConsentListener = (state: 'granted' | 'denied') => void;
|
|
2602
|
+
/** True when the browser signals Do Not Track or Global Privacy Control. */
|
|
2603
|
+
declare function dntActive(): boolean;
|
|
2604
|
+
/** True for WebDriver-controlled browsers (Playwright, Puppeteer, Selenium) and crawler user agents. */
|
|
2605
|
+
declare function isAutomatedBrowser(): boolean;
|
|
2606
|
+
/**
|
|
2607
|
+
* Why analytics may not run on this page at all, or null when only consent
|
|
2608
|
+
* stands between the tracker and the network.
|
|
2609
|
+
*/
|
|
2610
|
+
declare function analyticsBlockReason(config?: MushiAnalyticsConfig): AnalyticsBlockReason | null;
|
|
2611
|
+
/** Consent for this page: a stored choice wins, otherwise the configured mode decides. */
|
|
2612
|
+
declare function resolveAnalyticsConsent(projectId: string, config?: MushiAnalyticsConfig): AnalyticsConsentState;
|
|
2613
|
+
/** Persist a consent decision and tell every subscribed tracker. */
|
|
2614
|
+
declare function setAnalyticsConsent(projectId: string, state: 'granted' | 'denied'): void;
|
|
2615
|
+
/** Follow consent changes. Returns the unsubscribe function. */
|
|
2616
|
+
declare function onAnalyticsConsentChange(listener: ConsentListener): () => void;
|
|
2617
|
+
|
|
2194
2618
|
interface RateLimiterConfig {
|
|
2195
2619
|
maxBurst?: number;
|
|
2196
2620
|
refillRate?: number;
|
|
@@ -2753,4 +3177,4 @@ declare function projectInitialsThemeIndex(projectId: string): number;
|
|
|
2753
3177
|
*/
|
|
2754
3178
|
declare function readPageFaviconHref(): string | null;
|
|
2755
3179
|
|
|
2756
|
-
export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, type EnvConfigDiagnostics, type EnvNearMiss, 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_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_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type 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 MushiEventType, type MushiHallOfFameEntry, type MushiIdentityClaims, type MushiIntegrationsConfig, type MushiInternalRequestKind, type MushiLeaderboardEntry, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPageContext, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiPreset, type MushiPrivacyConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiReporterComment, type MushiReporterReport, type MushiReputationResult, type MushiRewardsConfig, type MushiRuntimeSdkConfig, type MushiSDKInstance, type MushiSdkVersionInfo, type MushiSelectedElement, type MushiSentryConfig, type MushiSentryContext, type MushiSessionEventPayload, 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, buildBeaconEnvelope, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroySessionTracker, diagnoseEnvConfig, estimateJsonBytes, expandPreset, extractTunnelPath, faviconUrlCandidates, flushLastOutboundOnUnload, formatBytes, getBackoffDelay, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initSessionTracker, isLikelyGenericFavicon, isMushiBeaconEnvelope, isPageUnloading, isSameOriginOrRelative, isUntrustedFaviconUrl, markPageUnloading, matchesErrorFilter, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, parseRetryAfter, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveRequestBaseUrl, resolveWidgetAccent, safeWidgetHex, scrubPii, scrubUrl, sendOnUnload, sha256Hex, shouldDropCapturedError, trackPageView, updateSessionIdentity, validateConfig };
|
|
3180
|
+
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 };
|