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