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