@mushi-mushi/core 1.28.0 → 1.30.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 +577 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +474 -13
- package/dist/index.d.ts +474 -13
- package/dist/index.js +554 -91
- package/dist/index.js.map +1 -1
- package/dist/reporter-ui.cjs +475 -0
- package/dist/reporter-ui.cjs.map +1 -0
- package/dist/reporter-ui.d.cts +131 -0
- package/dist/reporter-ui.d.ts +131 -0
- package/dist/reporter-ui.js +462 -0
- package/dist/reporter-ui.js.map +1 -0
- package/package.json +22 -13
- package/CODE_OF_CONDUCT.md +0 -51
- package/CONTRIBUTING.md +0 -226
- package/SECURITY.md +0 -359
package/dist/index.cjs
CHANGED
|
@@ -232,7 +232,8 @@ function createApiClient(options) {
|
|
|
232
232
|
if (cbFailures >= cbThreshold) cbOpenUntil = Date.now() + cbCooldownMs;
|
|
233
233
|
};
|
|
234
234
|
async function request(method, path, body, retries = maxRetries, internalKind, extraHeaders) {
|
|
235
|
-
|
|
235
|
+
const tracked = internalKind !== "reporter-poll";
|
|
236
|
+
if (tracked && cbIsOpen()) {
|
|
236
237
|
return { ok: false, error: { code: "CIRCUIT_OPEN", message: "Endpoint temporarily unavailable; retrying later." } };
|
|
237
238
|
}
|
|
238
239
|
const url = `${baseUrl}${path}`;
|
|
@@ -251,7 +252,7 @@ function createApiClient(options) {
|
|
|
251
252
|
...extraHeaders
|
|
252
253
|
};
|
|
253
254
|
const serialized = body ? JSON.stringify(body) : void 0;
|
|
254
|
-
if (serialized && method !== "GET") {
|
|
255
|
+
if (serialized && method !== "GET" && internalKind !== "reporter-poll") {
|
|
255
256
|
lastOutbound = { url, headers, body: serialized, path };
|
|
256
257
|
}
|
|
257
258
|
try {
|
|
@@ -291,19 +292,22 @@ function createApiClient(options) {
|
|
|
291
292
|
await sleep(retryAfterMs ?? getBackoffDelay(maxRetries - retries));
|
|
292
293
|
return request(method, path, body, retries - 1, internalKind, extraHeaders);
|
|
293
294
|
}
|
|
294
|
-
if (
|
|
295
|
-
|
|
295
|
+
if (tracked) {
|
|
296
|
+
if (unusable) cbRecordUnreachable();
|
|
297
|
+
else cbRecordReachable();
|
|
298
|
+
}
|
|
296
299
|
return {
|
|
297
300
|
ok: false,
|
|
298
301
|
error: {
|
|
299
302
|
code: errorBody.error?.code || `HTTP_${response.status}`,
|
|
300
|
-
message: errorBody.error?.message || errorBody.message || `HTTP ${response.status} error
|
|
303
|
+
message: errorBody.error?.message || errorBody.message || `HTTP ${response.status} error`,
|
|
304
|
+
status: response.status
|
|
301
305
|
}
|
|
302
306
|
};
|
|
303
307
|
}
|
|
304
308
|
const payload = await response.json();
|
|
305
309
|
const data = payload && typeof payload === "object" && "ok" in payload && "data" in payload ? payload.data : payload;
|
|
306
|
-
cbRecordReachable();
|
|
310
|
+
if (tracked) cbRecordReachable();
|
|
307
311
|
return { ok: true, data };
|
|
308
312
|
} catch (error) {
|
|
309
313
|
clearTimeout(timer);
|
|
@@ -311,7 +315,7 @@ function createApiClient(options) {
|
|
|
311
315
|
await sleep(getBackoffDelay(maxRetries - retries));
|
|
312
316
|
return request(method, path, body, retries - 1, internalKind, extraHeaders);
|
|
313
317
|
}
|
|
314
|
-
cbRecordUnreachable();
|
|
318
|
+
if (tracked) cbRecordUnreachable();
|
|
315
319
|
return {
|
|
316
320
|
ok: false,
|
|
317
321
|
error: {
|
|
@@ -322,39 +326,17 @@ function createApiClient(options) {
|
|
|
322
326
|
}
|
|
323
327
|
}
|
|
324
328
|
async function requestForReporter(method, path, reporterToken, body) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const response = await fetch(url, {
|
|
330
|
-
method,
|
|
331
|
-
headers: {
|
|
332
|
-
"Content-Type": "application/json",
|
|
333
|
-
"X-Mushi-Api-Key": apiKey,
|
|
334
|
-
"X-Mushi-Project": projectId,
|
|
335
|
-
...sdkPackage ? { [MUSHI_SDK_PACKAGE_HEADER]: sdkPackage } : {},
|
|
336
|
-
...sdkVersion ? { [MUSHI_SDK_VERSION_HEADER]: sdkVersion } : {},
|
|
337
|
-
[MUSHI_INTERNAL_HEADER]: "reporter-poll",
|
|
329
|
+
try {
|
|
330
|
+
const tokenHash = await sha256Hex(reporterToken);
|
|
331
|
+
const ts = String(Date.now());
|
|
332
|
+
return await request(method, path, body, maxRetries, "reporter-poll", {
|
|
338
333
|
"X-Reporter-Token-Hash": tokenHash,
|
|
339
334
|
"X-Reporter-Ts": ts,
|
|
340
|
-
"X-Reporter-Hmac":
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
[MUSHI_INTERNAL_INIT_MARKER]: "reporter-poll"
|
|
345
|
-
});
|
|
346
|
-
if (!response.ok) {
|
|
347
|
-
const errorBody = await response.json().catch(() => ({}));
|
|
348
|
-
return {
|
|
349
|
-
ok: false,
|
|
350
|
-
error: {
|
|
351
|
-
code: `HTTP_${response.status}`,
|
|
352
|
-
message: errorBody.error?.message ?? errorBody.message ?? `HTTP ${response.status} error`
|
|
353
|
-
}
|
|
354
|
-
};
|
|
335
|
+
"X-Reporter-Hmac": await hmacSha256Hex(apiKey, `${projectId}.${ts}.${tokenHash}`)
|
|
336
|
+
});
|
|
337
|
+
} catch (error) {
|
|
338
|
+
return { ok: false, error: { code: "NETWORK_ERROR", message: error instanceof Error ? error.message : "Unknown error" } };
|
|
355
339
|
}
|
|
356
|
-
const payload = await response.json();
|
|
357
|
-
return { ok: true, data: payload.data ?? payload };
|
|
358
340
|
}
|
|
359
341
|
return {
|
|
360
342
|
async submitReport(report) {
|
|
@@ -474,6 +456,18 @@ function createApiClient(options) {
|
|
|
474
456
|
"discovery"
|
|
475
457
|
);
|
|
476
458
|
},
|
|
459
|
+
/** POST /v1/sdk/events — batched product-analytics events (Mushi.track()).
|
|
460
|
+
* Best-effort (1 retry); the event tracker spills unsent batches to
|
|
461
|
+
* localStorage and replays them on the next page load. */
|
|
462
|
+
async postProductEvents(payload) {
|
|
463
|
+
return request(
|
|
464
|
+
"POST",
|
|
465
|
+
"/v1/sdk/events",
|
|
466
|
+
payload,
|
|
467
|
+
1,
|
|
468
|
+
"discovery"
|
|
469
|
+
);
|
|
470
|
+
},
|
|
477
471
|
async submitActivity(userId, events, opts) {
|
|
478
472
|
return request(
|
|
479
473
|
"POST",
|
|
@@ -600,7 +594,7 @@ function sleep(ms) {
|
|
|
600
594
|
function getBackoffDelay(attempt) {
|
|
601
595
|
return Math.min(1e3 * 2 ** attempt + Math.random() * 500, 1e4);
|
|
602
596
|
}
|
|
603
|
-
function parseRetryAfter(value,
|
|
597
|
+
function parseRetryAfter(value, now3 = Date.now()) {
|
|
604
598
|
if (!value) return null;
|
|
605
599
|
const raw = value.trim();
|
|
606
600
|
if (!raw) return null;
|
|
@@ -608,7 +602,7 @@ function parseRetryAfter(value, now2 = Date.now()) {
|
|
|
608
602
|
if (Number.isFinite(seconds)) return seconds < 0 ? null : seconds * 1e3;
|
|
609
603
|
const at = Date.parse(raw);
|
|
610
604
|
if (Number.isNaN(at)) return null;
|
|
611
|
-
return Math.max(at -
|
|
605
|
+
return Math.max(at - now3, 0);
|
|
612
606
|
}
|
|
613
607
|
function isRetryable(error) {
|
|
614
608
|
if (error instanceof DOMException && error.name === "AbortError") return true;
|
|
@@ -826,6 +820,8 @@ var KNOWN_CONFIG_KEYS = [
|
|
|
826
820
|
"circuitBreaker",
|
|
827
821
|
"preset",
|
|
828
822
|
"runtimeConfig",
|
|
823
|
+
"analytics",
|
|
824
|
+
"trackSessions",
|
|
829
825
|
"sentry",
|
|
830
826
|
"widget",
|
|
831
827
|
"capture",
|
|
@@ -917,23 +913,23 @@ function presetDefaults(preset) {
|
|
|
917
913
|
}
|
|
918
914
|
}
|
|
919
915
|
function expandPreset(config) {
|
|
920
|
-
const
|
|
921
|
-
if (!
|
|
916
|
+
const defaults2 = presetDefaults(config.preset);
|
|
917
|
+
if (!defaults2) return config;
|
|
922
918
|
return {
|
|
923
919
|
...config,
|
|
924
920
|
widget: {
|
|
925
|
-
...
|
|
921
|
+
...defaults2.widget,
|
|
926
922
|
...config.widget
|
|
927
923
|
},
|
|
928
924
|
capture: {
|
|
929
|
-
...
|
|
925
|
+
...defaults2.capture,
|
|
930
926
|
...config.capture
|
|
931
927
|
},
|
|
932
928
|
proactive: {
|
|
933
|
-
...
|
|
929
|
+
...defaults2.proactive,
|
|
934
930
|
...config.proactive,
|
|
935
931
|
cooldown: {
|
|
936
|
-
...
|
|
932
|
+
...defaults2.proactive?.cooldown,
|
|
937
933
|
...config.proactive?.cooldown
|
|
938
934
|
}
|
|
939
935
|
}
|
|
@@ -1344,12 +1340,12 @@ function createOfflineQueue(config = {}) {
|
|
|
1344
1340
|
const n = row.attempts;
|
|
1345
1341
|
return typeof n === "number" && Number.isFinite(n) ? n : 0;
|
|
1346
1342
|
}
|
|
1347
|
-
function isExpired(row,
|
|
1343
|
+
function isExpired(row, now3) {
|
|
1348
1344
|
const queuedAt = row.queuedAt;
|
|
1349
1345
|
if (!queuedAt) return false;
|
|
1350
1346
|
const ts = Date.parse(queuedAt);
|
|
1351
1347
|
if (Number.isNaN(ts)) return false;
|
|
1352
|
-
return
|
|
1348
|
+
return now3 - ts > MAX_QUEUE_AGE_MS;
|
|
1353
1349
|
}
|
|
1354
1350
|
function detectBackend() {
|
|
1355
1351
|
if (backendType) return backendType;
|
|
@@ -1536,7 +1532,7 @@ function createOfflineQueue(config = {}) {
|
|
|
1536
1532
|
await lsEnqueue(report);
|
|
1537
1533
|
return "localstorage";
|
|
1538
1534
|
}
|
|
1539
|
-
async function
|
|
1535
|
+
async function enqueue2(report) {
|
|
1540
1536
|
if (!enabled) return;
|
|
1541
1537
|
const currentSize = await size();
|
|
1542
1538
|
if (currentSize >= maxQueueSize) {
|
|
@@ -1554,10 +1550,10 @@ function createOfflineQueue(config = {}) {
|
|
|
1554
1550
|
async function runFlush(client) {
|
|
1555
1551
|
const { backend, rows: storedRows } = await readRows();
|
|
1556
1552
|
let rows = storedRows;
|
|
1557
|
-
const
|
|
1553
|
+
const now3 = Date.now();
|
|
1558
1554
|
const fresh = [];
|
|
1559
1555
|
for (const row of rows) {
|
|
1560
|
-
if (isExpired(row,
|
|
1556
|
+
if (isExpired(row, now3)) {
|
|
1561
1557
|
const rowId = row.id;
|
|
1562
1558
|
await removeRow(backend, rowId);
|
|
1563
1559
|
queueLog.debug("Offline queue: evicting stale report", { id: rowId });
|
|
@@ -1705,7 +1701,7 @@ function createOfflineQueue(config = {}) {
|
|
|
1705
1701
|
syncCleanup?.();
|
|
1706
1702
|
syncCleanup = null;
|
|
1707
1703
|
}
|
|
1708
|
-
return { enqueue, flush, size, clear, startAutoSync, stopAutoSync };
|
|
1704
|
+
return { enqueue: enqueue2, flush, size, clear, startAutoSync, stopAutoSync };
|
|
1709
1705
|
}
|
|
1710
1706
|
|
|
1711
1707
|
// src/environment.ts
|
|
@@ -2047,21 +2043,94 @@ function randomSuffix() {
|
|
|
2047
2043
|
return n.toString(36).padStart(6, "0").slice(0, 6);
|
|
2048
2044
|
}
|
|
2049
2045
|
|
|
2046
|
+
// src/analytics-gate.ts
|
|
2047
|
+
var AUTOMATED_UA_RE = /HeadlessChrome|PhantomJS|Lighthouse|\bbot\b|bot[/-]|crawler|spider/i;
|
|
2048
|
+
function consentKey(projectId) {
|
|
2049
|
+
return "mushi_events_consent_" + projectId;
|
|
2050
|
+
}
|
|
2051
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
2052
|
+
function dntActive() {
|
|
2053
|
+
if (typeof navigator === "undefined") return false;
|
|
2054
|
+
const nav = navigator;
|
|
2055
|
+
if (nav.globalPrivacyControl === true) return true;
|
|
2056
|
+
const winDnt = typeof window !== "undefined" ? window.doNotTrack : void 0;
|
|
2057
|
+
const dnt = nav.doNotTrack ?? nav.msDoNotTrack ?? winDnt;
|
|
2058
|
+
return dnt === "1" || dnt === "yes";
|
|
2059
|
+
}
|
|
2060
|
+
function isAutomatedBrowser() {
|
|
2061
|
+
if (typeof navigator === "undefined") return false;
|
|
2062
|
+
if (navigator.webdriver === true) return true;
|
|
2063
|
+
return AUTOMATED_UA_RE.test(navigator.userAgent ?? "");
|
|
2064
|
+
}
|
|
2065
|
+
function analyticsBlockReason(config) {
|
|
2066
|
+
if (config?.enabled === false) return "disabled";
|
|
2067
|
+
if (config?.respectDoNotTrack !== false && dntActive()) return "dnt";
|
|
2068
|
+
if (config?.excludeBots !== false && isAutomatedBrowser()) return "automation";
|
|
2069
|
+
return null;
|
|
2070
|
+
}
|
|
2071
|
+
function readStoredConsent(projectId) {
|
|
2072
|
+
if (!projectId) return null;
|
|
2073
|
+
try {
|
|
2074
|
+
const v = localStorage.getItem(consentKey(projectId));
|
|
2075
|
+
return v === "granted" || v === "denied" ? v : null;
|
|
2076
|
+
} catch {
|
|
2077
|
+
return null;
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
function writeStoredConsent(projectId, state) {
|
|
2081
|
+
if (!projectId) return;
|
|
2082
|
+
try {
|
|
2083
|
+
localStorage.setItem(consentKey(projectId), state);
|
|
2084
|
+
} catch {
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
function resolveAnalyticsConsent(projectId, config) {
|
|
2088
|
+
const stored = readStoredConsent(projectId);
|
|
2089
|
+
if (config?.consent === "required") return stored ?? "pending";
|
|
2090
|
+
return stored === "denied" ? "denied" : "granted";
|
|
2091
|
+
}
|
|
2092
|
+
function setAnalyticsConsent(projectId, state) {
|
|
2093
|
+
writeStoredConsent(projectId, state);
|
|
2094
|
+
for (const listener of [...listeners]) {
|
|
2095
|
+
try {
|
|
2096
|
+
listener(state);
|
|
2097
|
+
} catch {
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
function onAnalyticsConsentChange(listener) {
|
|
2102
|
+
listeners.add(listener);
|
|
2103
|
+
return () => {
|
|
2104
|
+
listeners.delete(listener);
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2050
2108
|
// src/session-tracker.ts
|
|
2051
2109
|
var HEARTBEAT_INTERVAL_MS = 6e4;
|
|
2052
2110
|
var _client = null;
|
|
2053
2111
|
var _sdkVersion;
|
|
2054
2112
|
var _userIdHash = null;
|
|
2055
|
-
var
|
|
2113
|
+
var _reporterToken = null;
|
|
2056
2114
|
var _pageViewCount = 0;
|
|
2057
2115
|
var _heartbeatTimer = null;
|
|
2058
2116
|
var _initialized = false;
|
|
2117
|
+
var _active = false;
|
|
2118
|
+
var _started = false;
|
|
2119
|
+
var _unsubscribeConsent = null;
|
|
2059
2120
|
function now() {
|
|
2060
2121
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
2061
2122
|
}
|
|
2062
2123
|
function currentRoute() {
|
|
2063
2124
|
if (typeof window === "undefined") return "";
|
|
2064
|
-
return window.location.pathname
|
|
2125
|
+
return window.location.pathname;
|
|
2126
|
+
}
|
|
2127
|
+
function referrerOrigin() {
|
|
2128
|
+
if (typeof document === "undefined" || !document.referrer) return null;
|
|
2129
|
+
try {
|
|
2130
|
+
return new URL(document.referrer).origin;
|
|
2131
|
+
} catch {
|
|
2132
|
+
return null;
|
|
2133
|
+
}
|
|
2065
2134
|
}
|
|
2066
2135
|
function userAgent() {
|
|
2067
2136
|
if (typeof navigator === "undefined") return null;
|
|
@@ -2073,7 +2142,8 @@ function buildPayload(kind, extra) {
|
|
|
2073
2142
|
session_id: getSessionId(),
|
|
2074
2143
|
ts: now(),
|
|
2075
2144
|
page_view_count: _pageViewCount,
|
|
2076
|
-
|
|
2145
|
+
// Wire name kept for older servers; the value is the raw token (hashed server-side).
|
|
2146
|
+
reporter_token_hash: _reporterToken,
|
|
2077
2147
|
user_id_hash: _userIdHash,
|
|
2078
2148
|
user_agent: userAgent(),
|
|
2079
2149
|
sdk_version: _sdkVersion,
|
|
@@ -2081,26 +2151,42 @@ function buildPayload(kind, extra) {
|
|
|
2081
2151
|
};
|
|
2082
2152
|
}
|
|
2083
2153
|
function send(payload) {
|
|
2084
|
-
if (!_client) return;
|
|
2154
|
+
if (!_client || !_active) return;
|
|
2085
2155
|
_client.postSessionEvent(payload).catch(() => {
|
|
2086
2156
|
});
|
|
2087
2157
|
}
|
|
2158
|
+
function recordPageView(route) {
|
|
2159
|
+
if (!_active) return;
|
|
2160
|
+
_pageViewCount += 1;
|
|
2161
|
+
send(buildPayload("page_view", { route }));
|
|
2162
|
+
}
|
|
2163
|
+
function activate() {
|
|
2164
|
+
if (_active || !_initialized) return;
|
|
2165
|
+
_active = true;
|
|
2166
|
+
if (!_started) {
|
|
2167
|
+
_started = true;
|
|
2168
|
+
_pageViewCount = 1;
|
|
2169
|
+
send(buildPayload("session_start", { route: currentRoute(), referrer: referrerOrigin() }));
|
|
2170
|
+
}
|
|
2171
|
+
_heartbeatTimer = setInterval(() => {
|
|
2172
|
+
send(buildPayload("session_heartbeat", { route: currentRoute() }));
|
|
2173
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
2174
|
+
}
|
|
2175
|
+
function deactivate() {
|
|
2176
|
+
_active = false;
|
|
2177
|
+
if (_heartbeatTimer != null) {
|
|
2178
|
+
clearInterval(_heartbeatTimer);
|
|
2179
|
+
_heartbeatTimer = null;
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2088
2182
|
function initSessionTracker(opts) {
|
|
2089
2183
|
if (_initialized || typeof window === "undefined") return;
|
|
2184
|
+
if (analyticsBlockReason(opts.analytics) !== null) return;
|
|
2090
2185
|
_initialized = true;
|
|
2091
2186
|
_client = opts.client;
|
|
2092
2187
|
_sdkVersion = opts.sdkVersion;
|
|
2093
|
-
|
|
2188
|
+
_reporterToken = opts.reporterToken ?? opts.reporterTokenHash ?? null;
|
|
2094
2189
|
_userIdHash = opts.userIdHash ?? null;
|
|
2095
|
-
const entryRoute = currentRoute();
|
|
2096
|
-
_pageViewCount = 1;
|
|
2097
|
-
send(buildPayload("session_start", {
|
|
2098
|
-
route: entryRoute,
|
|
2099
|
-
referrer: typeof document !== "undefined" ? document.referrer ?? null : null
|
|
2100
|
-
}));
|
|
2101
|
-
_heartbeatTimer = setInterval(() => {
|
|
2102
|
-
send(buildPayload("session_heartbeat", { route: currentRoute() }));
|
|
2103
|
-
}, HEARTBEAT_INTERVAL_MS);
|
|
2104
2190
|
const onHide = () => {
|
|
2105
2191
|
if (typeof document !== "undefined" && document.visibilityState === "hidden") {
|
|
2106
2192
|
send(buildPayload("session_end", { route: currentRoute() }));
|
|
@@ -2109,46 +2195,423 @@ function initSessionTracker(opts) {
|
|
|
2109
2195
|
if (typeof document !== "undefined") {
|
|
2110
2196
|
document.addEventListener("visibilitychange", onHide, { passive: true });
|
|
2111
2197
|
}
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2198
|
+
window.addEventListener("pagehide", () => {
|
|
2199
|
+
send(buildPayload("session_end", { route: currentRoute() }));
|
|
2200
|
+
}, { passive: true });
|
|
2201
|
+
if (opts.patchHistory !== false) {
|
|
2202
|
+
patchHistoryForPageViews();
|
|
2116
2203
|
}
|
|
2117
|
-
|
|
2204
|
+
_unsubscribeConsent = onAnalyticsConsentChange((state) => {
|
|
2205
|
+
if (state === "granted") activate();
|
|
2206
|
+
else deactivate();
|
|
2207
|
+
});
|
|
2208
|
+
if (resolveAnalyticsConsent(opts.projectId ?? "", opts.analytics) === "granted") activate();
|
|
2118
2209
|
}
|
|
2119
2210
|
function trackPageView(route) {
|
|
2120
2211
|
if (!_initialized || !_client) return;
|
|
2121
|
-
|
|
2122
|
-
send(buildPayload("page_view", { route: route ?? currentRoute() }));
|
|
2212
|
+
recordPageView(route ?? currentRoute());
|
|
2123
2213
|
}
|
|
2124
2214
|
function updateSessionIdentity(userIdHash) {
|
|
2125
2215
|
_userIdHash = userIdHash;
|
|
2126
2216
|
}
|
|
2127
2217
|
function destroySessionTracker() {
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
}
|
|
2218
|
+
deactivate();
|
|
2219
|
+
_unsubscribeConsent?.();
|
|
2220
|
+
_unsubscribeConsent = null;
|
|
2132
2221
|
_initialized = false;
|
|
2222
|
+
_started = false;
|
|
2133
2223
|
_client = null;
|
|
2134
2224
|
}
|
|
2135
2225
|
var _historyPatched = false;
|
|
2136
2226
|
function patchHistoryForPageViews() {
|
|
2137
2227
|
if (_historyPatched || typeof history === "undefined") return;
|
|
2138
2228
|
_historyPatched = true;
|
|
2139
|
-
const wrap = (original) => function(...args) {
|
|
2229
|
+
const wrap = (original, countsAsPageView) => function(...args) {
|
|
2140
2230
|
const result = original.apply(this, args);
|
|
2141
|
-
if (
|
|
2142
|
-
|
|
2143
|
-
|
|
2231
|
+
if (countsAsPageView) recordPageView(currentRoute());
|
|
2232
|
+
return result;
|
|
2233
|
+
};
|
|
2234
|
+
history.pushState = wrap(history.pushState, true);
|
|
2235
|
+
history.replaceState = wrap(history.replaceState, false);
|
|
2236
|
+
window.addEventListener("popstate", () => {
|
|
2237
|
+
recordPageView(currentRoute());
|
|
2238
|
+
}, { passive: true });
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
// src/analytics-taxonomy.ts
|
|
2242
|
+
var EVENT_NAME_RE = /^[a-z][a-z0-9_]{1,63}$/;
|
|
2243
|
+
var EVENT_PROPERTY_LIMITS = {
|
|
2244
|
+
maxKeys: 40,
|
|
2245
|
+
maxKeyLength: 64,
|
|
2246
|
+
maxValueLength: 256,
|
|
2247
|
+
maxBytes: 8192,
|
|
2248
|
+
/** Client batch size before an immediate flush. */
|
|
2249
|
+
maxClientBatch: 20,
|
|
2250
|
+
/** Server-side per-request ceiling. */
|
|
2251
|
+
maxServerBatch: 50,
|
|
2252
|
+
/** Distinct event names per project before the server returns 422. */
|
|
2253
|
+
maxEventNamesPerProject: 200
|
|
2254
|
+
};
|
|
2255
|
+
var RESERVED_PROPERTY_PREFIX = "$";
|
|
2256
|
+
var PII_PROPERTY_KEY_RE = /(email|phone|password|passwd|token|secret|ssn|address|credit|card|iban)/i;
|
|
2257
|
+
var MUSHI_SURFACES = ["web", "console", "docs", "cli", "mcp", "server", "mobile"];
|
|
2258
|
+
var MUSHI_EVENTS = {
|
|
2259
|
+
// ── Any surface (SDK `analytics.autoPageviews`) ──────────────────────────
|
|
2260
|
+
page_view: { surface: ["web", "docs", "console"], required: [] },
|
|
2261
|
+
// ── Landing + docs (apps/docs) ───────────────────────────────────────────
|
|
2262
|
+
// Every docs route; `route` repeats the reserved `$route` as a host prop so
|
|
2263
|
+
// the requirement is checkable. company_funnel_weekly counts visits from
|
|
2264
|
+
// this and landing_view.
|
|
2265
|
+
docs_page_view: { surface: "docs", required: ["route"] },
|
|
2266
|
+
landing_view: { surface: "docs", required: [] },
|
|
2267
|
+
cta_click: { surface: "docs", required: ["cta_id", "location"] },
|
|
2268
|
+
quickstart_view: { surface: "docs", required: [] },
|
|
2269
|
+
pricing_view: { surface: "docs", required: [] },
|
|
2270
|
+
connect_demo_click: { surface: "docs", required: ["href"] },
|
|
2271
|
+
signup_click: { surface: "docs", required: ["href"] },
|
|
2272
|
+
// ── Console (apps/admin) ─────────────────────────────────────────────────
|
|
2273
|
+
signup_completed: { surface: "console", required: ["signup_source"] },
|
|
2274
|
+
report_opened: { surface: ["console", "mcp"], required: ["report_id"] },
|
|
2275
|
+
fix_context_pulled: { surface: ["console", "mcp"], required: ["report_id"] },
|
|
2276
|
+
fix_dispatched: { surface: ["console", "mcp"], required: ["report_id", "agent"] },
|
|
2277
|
+
invite_sent: { surface: "console", required: [] },
|
|
2278
|
+
upgrade_clicked: { surface: "console", required: ["plan"] },
|
|
2279
|
+
test_report_sent: { surface: "console", required: ["project_id"] },
|
|
2280
|
+
diagnosis_viewed: { surface: "console", required: ["report_id", "project_id", "surface"] },
|
|
2281
|
+
// ── Server-emitted (edge functions) ──────────────────────────────────────
|
|
2282
|
+
project_created: { surface: "server", required: ["project_id"] },
|
|
2283
|
+
key_minted: { surface: "server", required: ["project_id"] },
|
|
2284
|
+
first_report_received: { surface: "server", required: ["project_id"] },
|
|
2285
|
+
first_diagnosis_ready: { surface: "server", required: ["project_id"] },
|
|
2286
|
+
fix_merged: { surface: "server", required: ["project_id"] },
|
|
2287
|
+
upgrade_completed: { surface: "server", required: ["project_id", "plan"] },
|
|
2288
|
+
// ── Growth loop (widget "Bug reports by Mushi" mark) ─────────────────────
|
|
2289
|
+
loop_impression: { surface: "web", required: [] },
|
|
2290
|
+
loop_click: { surface: "web", required: [] },
|
|
2291
|
+
loop_signup: { surface: "console", required: ["ref"] }
|
|
2292
|
+
};
|
|
2293
|
+
var MUSHI_EVENT_NAMES = Object.keys(MUSHI_EVENTS);
|
|
2294
|
+
var ACTIVATION_EVENT = "first_report_received";
|
|
2295
|
+
var HABIT_EVENTS = ["report_opened", "fix_context_pulled", "fix_dispatched"];
|
|
2296
|
+
function isValidEventName(name) {
|
|
2297
|
+
return typeof name === "string" && EVENT_NAME_RE.test(name);
|
|
2298
|
+
}
|
|
2299
|
+
function sanitizeEventProperties(input, opts = {}) {
|
|
2300
|
+
const out = {};
|
|
2301
|
+
const dropped = [];
|
|
2302
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return { properties: out, dropped };
|
|
2303
|
+
const allow = new Set(opts.allowlist ?? []);
|
|
2304
|
+
let keys = 0;
|
|
2305
|
+
for (const [rawKey, rawValue] of Object.entries(input)) {
|
|
2306
|
+
if (keys >= EVENT_PROPERTY_LIMITS.maxKeys) {
|
|
2307
|
+
dropped.push(rawKey);
|
|
2308
|
+
continue;
|
|
2309
|
+
}
|
|
2310
|
+
const key = rawKey.slice(0, EVENT_PROPERTY_LIMITS.maxKeyLength);
|
|
2311
|
+
if (key.startsWith(RESERVED_PROPERTY_PREFIX) && !opts.allowReserved) {
|
|
2312
|
+
dropped.push(key);
|
|
2313
|
+
continue;
|
|
2314
|
+
}
|
|
2315
|
+
if (PII_PROPERTY_KEY_RE.test(key) && !allow.has(key)) {
|
|
2316
|
+
dropped.push(key);
|
|
2317
|
+
continue;
|
|
2318
|
+
}
|
|
2319
|
+
let value;
|
|
2320
|
+
if (rawValue === null || typeof rawValue === "boolean") value = rawValue;
|
|
2321
|
+
else if (typeof rawValue === "number") value = Number.isFinite(rawValue) ? rawValue : null;
|
|
2322
|
+
else if (typeof rawValue === "string") {
|
|
2323
|
+
const s = rawValue.slice(0, EVENT_PROPERTY_LIMITS.maxValueLength);
|
|
2324
|
+
value = opts.scrub ? opts.scrub(s) : s;
|
|
2325
|
+
} else if (rawValue instanceof Date) value = rawValue.toISOString();
|
|
2326
|
+
else {
|
|
2327
|
+
dropped.push(key);
|
|
2328
|
+
continue;
|
|
2329
|
+
}
|
|
2330
|
+
out[key] = value;
|
|
2331
|
+
keys += 1;
|
|
2332
|
+
}
|
|
2333
|
+
return { properties: out, dropped };
|
|
2334
|
+
}
|
|
2335
|
+
function propertiesWithinByteLimit(properties) {
|
|
2336
|
+
try {
|
|
2337
|
+
return JSON.stringify(properties).length <= EVENT_PROPERTY_LIMITS.maxBytes;
|
|
2338
|
+
} catch {
|
|
2339
|
+
return false;
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
// src/event-tracker.ts
|
|
2344
|
+
var _client2 = null;
|
|
2345
|
+
var _projectId = "";
|
|
2346
|
+
var _anonId = null;
|
|
2347
|
+
var _userId = null;
|
|
2348
|
+
var _userTraits = null;
|
|
2349
|
+
var _sdkVersion2;
|
|
2350
|
+
var _config = defaults();
|
|
2351
|
+
var _scrub;
|
|
2352
|
+
var _getSessionId;
|
|
2353
|
+
var _buffer = [];
|
|
2354
|
+
var _consentBuffer = [];
|
|
2355
|
+
var _consent = "granted";
|
|
2356
|
+
var _sampledIn = true;
|
|
2357
|
+
var _flushTimer = null;
|
|
2358
|
+
var _initialized2 = false;
|
|
2359
|
+
var _flushing = false;
|
|
2360
|
+
var _pendingIdentify = false;
|
|
2361
|
+
var _unsubscribeConsent2 = null;
|
|
2362
|
+
var CONSENT_BUFFER_MAX = 50;
|
|
2363
|
+
var SPILL_MAX = 200;
|
|
2364
|
+
var SPILL_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2365
|
+
function defaults() {
|
|
2366
|
+
return {
|
|
2367
|
+
sampleRate: 1,
|
|
2368
|
+
autoPageviews: false,
|
|
2369
|
+
flushIntervalMs: 5e3,
|
|
2370
|
+
surface: "web",
|
|
2371
|
+
propertyAllowlist: []
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
function now2() {
|
|
2375
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
2376
|
+
}
|
|
2377
|
+
function spillKey() {
|
|
2378
|
+
return "mushi_events_spill_" + _projectId;
|
|
2379
|
+
}
|
|
2380
|
+
function isRetryableStatus(status) {
|
|
2381
|
+
return status === void 0 || status === 429 || status >= 500;
|
|
2382
|
+
}
|
|
2383
|
+
function analyticsIdKey() {
|
|
2384
|
+
return "mushi_analytics_id_" + _projectId;
|
|
2385
|
+
}
|
|
2386
|
+
function loadOrMintAnalyticsId() {
|
|
2387
|
+
try {
|
|
2388
|
+
const stored = localStorage.getItem(analyticsIdKey());
|
|
2389
|
+
if (stored) return stored;
|
|
2390
|
+
} catch {
|
|
2391
|
+
}
|
|
2392
|
+
return typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : "a-" + Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
2393
|
+
}
|
|
2394
|
+
function persistAnalyticsId() {
|
|
2395
|
+
if (!_anonId) return;
|
|
2396
|
+
try {
|
|
2397
|
+
if (localStorage.getItem(analyticsIdKey()) !== _anonId) localStorage.setItem(analyticsIdKey(), _anonId);
|
|
2398
|
+
} catch {
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
function hashToUnit(s) {
|
|
2402
|
+
let h = 2166136261;
|
|
2403
|
+
for (let i = 0; i < s.length; i += 1) {
|
|
2404
|
+
h ^= s.charCodeAt(i);
|
|
2405
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
2406
|
+
}
|
|
2407
|
+
return (h >>> 0) / 4294967296;
|
|
2408
|
+
}
|
|
2409
|
+
function readSpill() {
|
|
2410
|
+
try {
|
|
2411
|
+
const raw = localStorage.getItem(spillKey());
|
|
2412
|
+
if (!raw) return [];
|
|
2413
|
+
const parsed = JSON.parse(raw);
|
|
2414
|
+
if (!parsed || Date.now() - parsed.at > SPILL_TTL_MS) {
|
|
2415
|
+
localStorage.removeItem(spillKey());
|
|
2416
|
+
return [];
|
|
2417
|
+
}
|
|
2418
|
+
return Array.isArray(parsed.events) ? parsed.events.slice(0, SPILL_MAX) : [];
|
|
2419
|
+
} catch {
|
|
2420
|
+
return [];
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
function writeSpill(events) {
|
|
2424
|
+
try {
|
|
2425
|
+
if (events.length === 0) {
|
|
2426
|
+
localStorage.removeItem(spillKey());
|
|
2427
|
+
return;
|
|
2144
2428
|
}
|
|
2429
|
+
localStorage.setItem(spillKey(), JSON.stringify({ at: Date.now(), events: events.slice(-SPILL_MAX) }));
|
|
2430
|
+
} catch {
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
function takeSpill() {
|
|
2434
|
+
const events = readSpill();
|
|
2435
|
+
if (events.length > 0) writeSpill([]);
|
|
2436
|
+
return events;
|
|
2437
|
+
}
|
|
2438
|
+
function buildPayload2(events) {
|
|
2439
|
+
return {
|
|
2440
|
+
anon_id: _anonId,
|
|
2441
|
+
user_id: _userId,
|
|
2442
|
+
user_traits: _userTraits,
|
|
2443
|
+
session_id: _getSessionId ? _getSessionId() : null,
|
|
2444
|
+
sdk_version: _sdkVersion2,
|
|
2445
|
+
surface: _config.surface,
|
|
2446
|
+
events
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
async function flushNow() {
|
|
2450
|
+
if (!_client2 || _flushing || _consent !== "granted") return;
|
|
2451
|
+
if (_buffer.length === 0 && !_pendingIdentify) return;
|
|
2452
|
+
_flushing = true;
|
|
2453
|
+
persistAnalyticsId();
|
|
2454
|
+
const batch = _buffer.splice(0, EVENT_PROPERTY_LIMITS.maxServerBatch);
|
|
2455
|
+
if (_pendingIdentify) {
|
|
2456
|
+
batch.unshift({ name: "identify", ts: now2(), properties: {} });
|
|
2457
|
+
_pendingIdentify = false;
|
|
2458
|
+
}
|
|
2459
|
+
try {
|
|
2460
|
+
const res = await _client2.postProductEvents(buildPayload2(batch));
|
|
2461
|
+
if (res.ok) {
|
|
2462
|
+
writeSpill([]);
|
|
2463
|
+
} else if (isRetryableStatus(res.error?.status)) {
|
|
2464
|
+
writeSpill([...readSpill(), ...batch.filter((e) => e.name !== "identify")]);
|
|
2465
|
+
}
|
|
2466
|
+
} catch {
|
|
2467
|
+
writeSpill([...readSpill(), ...batch.filter((e) => e.name !== "identify")]);
|
|
2468
|
+
} finally {
|
|
2469
|
+
_flushing = false;
|
|
2470
|
+
}
|
|
2471
|
+
if (_buffer.length >= EVENT_PROPERTY_LIMITS.maxClientBatch) void flushNow();
|
|
2472
|
+
}
|
|
2473
|
+
function enqueue(ev) {
|
|
2474
|
+
if (_consent === "denied") return false;
|
|
2475
|
+
if (_consent === "pending") {
|
|
2476
|
+
if (_consentBuffer.length >= CONSENT_BUFFER_MAX) return false;
|
|
2477
|
+
_consentBuffer.push(ev);
|
|
2478
|
+
return true;
|
|
2479
|
+
}
|
|
2480
|
+
_buffer.push(ev);
|
|
2481
|
+
if (_buffer.length >= EVENT_PROPERTY_LIMITS.maxClientBatch) void flushNow();
|
|
2482
|
+
return true;
|
|
2483
|
+
}
|
|
2484
|
+
function applyConsent(state) {
|
|
2485
|
+
if (state === "denied") {
|
|
2486
|
+
_consent = "denied";
|
|
2487
|
+
_buffer = [];
|
|
2488
|
+
_consentBuffer = [];
|
|
2489
|
+
_pendingIdentify = false;
|
|
2490
|
+
writeSpill([]);
|
|
2491
|
+
return;
|
|
2492
|
+
}
|
|
2493
|
+
const wasPending = _consent === "pending";
|
|
2494
|
+
_consent = "granted";
|
|
2495
|
+
if (wasPending) {
|
|
2496
|
+
_buffer.push(...takeSpill(), ..._consentBuffer);
|
|
2497
|
+
_consentBuffer = [];
|
|
2498
|
+
}
|
|
2499
|
+
if (_buffer.length > 0 || _pendingIdentify) void flushNow();
|
|
2500
|
+
}
|
|
2501
|
+
function stripUndefined(o) {
|
|
2502
|
+
const out = {};
|
|
2503
|
+
for (const [k, v] of Object.entries(o)) {
|
|
2504
|
+
if (v !== void 0) out[k] = v;
|
|
2505
|
+
}
|
|
2506
|
+
return out;
|
|
2507
|
+
}
|
|
2508
|
+
function isEventTrackingActive() {
|
|
2509
|
+
return _initialized2 && _consent === "granted" && _sampledIn;
|
|
2510
|
+
}
|
|
2511
|
+
function getEventAnonymousId() {
|
|
2512
|
+
if (!_initialized2 || _consent === "denied") return null;
|
|
2513
|
+
return _anonId;
|
|
2514
|
+
}
|
|
2515
|
+
function initEventTracker(opts) {
|
|
2516
|
+
if (_initialized2) return;
|
|
2517
|
+
if (typeof window === "undefined") return;
|
|
2518
|
+
const cfg = opts.config ?? {};
|
|
2519
|
+
_config = { ...defaults(), ...stripUndefined(cfg), propertyAllowlist: cfg.propertyAllowlist ?? [] };
|
|
2520
|
+
_projectId = opts.projectId;
|
|
2521
|
+
if (analyticsBlockReason(cfg) !== null) return;
|
|
2522
|
+
_initialized2 = true;
|
|
2523
|
+
_client2 = opts.client;
|
|
2524
|
+
_anonId = opts.anonId ?? loadOrMintAnalyticsId();
|
|
2525
|
+
_userId = opts.userId ?? null;
|
|
2526
|
+
_sdkVersion2 = opts.sdkVersion;
|
|
2527
|
+
_scrub = opts.scrub;
|
|
2528
|
+
_getSessionId = opts.getSessionId;
|
|
2529
|
+
const rate = Math.min(1, Math.max(0, _config.sampleRate));
|
|
2530
|
+
_sampledIn = rate >= 1 ? true : rate <= 0 ? false : hashToUnit(_anonId ?? "anon") < rate;
|
|
2531
|
+
if (!_sampledIn) return;
|
|
2532
|
+
_consent = resolveAnalyticsConsent(_projectId, cfg);
|
|
2533
|
+
if (_consent === "granted") _buffer.push(...takeSpill());
|
|
2534
|
+
else if (_consent === "denied") writeSpill([]);
|
|
2535
|
+
_unsubscribeConsent2 = onAnalyticsConsentChange(applyConsent);
|
|
2536
|
+
const interval = Math.max(1e3, _config.flushIntervalMs);
|
|
2537
|
+
_flushTimer = setInterval(() => {
|
|
2538
|
+
void flushNow();
|
|
2539
|
+
}, interval);
|
|
2540
|
+
const onHide = () => {
|
|
2541
|
+
if (typeof document !== "undefined" && document.visibilityState === "hidden") void flushNow();
|
|
2542
|
+
};
|
|
2543
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", onHide, { passive: true });
|
|
2544
|
+
window.addEventListener("pagehide", () => {
|
|
2545
|
+
void flushNow();
|
|
2546
|
+
}, { passive: true });
|
|
2547
|
+
if (_config.autoPageviews) patchHistory();
|
|
2548
|
+
}
|
|
2549
|
+
function trackEvent(name, properties, opts) {
|
|
2550
|
+
if (!_initialized2 || !_sampledIn) return false;
|
|
2551
|
+
if (!isValidEventName(name)) return false;
|
|
2552
|
+
const { properties: props } = sanitizeEventProperties(properties, {
|
|
2553
|
+
allowlist: _config.propertyAllowlist,
|
|
2554
|
+
scrub: _scrub
|
|
2555
|
+
});
|
|
2556
|
+
let merged = props;
|
|
2557
|
+
if (opts?.reserved) {
|
|
2558
|
+
const { properties: res } = sanitizeEventProperties(opts.reserved, { allowReserved: true, scrub: _scrub });
|
|
2559
|
+
merged = { ...props, ...res };
|
|
2560
|
+
}
|
|
2561
|
+
merged.$surface = _config.surface;
|
|
2562
|
+
if (typeof location !== "undefined" && merged.$route === void 0) merged.$route = location.pathname;
|
|
2563
|
+
if (!propertiesWithinByteLimit(merged)) return false;
|
|
2564
|
+
return enqueue({
|
|
2565
|
+
name,
|
|
2566
|
+
ts: opts?.ts ?? now2(),
|
|
2567
|
+
properties: merged,
|
|
2568
|
+
...opts?.dedupKey ? { dedup_key: opts.dedupKey } : {}
|
|
2569
|
+
});
|
|
2570
|
+
}
|
|
2571
|
+
function setEventConsent(state) {
|
|
2572
|
+
if (!_initialized2) _consent = state;
|
|
2573
|
+
setAnalyticsConsent(_projectId, state);
|
|
2574
|
+
}
|
|
2575
|
+
function updateEventIdentity(userId, traits) {
|
|
2576
|
+
_userId = userId;
|
|
2577
|
+
_userTraits = traits ?? null;
|
|
2578
|
+
if (!_initialized2 || !_sampledIn || !userId || _consent === "denied") return;
|
|
2579
|
+
_pendingIdentify = true;
|
|
2580
|
+
if (_consent === "granted") void flushNow();
|
|
2581
|
+
}
|
|
2582
|
+
function flushEvents() {
|
|
2583
|
+
return flushNow();
|
|
2584
|
+
}
|
|
2585
|
+
function destroyEventTracker() {
|
|
2586
|
+
if (_flushTimer != null) {
|
|
2587
|
+
clearInterval(_flushTimer);
|
|
2588
|
+
_flushTimer = null;
|
|
2589
|
+
}
|
|
2590
|
+
_unsubscribeConsent2?.();
|
|
2591
|
+
_unsubscribeConsent2 = null;
|
|
2592
|
+
_initialized2 = false;
|
|
2593
|
+
_client2 = null;
|
|
2594
|
+
_buffer = [];
|
|
2595
|
+
_consentBuffer = [];
|
|
2596
|
+
_consent = "granted";
|
|
2597
|
+
_sampledIn = true;
|
|
2598
|
+
_pendingIdentify = false;
|
|
2599
|
+
_userId = null;
|
|
2600
|
+
_userTraits = null;
|
|
2601
|
+
_config = defaults();
|
|
2602
|
+
}
|
|
2603
|
+
var _historyPatched2 = false;
|
|
2604
|
+
function patchHistory() {
|
|
2605
|
+
if (_historyPatched2 || typeof history === "undefined") return;
|
|
2606
|
+
_historyPatched2 = true;
|
|
2607
|
+
const original = history.pushState;
|
|
2608
|
+
history.pushState = function(...args) {
|
|
2609
|
+
const result = original.apply(this, args);
|
|
2610
|
+
trackEvent("page_view");
|
|
2145
2611
|
return result;
|
|
2146
2612
|
};
|
|
2147
|
-
history.pushState = wrap(history.pushState);
|
|
2148
|
-
history.replaceState = wrap(history.replaceState);
|
|
2149
2613
|
window.addEventListener("popstate", () => {
|
|
2150
|
-
|
|
2151
|
-
send(buildPayload("page_view", { route: currentRoute() }));
|
|
2614
|
+
trackEvent("page_view");
|
|
2152
2615
|
}, { passive: true });
|
|
2153
2616
|
}
|
|
2154
2617
|
|
|
@@ -2165,12 +2628,12 @@ function createRateLimiter(config = {}) {
|
|
|
2165
2628
|
let tokens = maxBurst;
|
|
2166
2629
|
let lastRefill = Date.now();
|
|
2167
2630
|
function refill() {
|
|
2168
|
-
const
|
|
2169
|
-
const elapsed =
|
|
2631
|
+
const now3 = Date.now();
|
|
2632
|
+
const elapsed = now3 - lastRefill;
|
|
2170
2633
|
const refills = Math.floor(elapsed / refillIntervalMs);
|
|
2171
2634
|
if (refills > 0) {
|
|
2172
2635
|
tokens = Math.min(maxBurst, tokens + refills * refillRate);
|
|
2173
|
-
lastRefill =
|
|
2636
|
+
lastRefill = now3;
|
|
2174
2637
|
}
|
|
2175
2638
|
}
|
|
2176
2639
|
function tryConsume() {
|
|
@@ -2568,15 +3031,15 @@ function mushiTokens(mode) {
|
|
|
2568
3031
|
// src/identity.ts
|
|
2569
3032
|
var MUSHI_IDENTITY_TOKEN_PREFIX = "mushi.identity";
|
|
2570
3033
|
function buildIdentityClaims(input) {
|
|
2571
|
-
const
|
|
3034
|
+
const now3 = Math.floor(Date.now() / 1e3);
|
|
2572
3035
|
const ttl = input.ttlSeconds && input.ttlSeconds > 0 ? Math.min(input.ttlSeconds, 3600) : 600;
|
|
2573
3036
|
return {
|
|
2574
3037
|
projectId: input.projectId,
|
|
2575
3038
|
sub: input.userId,
|
|
2576
3039
|
...input.email ? { email: input.email } : {},
|
|
2577
3040
|
...input.name ? { name: input.name } : {},
|
|
2578
|
-
iat:
|
|
2579
|
-
exp:
|
|
3041
|
+
iat: now3,
|
|
3042
|
+
exp: now3 + ttl
|
|
2580
3043
|
};
|
|
2581
3044
|
}
|
|
2582
3045
|
function base64UrlDecode(segment) {
|
|
@@ -2803,9 +3266,13 @@ function isSafeFaviconHref(href) {
|
|
|
2803
3266
|
}
|
|
2804
3267
|
}
|
|
2805
3268
|
|
|
3269
|
+
exports.ACTIVATION_EVENT = ACTIVATION_EVENT;
|
|
2806
3270
|
exports.DEFAULT_API_ENDPOINT = DEFAULT_API_ENDPOINT;
|
|
2807
3271
|
exports.DEFAULT_MAX_RETRIES = DEFAULT_MAX_RETRIES;
|
|
2808
3272
|
exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
|
|
3273
|
+
exports.EVENT_NAME_RE = EVENT_NAME_RE;
|
|
3274
|
+
exports.EVENT_PROPERTY_LIMITS = EVENT_PROPERTY_LIMITS;
|
|
3275
|
+
exports.HABIT_EVENTS = HABIT_EVENTS;
|
|
2809
3276
|
exports.MAX_REPORT_PAYLOAD_BYTES = MAX_REPORT_PAYLOAD_BYTES;
|
|
2810
3277
|
exports.MAX_SCREENSHOT_DATA_URL_BYTES = MAX_SCREENSHOT_DATA_URL_BYTES;
|
|
2811
3278
|
exports.MUSHI_ACCENT_SHADOW = MUSHI_ACCENT_SHADOW;
|
|
@@ -2818,6 +3285,8 @@ exports.MUSHI_COLORS_LIGHT = MUSHI_COLORS_LIGHT;
|
|
|
2818
3285
|
exports.MUSHI_CONTROL_DISABLED = MUSHI_CONTROL_DISABLED;
|
|
2819
3286
|
exports.MUSHI_COPY = MUSHI_COPY;
|
|
2820
3287
|
exports.MUSHI_DURATION = MUSHI_DURATION;
|
|
3288
|
+
exports.MUSHI_EVENTS = MUSHI_EVENTS;
|
|
3289
|
+
exports.MUSHI_EVENT_NAMES = MUSHI_EVENT_NAMES;
|
|
2821
3290
|
exports.MUSHI_GEOMETRY = MUSHI_GEOMETRY;
|
|
2822
3291
|
exports.MUSHI_IDENTITY_TOKEN_PREFIX = MUSHI_IDENTITY_TOKEN_PREFIX;
|
|
2823
3292
|
exports.MUSHI_INTERNAL_HEADER = MUSHI_INTERNAL_HEADER;
|
|
@@ -2834,11 +3303,13 @@ exports.MUSHI_SDK_PACKAGE_HEADER = MUSHI_SDK_PACKAGE_HEADER;
|
|
|
2834
3303
|
exports.MUSHI_SDK_VERSION_HEADER = MUSHI_SDK_VERSION_HEADER;
|
|
2835
3304
|
exports.MUSHI_SHADOW_INK = MUSHI_SHADOW_INK;
|
|
2836
3305
|
exports.MUSHI_SPACING = MUSHI_SPACING;
|
|
3306
|
+
exports.MUSHI_SURFACES = MUSHI_SURFACES;
|
|
2837
3307
|
exports.MUSHI_TIER_COLORS = MUSHI_TIER_COLORS;
|
|
2838
3308
|
exports.MUSHI_TYPE = MUSHI_TYPE;
|
|
2839
3309
|
exports.MUSHI_USER_TOKEN_HEADER = MUSHI_USER_TOKEN_HEADER;
|
|
2840
3310
|
exports.MUSHI_Z = MUSHI_Z;
|
|
2841
3311
|
exports.REGION_ENDPOINTS = REGION_ENDPOINTS;
|
|
3312
|
+
exports.analyticsBlockReason = analyticsBlockReason;
|
|
2842
3313
|
exports.buildBeaconEnvelope = buildBeaconEnvelope;
|
|
2843
3314
|
exports.buildIdentityClaims = buildIdentityClaims;
|
|
2844
3315
|
exports.buildSdkIngestHeaders = buildSdkIngestHeaders;
|
|
@@ -2851,26 +3322,34 @@ exports.createOfflineQueue = createOfflineQueue;
|
|
|
2851
3322
|
exports.createPiiScrubber = createPiiScrubber;
|
|
2852
3323
|
exports.createPreFilter = createPreFilter;
|
|
2853
3324
|
exports.createRateLimiter = createRateLimiter;
|
|
3325
|
+
exports.destroyEventTracker = destroyEventTracker;
|
|
2854
3326
|
exports.destroySessionTracker = destroySessionTracker;
|
|
2855
3327
|
exports.diagnoseEnvConfig = diagnoseEnvConfig;
|
|
3328
|
+
exports.dntActive = dntActive;
|
|
2856
3329
|
exports.estimateJsonBytes = estimateJsonBytes;
|
|
2857
3330
|
exports.expandPreset = expandPreset;
|
|
2858
3331
|
exports.extractTunnelPath = extractTunnelPath;
|
|
2859
3332
|
exports.faviconUrlCandidates = faviconUrlCandidates;
|
|
3333
|
+
exports.flushEvents = flushEvents;
|
|
2860
3334
|
exports.flushLastOutboundOnUnload = flushLastOutboundOnUnload;
|
|
2861
3335
|
exports.formatBytes = formatBytes;
|
|
2862
3336
|
exports.getBackoffDelay = getBackoffDelay;
|
|
2863
3337
|
exports.getDeviceFingerprintHash = getDeviceFingerprintHash;
|
|
3338
|
+
exports.getEventAnonymousId = getEventAnonymousId;
|
|
2864
3339
|
exports.getReporterToken = getReporterToken;
|
|
2865
3340
|
exports.getSessionId = getSessionId;
|
|
2866
3341
|
exports.githubRepoDomainHint = githubRepoDomainHint;
|
|
2867
3342
|
exports.hmacSha256Hex = hmacSha256Hex;
|
|
3343
|
+
exports.initEventTracker = initEventTracker;
|
|
2868
3344
|
exports.initSessionTracker = initSessionTracker;
|
|
3345
|
+
exports.isAutomatedBrowser = isAutomatedBrowser;
|
|
3346
|
+
exports.isEventTrackingActive = isEventTrackingActive;
|
|
2869
3347
|
exports.isLikelyGenericFavicon = isLikelyGenericFavicon;
|
|
2870
3348
|
exports.isMushiBeaconEnvelope = isMushiBeaconEnvelope;
|
|
2871
3349
|
exports.isPageUnloading = isPageUnloading;
|
|
2872
3350
|
exports.isSameOriginOrRelative = isSameOriginOrRelative;
|
|
2873
3351
|
exports.isUntrustedFaviconUrl = isUntrustedFaviconUrl;
|
|
3352
|
+
exports.isValidEventName = isValidEventName;
|
|
2874
3353
|
exports.markPageUnloading = markPageUnloading;
|
|
2875
3354
|
exports.matchesErrorFilter = matchesErrorFilter;
|
|
2876
3355
|
exports.mushiPalette = mushiPalette;
|
|
@@ -2878,13 +3357,16 @@ exports.mushiTokens = mushiTokens;
|
|
|
2878
3357
|
exports.newUuid = newUuid;
|
|
2879
3358
|
exports.noopLogger = noopLogger;
|
|
2880
3359
|
exports.normaliseThrown = normaliseThrown;
|
|
3360
|
+
exports.onAnalyticsConsentChange = onAnalyticsConsentChange;
|
|
2881
3361
|
exports.originToDomain = originToDomain;
|
|
2882
3362
|
exports.parseIdentityToken = parseIdentityToken;
|
|
2883
3363
|
exports.parseRetryAfter = parseRetryAfter;
|
|
2884
3364
|
exports.projectFaviconUrlCandidates = projectFaviconUrlCandidates;
|
|
2885
3365
|
exports.projectInitials = projectInitials;
|
|
2886
3366
|
exports.projectInitialsThemeIndex = projectInitialsThemeIndex;
|
|
3367
|
+
exports.propertiesWithinByteLimit = propertiesWithinByteLimit;
|
|
2887
3368
|
exports.readPageFaviconHref = readPageFaviconHref;
|
|
3369
|
+
exports.resolveAnalyticsConsent = resolveAnalyticsConsent;
|
|
2888
3370
|
exports.resolveEnvConfig = resolveEnvConfig;
|
|
2889
3371
|
exports.resolveProjectDomain = resolveProjectDomain;
|
|
2890
3372
|
exports.resolveProjectFaviconDomains = resolveProjectFaviconDomains;
|
|
@@ -2892,12 +3374,17 @@ exports.resolveRegionEndpoint = resolveRegionEndpoint;
|
|
|
2892
3374
|
exports.resolveRequestBaseUrl = resolveRequestBaseUrl;
|
|
2893
3375
|
exports.resolveWidgetAccent = resolveWidgetAccent;
|
|
2894
3376
|
exports.safeWidgetHex = safeWidgetHex;
|
|
3377
|
+
exports.sanitizeEventProperties = sanitizeEventProperties;
|
|
2895
3378
|
exports.scrubPii = scrubPii;
|
|
2896
3379
|
exports.scrubUrl = scrubUrl;
|
|
2897
3380
|
exports.sendOnUnload = sendOnUnload;
|
|
3381
|
+
exports.setAnalyticsConsent = setAnalyticsConsent;
|
|
3382
|
+
exports.setEventConsent = setEventConsent;
|
|
2898
3383
|
exports.sha256Hex = sha256Hex;
|
|
2899
3384
|
exports.shouldDropCapturedError = shouldDropCapturedError;
|
|
3385
|
+
exports.trackEvent = trackEvent;
|
|
2900
3386
|
exports.trackPageView = trackPageView;
|
|
3387
|
+
exports.updateEventIdentity = updateEventIdentity;
|
|
2901
3388
|
exports.updateSessionIdentity = updateSessionIdentity;
|
|
2902
3389
|
exports.validateConfig = validateConfig;
|
|
2903
3390
|
//# sourceMappingURL=index.cjs.map
|