@mushi-mushi/core 1.27.2 → 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/dist/index.js CHANGED
@@ -84,7 +84,92 @@ async function hmacSha256Hex(secret, value) {
84
84
  return bytesToHex(result);
85
85
  }
86
86
 
87
+ // src/unload-transport.ts
88
+ var MUSHI_BEACON_MAX_BYTES = 60 * 1024;
89
+ function isMushiBeaconEnvelope(value) {
90
+ if (!value || typeof value !== "object") return false;
91
+ const rec = value;
92
+ return rec.mushiBeacon === true && typeof rec.path === "string" && rec.headers !== null && typeof rec.headers === "object";
93
+ }
94
+ function buildBeaconEnvelope(opts) {
95
+ return {
96
+ mushiBeacon: true,
97
+ path: opts.path,
98
+ headers: opts.headers,
99
+ body: opts.body
100
+ };
101
+ }
102
+ function isSameOriginOrRelative(url, origin = typeof location !== "undefined" ? location.origin : "") {
103
+ if (!url) return false;
104
+ if (url.startsWith("/")) return true;
105
+ if (!origin) return false;
106
+ try {
107
+ return new URL(url, origin).origin === origin;
108
+ } catch {
109
+ return false;
110
+ }
111
+ }
112
+ function extractTunnelPath(url) {
113
+ try {
114
+ const parsed = url.startsWith("/") ? new URL(url, "https://tunnel.local") : new URL(url);
115
+ return `${parsed.pathname}${parsed.search}`;
116
+ } catch {
117
+ return url;
118
+ }
119
+ }
120
+ function sendOnUnload(opts) {
121
+ const fetchImpl = opts.fetchImpl ?? (typeof fetch === "function" ? fetch : void 0);
122
+ if (fetchImpl) {
123
+ try {
124
+ void fetchImpl(opts.url, {
125
+ method: "POST",
126
+ headers: {
127
+ "Content-Type": "application/json",
128
+ ...opts.headers
129
+ },
130
+ body: opts.body,
131
+ keepalive: true
132
+ });
133
+ return true;
134
+ } catch {
135
+ }
136
+ }
137
+ const beacon = opts.sendBeacon ?? (typeof navigator !== "undefined" ? navigator.sendBeacon?.bind(navigator) : void 0);
138
+ if (!beacon || !isSameOriginOrRelative(opts.url)) return false;
139
+ let parsedBody = opts.body;
140
+ try {
141
+ parsedBody = JSON.parse(opts.body);
142
+ } catch {
143
+ parsedBody = opts.body;
144
+ }
145
+ const envelope = JSON.stringify(
146
+ buildBeaconEnvelope({
147
+ path: opts.path ?? extractTunnelPath(opts.url),
148
+ headers: opts.headers,
149
+ body: parsedBody
150
+ })
151
+ );
152
+ if (envelope.length > MUSHI_BEACON_MAX_BYTES) return false;
153
+ try {
154
+ return beacon(opts.url, new Blob([envelope], { type: "application/json" }));
155
+ } catch {
156
+ return false;
157
+ }
158
+ }
159
+ var pageUnloading = false;
160
+ function markPageUnloading() {
161
+ pageUnloading = true;
162
+ }
163
+ function isPageUnloading() {
164
+ return pageUnloading;
165
+ }
166
+
87
167
  // src/api-client.ts
168
+ var lastOutbound = null;
169
+ function flushLastOutboundOnUnload() {
170
+ if (!lastOutbound) return false;
171
+ return sendOnUnload(lastOutbound);
172
+ }
88
173
  var _credWarningEmitted = false;
89
174
  var MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
90
175
  var MUSHI_PROJECT_HEADER = "X-Mushi-Project";
@@ -105,6 +190,11 @@ function buildSdkIngestHeaders(opts) {
105
190
  var DEFAULT_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api";
106
191
  var MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
107
192
  var MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
193
+ function resolveRequestBaseUrl(apiEndpoint, tunnel) {
194
+ const trimmedTunnel = tunnel?.trim();
195
+ if (trimmedTunnel) return trimmedTunnel.replace(/\/$/, "");
196
+ return (apiEndpoint ?? DEFAULT_API_ENDPOINT).replace(/\/$/, "");
197
+ }
108
198
  var DEFAULT_TIMEOUT = 1e4;
109
199
  var DEFAULT_MAX_RETRIES = 2;
110
200
  var DEFAULT_CIRCUIT_THRESHOLD = 4;
@@ -115,6 +205,7 @@ function createApiClient(options) {
115
205
  projectId,
116
206
  apiKey,
117
207
  apiEndpoint = DEFAULT_API_ENDPOINT,
208
+ tunnel,
118
209
  timeout = DEFAULT_TIMEOUT,
119
210
  maxRetries = DEFAULT_MAX_RETRIES,
120
211
  getUserToken,
@@ -122,7 +213,7 @@ function createApiClient(options) {
122
213
  sdkVersion,
123
214
  circuitBreaker
124
215
  } = options;
125
- let baseUrl = apiEndpoint.replace(/\/$/, "");
216
+ let baseUrl = resolveRequestBaseUrl(apiEndpoint, tunnel);
126
217
  const cbEnabled = circuitBreaker?.enabled !== false;
127
218
  const cbThreshold = Math.max(1, circuitBreaker?.threshold ?? DEFAULT_CIRCUIT_THRESHOLD);
128
219
  const cbCooldownMs = Math.max(1e3, circuitBreaker?.cooldownMs ?? DEFAULT_CIRCUIT_COOLDOWN_MS);
@@ -146,21 +237,27 @@ function createApiClient(options) {
146
237
  const controller = new AbortController();
147
238
  const timer = setTimeout(() => controller.abort(), timeout);
148
239
  const userToken = getUserToken?.() ?? null;
240
+ const headers = {
241
+ ...buildSdkIngestHeaders({
242
+ apiKey,
243
+ projectId,
244
+ sdkPackage,
245
+ sdkVersion,
246
+ userToken,
247
+ internalKind
248
+ }),
249
+ ...extraHeaders
250
+ };
251
+ const serialized = body ? JSON.stringify(body) : void 0;
252
+ if (serialized && method !== "GET") {
253
+ lastOutbound = { url, headers, body: serialized, path };
254
+ }
149
255
  try {
150
256
  const response = await fetch(url, {
151
257
  method,
152
- headers: {
153
- ...buildSdkIngestHeaders({
154
- apiKey,
155
- projectId,
156
- sdkPackage,
157
- sdkVersion,
158
- userToken,
159
- internalKind
160
- }),
161
- ...extraHeaders
162
- },
163
- body: body ? JSON.stringify(body) : void 0,
258
+ headers,
259
+ body: serialized,
260
+ keepalive: isPageUnloading(),
164
261
  signal: controller.signal,
165
262
  ...internalKind ? { [MUSHI_INTERNAL_INIT_MARKER]: internalKind } : {}
166
263
  });
@@ -198,7 +295,8 @@ function createApiClient(options) {
198
295
  ok: false,
199
296
  error: {
200
297
  code: errorBody.error?.code || `HTTP_${response.status}`,
201
- message: errorBody.error?.message || errorBody.message || `HTTP ${response.status} error`
298
+ message: errorBody.error?.message || errorBody.message || `HTTP ${response.status} error`,
299
+ status: response.status
202
300
  }
203
301
  };
204
302
  }
@@ -241,6 +339,7 @@ function createApiClient(options) {
241
339
  "X-Reporter-Hmac": hmac
242
340
  },
243
341
  body: body ? JSON.stringify(body) : void 0,
342
+ keepalive: isPageUnloading(),
244
343
  [MUSHI_INTERNAL_INIT_MARKER]: "reporter-poll"
245
344
  });
246
345
  if (!response.ok) {
@@ -374,6 +473,18 @@ function createApiClient(options) {
374
473
  "discovery"
375
474
  );
376
475
  },
476
+ /** POST /v1/sdk/events — batched product-analytics events (Mushi.track()).
477
+ * Best-effort (1 retry); the event tracker spills unsent batches to
478
+ * localStorage and replays them on the next page load. */
479
+ async postProductEvents(payload) {
480
+ return request(
481
+ "POST",
482
+ "/v1/sdk/events",
483
+ payload,
484
+ 1,
485
+ "discovery"
486
+ );
487
+ },
377
488
  async submitActivity(userId, events, opts) {
378
489
  return request(
379
490
  "POST",
@@ -500,7 +611,7 @@ function sleep(ms) {
500
611
  function getBackoffDelay(attempt) {
501
612
  return Math.min(1e3 * 2 ** attempt + Math.random() * 500, 1e4);
502
613
  }
503
- function parseRetryAfter(value, now2 = Date.now()) {
614
+ function parseRetryAfter(value, now3 = Date.now()) {
504
615
  if (!value) return null;
505
616
  const raw = value.trim();
506
617
  if (!raw) return null;
@@ -508,7 +619,7 @@ function parseRetryAfter(value, now2 = Date.now()) {
508
619
  if (Number.isFinite(seconds)) return seconds < 0 ? null : seconds * 1e3;
509
620
  const at = Date.parse(raw);
510
621
  if (Number.isNaN(at)) return null;
511
- return Math.max(at - now2, 0);
622
+ return Math.max(at - now3, 0);
512
623
  }
513
624
  function isRetryable(error) {
514
625
  if (error instanceof DOMException && error.name === "AbortError") return true;
@@ -516,6 +627,32 @@ function isRetryable(error) {
516
627
  return false;
517
628
  }
518
629
 
630
+ // src/error-filters.ts
631
+ function matchesErrorFilter(value, filters) {
632
+ if (!value || !filters || filters.length === 0) return false;
633
+ for (const filter of filters) {
634
+ if (typeof filter === "string") {
635
+ if (value.includes(filter)) return true;
636
+ continue;
637
+ }
638
+ try {
639
+ if (filter.test(value)) return true;
640
+ } catch {
641
+ }
642
+ }
643
+ return false;
644
+ }
645
+ function shouldDropCapturedError(input) {
646
+ if (matchesErrorFilter(input.message, input.ignoreErrors)) return true;
647
+ const filename = input.filename?.trim() || "";
648
+ if (filename && matchesErrorFilter(filename, input.denyUrls)) return true;
649
+ if (input.allowUrls && input.allowUrls.length > 0) {
650
+ if (!filename) return true;
651
+ if (!matchesErrorFilter(filename, input.allowUrls)) return true;
652
+ }
653
+ return false;
654
+ }
655
+
519
656
  // src/region.ts
520
657
  var REGION_ENDPOINTS = {
521
658
  us: DEFAULT_API_ENDPOINT,
@@ -694,11 +831,14 @@ var KNOWN_CONFIG_KEYS = [
694
831
  "projectId",
695
832
  "apiKey",
696
833
  "apiEndpoint",
834
+ "tunnel",
697
835
  "timeout",
698
836
  "maxRetries",
699
837
  "circuitBreaker",
700
838
  "preset",
701
839
  "runtimeConfig",
840
+ "analytics",
841
+ "trackSessions",
702
842
  "sentry",
703
843
  "widget",
704
844
  "capture",
@@ -713,8 +853,13 @@ var KNOWN_CONFIG_KEYS = [
713
853
  "enabled",
714
854
  "appVersion",
715
855
  "sampleRate",
856
+ "replaySampleRate",
857
+ "replaysOnErrorSampleRate",
716
858
  "beforeSend",
717
859
  "beforeSendFeedback",
860
+ "ignoreErrors",
861
+ "denyUrls",
862
+ "allowUrls",
718
863
  "onCrashedLastRun"
719
864
  ];
720
865
  function presetDefaults(preset) {
@@ -785,23 +930,23 @@ function presetDefaults(preset) {
785
930
  }
786
931
  }
787
932
  function expandPreset(config) {
788
- const defaults = presetDefaults(config.preset);
789
- if (!defaults) return config;
933
+ const defaults2 = presetDefaults(config.preset);
934
+ if (!defaults2) return config;
790
935
  return {
791
936
  ...config,
792
937
  widget: {
793
- ...defaults.widget,
938
+ ...defaults2.widget,
794
939
  ...config.widget
795
940
  },
796
941
  capture: {
797
- ...defaults.capture,
942
+ ...defaults2.capture,
798
943
  ...config.capture
799
944
  },
800
945
  proactive: {
801
- ...defaults.proactive,
946
+ ...defaults2.proactive,
802
947
  ...config.proactive,
803
948
  cooldown: {
804
- ...defaults.proactive?.cooldown,
949
+ ...defaults2.proactive?.cooldown,
805
950
  ...config.proactive?.cooldown
806
951
  }
807
952
  }
@@ -1212,12 +1357,12 @@ function createOfflineQueue(config = {}) {
1212
1357
  const n = row.attempts;
1213
1358
  return typeof n === "number" && Number.isFinite(n) ? n : 0;
1214
1359
  }
1215
- function isExpired(row, now2) {
1360
+ function isExpired(row, now3) {
1216
1361
  const queuedAt = row.queuedAt;
1217
1362
  if (!queuedAt) return false;
1218
1363
  const ts = Date.parse(queuedAt);
1219
1364
  if (Number.isNaN(ts)) return false;
1220
- return now2 - ts > MAX_QUEUE_AGE_MS;
1365
+ return now3 - ts > MAX_QUEUE_AGE_MS;
1221
1366
  }
1222
1367
  function detectBackend() {
1223
1368
  if (backendType) return backendType;
@@ -1404,7 +1549,7 @@ function createOfflineQueue(config = {}) {
1404
1549
  await lsEnqueue(report);
1405
1550
  return "localstorage";
1406
1551
  }
1407
- async function enqueue(report) {
1552
+ async function enqueue2(report) {
1408
1553
  if (!enabled) return;
1409
1554
  const currentSize = await size();
1410
1555
  if (currentSize >= maxQueueSize) {
@@ -1422,10 +1567,10 @@ function createOfflineQueue(config = {}) {
1422
1567
  async function runFlush(client) {
1423
1568
  const { backend, rows: storedRows } = await readRows();
1424
1569
  let rows = storedRows;
1425
- const now2 = Date.now();
1570
+ const now3 = Date.now();
1426
1571
  const fresh = [];
1427
1572
  for (const row of rows) {
1428
- if (isExpired(row, now2)) {
1573
+ if (isExpired(row, now3)) {
1429
1574
  const rowId = row.id;
1430
1575
  await removeRow(backend, rowId);
1431
1576
  queueLog.debug("Offline queue: evicting stale report", { id: rowId });
@@ -1573,7 +1718,7 @@ function createOfflineQueue(config = {}) {
1573
1718
  syncCleanup?.();
1574
1719
  syncCleanup = null;
1575
1720
  }
1576
- return { enqueue, flush, size, clear, startAutoSync, stopAutoSync };
1721
+ return { enqueue: enqueue2, flush, size, clear, startAutoSync, stopAutoSync };
1577
1722
  }
1578
1723
 
1579
1724
  // src/environment.ts
@@ -1915,21 +2060,94 @@ function randomSuffix() {
1915
2060
  return n.toString(36).padStart(6, "0").slice(0, 6);
1916
2061
  }
1917
2062
 
2063
+ // src/analytics-gate.ts
2064
+ var AUTOMATED_UA_RE = /HeadlessChrome|PhantomJS|Lighthouse|\bbot\b|bot[/-]|crawler|spider/i;
2065
+ function consentKey(projectId) {
2066
+ return "mushi_events_consent_" + projectId;
2067
+ }
2068
+ var listeners = /* @__PURE__ */ new Set();
2069
+ function dntActive() {
2070
+ if (typeof navigator === "undefined") return false;
2071
+ const nav = navigator;
2072
+ if (nav.globalPrivacyControl === true) return true;
2073
+ const winDnt = typeof window !== "undefined" ? window.doNotTrack : void 0;
2074
+ const dnt = nav.doNotTrack ?? nav.msDoNotTrack ?? winDnt;
2075
+ return dnt === "1" || dnt === "yes";
2076
+ }
2077
+ function isAutomatedBrowser() {
2078
+ if (typeof navigator === "undefined") return false;
2079
+ if (navigator.webdriver === true) return true;
2080
+ return AUTOMATED_UA_RE.test(navigator.userAgent ?? "");
2081
+ }
2082
+ function analyticsBlockReason(config) {
2083
+ if (config?.enabled === false) return "disabled";
2084
+ if (config?.respectDoNotTrack !== false && dntActive()) return "dnt";
2085
+ if (config?.excludeBots !== false && isAutomatedBrowser()) return "automation";
2086
+ return null;
2087
+ }
2088
+ function readStoredConsent(projectId) {
2089
+ if (!projectId) return null;
2090
+ try {
2091
+ const v = localStorage.getItem(consentKey(projectId));
2092
+ return v === "granted" || v === "denied" ? v : null;
2093
+ } catch {
2094
+ return null;
2095
+ }
2096
+ }
2097
+ function writeStoredConsent(projectId, state) {
2098
+ if (!projectId) return;
2099
+ try {
2100
+ localStorage.setItem(consentKey(projectId), state);
2101
+ } catch {
2102
+ }
2103
+ }
2104
+ function resolveAnalyticsConsent(projectId, config) {
2105
+ const stored = readStoredConsent(projectId);
2106
+ if (config?.consent === "required") return stored ?? "pending";
2107
+ return stored === "denied" ? "denied" : "granted";
2108
+ }
2109
+ function setAnalyticsConsent(projectId, state) {
2110
+ writeStoredConsent(projectId, state);
2111
+ for (const listener of [...listeners]) {
2112
+ try {
2113
+ listener(state);
2114
+ } catch {
2115
+ }
2116
+ }
2117
+ }
2118
+ function onAnalyticsConsentChange(listener) {
2119
+ listeners.add(listener);
2120
+ return () => {
2121
+ listeners.delete(listener);
2122
+ };
2123
+ }
2124
+
1918
2125
  // src/session-tracker.ts
1919
2126
  var HEARTBEAT_INTERVAL_MS = 6e4;
1920
2127
  var _client = null;
1921
2128
  var _sdkVersion;
1922
2129
  var _userIdHash = null;
1923
- var _reporterTokenHash = null;
2130
+ var _reporterToken = null;
1924
2131
  var _pageViewCount = 0;
1925
2132
  var _heartbeatTimer = null;
1926
2133
  var _initialized = false;
2134
+ var _active = false;
2135
+ var _started = false;
2136
+ var _unsubscribeConsent = null;
1927
2137
  function now() {
1928
2138
  return (/* @__PURE__ */ new Date()).toISOString();
1929
2139
  }
1930
2140
  function currentRoute() {
1931
2141
  if (typeof window === "undefined") return "";
1932
- return window.location.pathname + window.location.search;
2142
+ return window.location.pathname;
2143
+ }
2144
+ function referrerOrigin() {
2145
+ if (typeof document === "undefined" || !document.referrer) return null;
2146
+ try {
2147
+ return new URL(document.referrer).origin;
2148
+ } catch {
2149
+ return null;
2150
+ }
1933
2151
  }
1934
2152
  function userAgent() {
1935
2153
  if (typeof navigator === "undefined") return null;
@@ -1941,7 +2159,8 @@ function buildPayload(kind, extra) {
1941
2159
  session_id: getSessionId(),
1942
2160
  ts: now(),
1943
2161
  page_view_count: _pageViewCount,
1944
- reporter_token_hash: _reporterTokenHash,
2162
+ // Wire name kept for older servers; the value is the raw token (hashed server-side).
2163
+ reporter_token_hash: _reporterToken,
1945
2164
  user_id_hash: _userIdHash,
1946
2165
  user_agent: userAgent(),
1947
2166
  sdk_version: _sdkVersion,
@@ -1949,26 +2168,42 @@ function buildPayload(kind, extra) {
1949
2168
  };
1950
2169
  }
1951
2170
  function send(payload) {
1952
- if (!_client) return;
2171
+ if (!_client || !_active) return;
1953
2172
  _client.postSessionEvent(payload).catch(() => {
1954
2173
  });
1955
2174
  }
2175
+ function recordPageView(route) {
2176
+ if (!_active) return;
2177
+ _pageViewCount += 1;
2178
+ send(buildPayload("page_view", { route }));
2179
+ }
2180
+ function activate() {
2181
+ if (_active || !_initialized) return;
2182
+ _active = true;
2183
+ if (!_started) {
2184
+ _started = true;
2185
+ _pageViewCount = 1;
2186
+ send(buildPayload("session_start", { route: currentRoute(), referrer: referrerOrigin() }));
2187
+ }
2188
+ _heartbeatTimer = setInterval(() => {
2189
+ send(buildPayload("session_heartbeat", { route: currentRoute() }));
2190
+ }, HEARTBEAT_INTERVAL_MS);
2191
+ }
2192
+ function deactivate() {
2193
+ _active = false;
2194
+ if (_heartbeatTimer != null) {
2195
+ clearInterval(_heartbeatTimer);
2196
+ _heartbeatTimer = null;
2197
+ }
2198
+ }
1956
2199
  function initSessionTracker(opts) {
1957
2200
  if (_initialized || typeof window === "undefined") return;
2201
+ if (analyticsBlockReason(opts.analytics) !== null) return;
1958
2202
  _initialized = true;
1959
2203
  _client = opts.client;
1960
2204
  _sdkVersion = opts.sdkVersion;
1961
- _reporterTokenHash = opts.reporterTokenHash ?? null;
2205
+ _reporterToken = opts.reporterToken ?? opts.reporterTokenHash ?? null;
1962
2206
  _userIdHash = opts.userIdHash ?? null;
1963
- const entryRoute = currentRoute();
1964
- _pageViewCount = 1;
1965
- send(buildPayload("session_start", {
1966
- route: entryRoute,
1967
- referrer: typeof document !== "undefined" ? document.referrer ?? null : null
1968
- }));
1969
- _heartbeatTimer = setInterval(() => {
1970
- send(buildPayload("session_heartbeat", { route: currentRoute() }));
1971
- }, HEARTBEAT_INTERVAL_MS);
1972
2207
  const onHide = () => {
1973
2208
  if (typeof document !== "undefined" && document.visibilityState === "hidden") {
1974
2209
  send(buildPayload("session_end", { route: currentRoute() }));
@@ -1977,46 +2212,421 @@ function initSessionTracker(opts) {
1977
2212
  if (typeof document !== "undefined") {
1978
2213
  document.addEventListener("visibilitychange", onHide, { passive: true });
1979
2214
  }
1980
- if (typeof window !== "undefined") {
1981
- window.addEventListener("pagehide", () => {
1982
- send(buildPayload("session_end", { route: currentRoute() }));
1983
- }, { passive: true });
2215
+ window.addEventListener("pagehide", () => {
2216
+ send(buildPayload("session_end", { route: currentRoute() }));
2217
+ }, { passive: true });
2218
+ if (opts.patchHistory !== false) {
2219
+ patchHistoryForPageViews();
1984
2220
  }
1985
- patchHistoryForPageViews();
2221
+ _unsubscribeConsent = onAnalyticsConsentChange((state) => {
2222
+ if (state === "granted") activate();
2223
+ else deactivate();
2224
+ });
2225
+ if (resolveAnalyticsConsent(opts.projectId ?? "", opts.analytics) === "granted") activate();
1986
2226
  }
1987
2227
  function trackPageView(route) {
1988
2228
  if (!_initialized || !_client) return;
1989
- _pageViewCount += 1;
1990
- send(buildPayload("page_view", { route: route ?? currentRoute() }));
2229
+ recordPageView(route ?? currentRoute());
1991
2230
  }
1992
2231
  function updateSessionIdentity(userIdHash) {
1993
2232
  _userIdHash = userIdHash;
1994
2233
  }
1995
2234
  function destroySessionTracker() {
1996
- if (_heartbeatTimer != null) {
1997
- clearInterval(_heartbeatTimer);
1998
- _heartbeatTimer = null;
1999
- }
2235
+ deactivate();
2236
+ _unsubscribeConsent?.();
2237
+ _unsubscribeConsent = null;
2000
2238
  _initialized = false;
2239
+ _started = false;
2001
2240
  _client = null;
2002
2241
  }
2003
2242
  var _historyPatched = false;
2004
2243
  function patchHistoryForPageViews() {
2005
2244
  if (_historyPatched || typeof history === "undefined") return;
2006
2245
  _historyPatched = true;
2007
- const wrap = (original) => function(...args) {
2246
+ const wrap = (original, countsAsPageView) => function(...args) {
2008
2247
  const result = original.apply(this, args);
2009
- if (original === history.pushState) {
2010
- _pageViewCount += 1;
2011
- send(buildPayload("page_view", { route: currentRoute() }));
2248
+ if (countsAsPageView) recordPageView(currentRoute());
2249
+ return result;
2250
+ };
2251
+ history.pushState = wrap(history.pushState, true);
2252
+ history.replaceState = wrap(history.replaceState, false);
2253
+ window.addEventListener("popstate", () => {
2254
+ recordPageView(currentRoute());
2255
+ }, { passive: true });
2256
+ }
2257
+
2258
+ // src/analytics-taxonomy.ts
2259
+ var EVENT_NAME_RE = /^[a-z][a-z0-9_]{1,63}$/;
2260
+ var EVENT_PROPERTY_LIMITS = {
2261
+ maxKeys: 40,
2262
+ maxKeyLength: 64,
2263
+ maxValueLength: 256,
2264
+ maxBytes: 8192,
2265
+ /** Client batch size before an immediate flush. */
2266
+ maxClientBatch: 20,
2267
+ /** Server-side per-request ceiling. */
2268
+ maxServerBatch: 50,
2269
+ /** Distinct event names per project before the server returns 422. */
2270
+ maxEventNamesPerProject: 200
2271
+ };
2272
+ var RESERVED_PROPERTY_PREFIX = "$";
2273
+ var PII_PROPERTY_KEY_RE = /(email|phone|password|passwd|token|secret|ssn|address|credit|card|iban)/i;
2274
+ var MUSHI_SURFACES = ["web", "console", "docs", "cli", "mcp", "server", "mobile"];
2275
+ var MUSHI_EVENTS = {
2276
+ // ── Any surface (SDK `analytics.autoPageviews`) ──────────────────────────
2277
+ page_view: { surface: ["web", "docs", "console"], required: [] },
2278
+ // ── Landing + docs (apps/docs) ───────────────────────────────────────────
2279
+ // Every docs route; `route` repeats the reserved `$route` as a host prop so
2280
+ // the requirement is checkable. company_funnel_weekly counts visits from
2281
+ // this and landing_view.
2282
+ docs_page_view: { surface: "docs", required: ["route"] },
2283
+ landing_view: { surface: "docs", required: [] },
2284
+ cta_click: { surface: "docs", required: ["cta_id", "location"] },
2285
+ quickstart_view: { surface: "docs", required: [] },
2286
+ pricing_view: { surface: "docs", required: [] },
2287
+ connect_demo_click: { surface: "docs", required: ["href"] },
2288
+ signup_click: { surface: "docs", required: ["href"] },
2289
+ // ── Console (apps/admin) ─────────────────────────────────────────────────
2290
+ signup_completed: { surface: "console", required: ["signup_source"] },
2291
+ report_opened: { surface: ["console", "mcp"], required: ["report_id"] },
2292
+ fix_context_pulled: { surface: ["console", "mcp"], required: ["report_id"] },
2293
+ fix_dispatched: { surface: ["console", "mcp"], required: ["report_id", "agent"] },
2294
+ invite_sent: { surface: "console", required: [] },
2295
+ upgrade_clicked: { surface: "console", required: ["plan"] },
2296
+ test_report_sent: { surface: "console", required: ["project_id"] },
2297
+ // ── Server-emitted (edge functions) ──────────────────────────────────────
2298
+ project_created: { surface: "server", required: ["project_id"] },
2299
+ key_minted: { surface: "server", required: ["project_id"] },
2300
+ first_report_received: { surface: "server", required: ["project_id"] },
2301
+ fix_merged: { surface: "server", required: ["project_id"] },
2302
+ upgrade_completed: { surface: "server", required: ["project_id", "plan"] },
2303
+ // ── Growth loop (widget "Bug reports by Mushi" mark) ─────────────────────
2304
+ loop_impression: { surface: "web", required: [] },
2305
+ loop_click: { surface: "web", required: [] },
2306
+ loop_signup: { surface: "console", required: ["ref"] }
2307
+ };
2308
+ var MUSHI_EVENT_NAMES = Object.keys(MUSHI_EVENTS);
2309
+ var ACTIVATION_EVENT = "first_report_received";
2310
+ var HABIT_EVENTS = ["report_opened", "fix_context_pulled", "fix_dispatched"];
2311
+ function isValidEventName(name) {
2312
+ return typeof name === "string" && EVENT_NAME_RE.test(name);
2313
+ }
2314
+ function sanitizeEventProperties(input, opts = {}) {
2315
+ const out = {};
2316
+ const dropped = [];
2317
+ if (!input || typeof input !== "object" || Array.isArray(input)) return { properties: out, dropped };
2318
+ const allow = new Set(opts.allowlist ?? []);
2319
+ let keys = 0;
2320
+ for (const [rawKey, rawValue] of Object.entries(input)) {
2321
+ if (keys >= EVENT_PROPERTY_LIMITS.maxKeys) {
2322
+ dropped.push(rawKey);
2323
+ continue;
2324
+ }
2325
+ const key = rawKey.slice(0, EVENT_PROPERTY_LIMITS.maxKeyLength);
2326
+ if (key.startsWith(RESERVED_PROPERTY_PREFIX) && !opts.allowReserved) {
2327
+ dropped.push(key);
2328
+ continue;
2329
+ }
2330
+ if (PII_PROPERTY_KEY_RE.test(key) && !allow.has(key)) {
2331
+ dropped.push(key);
2332
+ continue;
2012
2333
  }
2334
+ let value;
2335
+ if (rawValue === null || typeof rawValue === "boolean") value = rawValue;
2336
+ else if (typeof rawValue === "number") value = Number.isFinite(rawValue) ? rawValue : null;
2337
+ else if (typeof rawValue === "string") {
2338
+ const s = rawValue.slice(0, EVENT_PROPERTY_LIMITS.maxValueLength);
2339
+ value = opts.scrub ? opts.scrub(s) : s;
2340
+ } else if (rawValue instanceof Date) value = rawValue.toISOString();
2341
+ else {
2342
+ dropped.push(key);
2343
+ continue;
2344
+ }
2345
+ out[key] = value;
2346
+ keys += 1;
2347
+ }
2348
+ return { properties: out, dropped };
2349
+ }
2350
+ function propertiesWithinByteLimit(properties) {
2351
+ try {
2352
+ return JSON.stringify(properties).length <= EVENT_PROPERTY_LIMITS.maxBytes;
2353
+ } catch {
2354
+ return false;
2355
+ }
2356
+ }
2357
+
2358
+ // src/event-tracker.ts
2359
+ var _client2 = null;
2360
+ var _projectId = "";
2361
+ var _anonId = null;
2362
+ var _userId = null;
2363
+ var _userTraits = null;
2364
+ var _sdkVersion2;
2365
+ var _config = defaults();
2366
+ var _scrub;
2367
+ var _getSessionId;
2368
+ var _buffer = [];
2369
+ var _consentBuffer = [];
2370
+ var _consent = "granted";
2371
+ var _sampledIn = true;
2372
+ var _flushTimer = null;
2373
+ var _initialized2 = false;
2374
+ var _flushing = false;
2375
+ var _pendingIdentify = false;
2376
+ var _unsubscribeConsent2 = null;
2377
+ var CONSENT_BUFFER_MAX = 50;
2378
+ var SPILL_MAX = 200;
2379
+ var SPILL_TTL_MS = 24 * 60 * 60 * 1e3;
2380
+ function defaults() {
2381
+ return {
2382
+ sampleRate: 1,
2383
+ autoPageviews: false,
2384
+ flushIntervalMs: 5e3,
2385
+ surface: "web",
2386
+ propertyAllowlist: []
2387
+ };
2388
+ }
2389
+ function now2() {
2390
+ return (/* @__PURE__ */ new Date()).toISOString();
2391
+ }
2392
+ function spillKey() {
2393
+ return "mushi_events_spill_" + _projectId;
2394
+ }
2395
+ function isRetryableStatus(status) {
2396
+ return status === void 0 || status === 429 || status >= 500;
2397
+ }
2398
+ function analyticsIdKey() {
2399
+ return "mushi_analytics_id_" + _projectId;
2400
+ }
2401
+ function loadOrMintAnalyticsId() {
2402
+ try {
2403
+ const stored = localStorage.getItem(analyticsIdKey());
2404
+ if (stored) return stored;
2405
+ } catch {
2406
+ }
2407
+ return typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : "a-" + Math.random().toString(36).slice(2) + Date.now().toString(36);
2408
+ }
2409
+ function persistAnalyticsId() {
2410
+ if (!_anonId) return;
2411
+ try {
2412
+ if (localStorage.getItem(analyticsIdKey()) !== _anonId) localStorage.setItem(analyticsIdKey(), _anonId);
2413
+ } catch {
2414
+ }
2415
+ }
2416
+ function hashToUnit(s) {
2417
+ let h = 2166136261;
2418
+ for (let i = 0; i < s.length; i += 1) {
2419
+ h ^= s.charCodeAt(i);
2420
+ h = Math.imul(h, 16777619) >>> 0;
2421
+ }
2422
+ return (h >>> 0) / 4294967296;
2423
+ }
2424
+ function readSpill() {
2425
+ try {
2426
+ const raw = localStorage.getItem(spillKey());
2427
+ if (!raw) return [];
2428
+ const parsed = JSON.parse(raw);
2429
+ if (!parsed || Date.now() - parsed.at > SPILL_TTL_MS) {
2430
+ localStorage.removeItem(spillKey());
2431
+ return [];
2432
+ }
2433
+ return Array.isArray(parsed.events) ? parsed.events.slice(0, SPILL_MAX) : [];
2434
+ } catch {
2435
+ return [];
2436
+ }
2437
+ }
2438
+ function writeSpill(events) {
2439
+ try {
2440
+ if (events.length === 0) {
2441
+ localStorage.removeItem(spillKey());
2442
+ return;
2443
+ }
2444
+ localStorage.setItem(spillKey(), JSON.stringify({ at: Date.now(), events: events.slice(-SPILL_MAX) }));
2445
+ } catch {
2446
+ }
2447
+ }
2448
+ function takeSpill() {
2449
+ const events = readSpill();
2450
+ if (events.length > 0) writeSpill([]);
2451
+ return events;
2452
+ }
2453
+ function buildPayload2(events) {
2454
+ return {
2455
+ anon_id: _anonId,
2456
+ user_id: _userId,
2457
+ user_traits: _userTraits,
2458
+ session_id: _getSessionId ? _getSessionId() : null,
2459
+ sdk_version: _sdkVersion2,
2460
+ surface: _config.surface,
2461
+ events
2462
+ };
2463
+ }
2464
+ async function flushNow() {
2465
+ if (!_client2 || _flushing || _consent !== "granted") return;
2466
+ if (_buffer.length === 0 && !_pendingIdentify) return;
2467
+ _flushing = true;
2468
+ persistAnalyticsId();
2469
+ const batch = _buffer.splice(0, EVENT_PROPERTY_LIMITS.maxServerBatch);
2470
+ if (_pendingIdentify) {
2471
+ batch.unshift({ name: "identify", ts: now2(), properties: {} });
2472
+ _pendingIdentify = false;
2473
+ }
2474
+ try {
2475
+ const res = await _client2.postProductEvents(buildPayload2(batch));
2476
+ if (res.ok) {
2477
+ writeSpill([]);
2478
+ } else if (isRetryableStatus(res.error?.status)) {
2479
+ writeSpill([...readSpill(), ...batch.filter((e) => e.name !== "identify")]);
2480
+ }
2481
+ } catch {
2482
+ writeSpill([...readSpill(), ...batch.filter((e) => e.name !== "identify")]);
2483
+ } finally {
2484
+ _flushing = false;
2485
+ }
2486
+ if (_buffer.length >= EVENT_PROPERTY_LIMITS.maxClientBatch) void flushNow();
2487
+ }
2488
+ function enqueue(ev) {
2489
+ if (_consent === "denied") return false;
2490
+ if (_consent === "pending") {
2491
+ if (_consentBuffer.length >= CONSENT_BUFFER_MAX) return false;
2492
+ _consentBuffer.push(ev);
2493
+ return true;
2494
+ }
2495
+ _buffer.push(ev);
2496
+ if (_buffer.length >= EVENT_PROPERTY_LIMITS.maxClientBatch) void flushNow();
2497
+ return true;
2498
+ }
2499
+ function applyConsent(state) {
2500
+ if (state === "denied") {
2501
+ _consent = "denied";
2502
+ _buffer = [];
2503
+ _consentBuffer = [];
2504
+ _pendingIdentify = false;
2505
+ writeSpill([]);
2506
+ return;
2507
+ }
2508
+ const wasPending = _consent === "pending";
2509
+ _consent = "granted";
2510
+ if (wasPending) {
2511
+ _buffer.push(...takeSpill(), ..._consentBuffer);
2512
+ _consentBuffer = [];
2513
+ }
2514
+ if (_buffer.length > 0 || _pendingIdentify) void flushNow();
2515
+ }
2516
+ function stripUndefined(o) {
2517
+ const out = {};
2518
+ for (const [k, v] of Object.entries(o)) {
2519
+ if (v !== void 0) out[k] = v;
2520
+ }
2521
+ return out;
2522
+ }
2523
+ function isEventTrackingActive() {
2524
+ return _initialized2 && _consent === "granted" && _sampledIn;
2525
+ }
2526
+ function getEventAnonymousId() {
2527
+ if (!_initialized2 || _consent === "denied") return null;
2528
+ return _anonId;
2529
+ }
2530
+ function initEventTracker(opts) {
2531
+ if (_initialized2) return;
2532
+ if (typeof window === "undefined") return;
2533
+ const cfg = opts.config ?? {};
2534
+ _config = { ...defaults(), ...stripUndefined(cfg), propertyAllowlist: cfg.propertyAllowlist ?? [] };
2535
+ _projectId = opts.projectId;
2536
+ if (analyticsBlockReason(cfg) !== null) return;
2537
+ _initialized2 = true;
2538
+ _client2 = opts.client;
2539
+ _anonId = opts.anonId ?? loadOrMintAnalyticsId();
2540
+ _userId = opts.userId ?? null;
2541
+ _sdkVersion2 = opts.sdkVersion;
2542
+ _scrub = opts.scrub;
2543
+ _getSessionId = opts.getSessionId;
2544
+ const rate = Math.min(1, Math.max(0, _config.sampleRate));
2545
+ _sampledIn = rate >= 1 ? true : rate <= 0 ? false : hashToUnit(_anonId ?? "anon") < rate;
2546
+ if (!_sampledIn) return;
2547
+ _consent = resolveAnalyticsConsent(_projectId, cfg);
2548
+ if (_consent === "granted") _buffer.push(...takeSpill());
2549
+ else if (_consent === "denied") writeSpill([]);
2550
+ _unsubscribeConsent2 = onAnalyticsConsentChange(applyConsent);
2551
+ const interval = Math.max(1e3, _config.flushIntervalMs);
2552
+ _flushTimer = setInterval(() => {
2553
+ void flushNow();
2554
+ }, interval);
2555
+ const onHide = () => {
2556
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") void flushNow();
2557
+ };
2558
+ if (typeof document !== "undefined") document.addEventListener("visibilitychange", onHide, { passive: true });
2559
+ window.addEventListener("pagehide", () => {
2560
+ void flushNow();
2561
+ }, { passive: true });
2562
+ if (_config.autoPageviews) patchHistory();
2563
+ }
2564
+ function trackEvent(name, properties, opts) {
2565
+ if (!_initialized2 || !_sampledIn) return false;
2566
+ if (!isValidEventName(name)) return false;
2567
+ const { properties: props } = sanitizeEventProperties(properties, {
2568
+ allowlist: _config.propertyAllowlist,
2569
+ scrub: _scrub
2570
+ });
2571
+ let merged = props;
2572
+ if (opts?.reserved) {
2573
+ const { properties: res } = sanitizeEventProperties(opts.reserved, { allowReserved: true, scrub: _scrub });
2574
+ merged = { ...props, ...res };
2575
+ }
2576
+ merged.$surface = _config.surface;
2577
+ if (typeof location !== "undefined" && merged.$route === void 0) merged.$route = location.pathname;
2578
+ if (!propertiesWithinByteLimit(merged)) return false;
2579
+ return enqueue({
2580
+ name,
2581
+ ts: opts?.ts ?? now2(),
2582
+ properties: merged,
2583
+ ...opts?.dedupKey ? { dedup_key: opts.dedupKey } : {}
2584
+ });
2585
+ }
2586
+ function setEventConsent(state) {
2587
+ if (!_initialized2) _consent = state;
2588
+ setAnalyticsConsent(_projectId, state);
2589
+ }
2590
+ function updateEventIdentity(userId, traits) {
2591
+ _userId = userId;
2592
+ _userTraits = traits ?? null;
2593
+ if (!_initialized2 || !_sampledIn || !userId || _consent === "denied") return;
2594
+ _pendingIdentify = true;
2595
+ if (_consent === "granted") void flushNow();
2596
+ }
2597
+ function flushEvents() {
2598
+ return flushNow();
2599
+ }
2600
+ function destroyEventTracker() {
2601
+ if (_flushTimer != null) {
2602
+ clearInterval(_flushTimer);
2603
+ _flushTimer = null;
2604
+ }
2605
+ _unsubscribeConsent2?.();
2606
+ _unsubscribeConsent2 = null;
2607
+ _initialized2 = false;
2608
+ _client2 = null;
2609
+ _buffer = [];
2610
+ _consentBuffer = [];
2611
+ _consent = "granted";
2612
+ _sampledIn = true;
2613
+ _pendingIdentify = false;
2614
+ _userId = null;
2615
+ _userTraits = null;
2616
+ _config = defaults();
2617
+ }
2618
+ var _historyPatched2 = false;
2619
+ function patchHistory() {
2620
+ if (_historyPatched2 || typeof history === "undefined") return;
2621
+ _historyPatched2 = true;
2622
+ const original = history.pushState;
2623
+ history.pushState = function(...args) {
2624
+ const result = original.apply(this, args);
2625
+ trackEvent("page_view");
2013
2626
  return result;
2014
2627
  };
2015
- history.pushState = wrap(history.pushState);
2016
- history.replaceState = wrap(history.replaceState);
2017
2628
  window.addEventListener("popstate", () => {
2018
- _pageViewCount += 1;
2019
- send(buildPayload("page_view", { route: currentRoute() }));
2629
+ trackEvent("page_view");
2020
2630
  }, { passive: true });
2021
2631
  }
2022
2632
 
@@ -2033,12 +2643,12 @@ function createRateLimiter(config = {}) {
2033
2643
  let tokens = maxBurst;
2034
2644
  let lastRefill = Date.now();
2035
2645
  function refill() {
2036
- const now2 = Date.now();
2037
- const elapsed = now2 - lastRefill;
2646
+ const now3 = Date.now();
2647
+ const elapsed = now3 - lastRefill;
2038
2648
  const refills = Math.floor(elapsed / refillIntervalMs);
2039
2649
  if (refills > 0) {
2040
2650
  tokens = Math.min(maxBurst, tokens + refills * refillRate);
2041
- lastRefill = now2;
2651
+ lastRefill = now3;
2042
2652
  }
2043
2653
  }
2044
2654
  function tryConsume() {
@@ -2436,15 +3046,15 @@ function mushiTokens(mode) {
2436
3046
  // src/identity.ts
2437
3047
  var MUSHI_IDENTITY_TOKEN_PREFIX = "mushi.identity";
2438
3048
  function buildIdentityClaims(input) {
2439
- const now2 = Math.floor(Date.now() / 1e3);
3049
+ const now3 = Math.floor(Date.now() / 1e3);
2440
3050
  const ttl = input.ttlSeconds && input.ttlSeconds > 0 ? Math.min(input.ttlSeconds, 3600) : 600;
2441
3051
  return {
2442
3052
  projectId: input.projectId,
2443
3053
  sub: input.userId,
2444
3054
  ...input.email ? { email: input.email } : {},
2445
3055
  ...input.name ? { name: input.name } : {},
2446
- iat: now2,
2447
- exp: now2 + ttl
3056
+ iat: now3,
3057
+ exp: now3 + ttl
2448
3058
  };
2449
3059
  }
2450
3060
  function base64UrlDecode(segment) {
@@ -2484,13 +3094,22 @@ var SLUG_DOMAIN_HINTS = {
2484
3094
  "glot-it": "glot.it",
2485
3095
  glotit: "glot.it",
2486
3096
  "solo-boss-cloud": "solo-boss.kensaur.us",
2487
- "mushi-mushi": "kensaur.us"
3097
+ "mushi-mushi": "kensaur.us",
3098
+ "how-to-talk-to-girls": "talk.kensaur.us",
3099
+ htttg: "talk.kensaur.us",
3100
+ tsumagoi: "tsumagoi.kensaur.us"
2488
3101
  };
2489
3102
  var SLUG_ICON_URL_HINTS = {
2490
3103
  "mushi-mushi": "https://kensaur.us/mushi-mushi/admin/favicon.svg",
2491
3104
  "solo-boss-cloud": "https://solo-boss.kensaur.us/favicon.svg",
2492
3105
  "glot-it": "https://kensaur.us/glot-it/apple-touch-icon.png",
2493
- glotit: "https://kensaur.us/glot-it/apple-touch-icon.png"
3106
+ glotit: "https://kensaur.us/glot-it/apple-touch-icon.png",
3107
+ "the-wanting-mind": "https://kensaur.us/the-wanting-mind/pwa-512x512.png",
3108
+ "how-to-talk-to-girls": "https://talk.kensaur.us/pwa-192.png",
3109
+ htttg: "https://talk.kensaur.us/pwa-192.png",
3110
+ tsumagoi: "https://tsumagoi.kensaur.us/apple-touch-icon.png",
3111
+ "help-her-take-photo": "https://kensaur.us/help-her-take-photo/assets/apple-touch-icon.png",
3112
+ "yen-yen": "https://kensaur.us/yen-yen/icon.svg"
2494
3113
  };
2495
3114
  var UNTRUSTED_FAVICON_HOSTS = [
2496
3115
  "www.google.com",
@@ -2662,6 +3281,6 @@ function isSafeFaviconHref(href) {
2662
3281
  }
2663
3282
  }
2664
3283
 
2665
- export { DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, 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, REGION_ENDPOINTS, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroySessionTracker, diagnoseEnvConfig, estimateJsonBytes, expandPreset, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initSessionTracker, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, scrubUrl, sha256Hex, trackPageView, updateSessionIdentity, validateConfig };
3284
+ export { ACTIVATION_EVENT, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, EVENT_NAME_RE, EVENT_PROPERTY_LIMITS, HABIT_EVENTS, 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, REGION_ENDPOINTS, 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 };
2666
3285
  //# sourceMappingURL=index.js.map
2667
3286
  //# sourceMappingURL=index.js.map