@mushi-mushi/core 1.32.0 → 1.32.3
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 +2 -2
- package/dist/index.cjs +63 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -10
- package/dist/index.d.ts +12 -10
- package/dist/index.js +63 -30
- package/dist/index.js.map +1 -1
- package/dist/reporter-channels.d.cts +1 -1
- package/dist/reporter-channels.d.ts +1 -1
- package/dist/{types-0j5BJ3aC.d.cts → types-DhR6TWJZ.d.cts} +55 -21
- package/dist/{types-0j5BJ3aC.d.ts → types-DhR6TWJZ.d.ts} +55 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,13 +48,13 @@ const resolved = expandPreset(config); // preset → nested options, explicit va
|
|
|
48
48
|
|
|
49
49
|
## Sampling and filters
|
|
50
50
|
|
|
51
|
-
Sampling
|
|
51
|
+
Sampling applies to **automatic** error reports, and the error filters to automatic reports and `captureException()`. A report a user sends from the widget is never sampled or filtered out. Only your own `beforeSend` can change or drop it.
|
|
52
52
|
|
|
53
53
|
| Field | Default | What it does |
|
|
54
54
|
| --- | --- | --- |
|
|
55
55
|
| `sampleRate` | `1` | Share of automatic error reports to send (`0`–`1`) |
|
|
56
56
|
| `replaySampleRate` | `1` | Share of sessions that record replay |
|
|
57
|
-
| `ignoreErrors` / `denyUrls` / `allowUrls` | — | Drop matching automatic
|
|
57
|
+
| `ignoreErrors` / `denyUrls` / `allowUrls` | — | Drop matching errors from automatic capture and `captureException()`. URLs match the frame that threw |
|
|
58
58
|
| `beforeSend` | — | `(report) => report \| null` for every report, after the PII scrubber. Return `null` to drop |
|
|
59
59
|
| `tunnel` | — | Same-origin ingest path (e.g. `/api/mushi-tunnel`) so ad blockers don't drop reports |
|
|
60
60
|
|
package/dist/index.cjs
CHANGED
|
@@ -169,8 +169,9 @@ function isPageUnloading() {
|
|
|
169
169
|
// src/api-client.ts
|
|
170
170
|
var lastOutbound = null;
|
|
171
171
|
function flushLastOutboundOnUnload() {
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
const outbound = lastOutbound;
|
|
173
|
+
lastOutbound = null;
|
|
174
|
+
return !!outbound && sendOnUnload(outbound);
|
|
174
175
|
}
|
|
175
176
|
var _credWarningEmitted = false;
|
|
176
177
|
var MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
|
|
@@ -252,8 +253,10 @@ function createApiClient(options) {
|
|
|
252
253
|
...extraHeaders
|
|
253
254
|
};
|
|
254
255
|
const serialized = body ? JSON.stringify(body) : void 0;
|
|
256
|
+
let outbound = null;
|
|
255
257
|
if (serialized && method !== "GET" && internalKind !== "reporter-poll") {
|
|
256
|
-
|
|
258
|
+
outbound = { url, headers, body: serialized, path };
|
|
259
|
+
lastOutbound = outbound;
|
|
257
260
|
}
|
|
258
261
|
try {
|
|
259
262
|
const response = await fetch(url, {
|
|
@@ -323,6 +326,8 @@ function createApiClient(options) {
|
|
|
323
326
|
message: error instanceof Error ? error.message : "Unknown network error"
|
|
324
327
|
}
|
|
325
328
|
};
|
|
329
|
+
} finally {
|
|
330
|
+
if (lastOutbound === outbound) lastOutbound = null;
|
|
326
331
|
}
|
|
327
332
|
}
|
|
328
333
|
async function requestForReporter(method, path, reporterToken, body) {
|
|
@@ -620,6 +625,7 @@ function matchesErrorFilter(value, filters) {
|
|
|
620
625
|
continue;
|
|
621
626
|
}
|
|
622
627
|
try {
|
|
628
|
+
filter.lastIndex = 0;
|
|
623
629
|
if (filter.test(value)) return true;
|
|
624
630
|
} catch {
|
|
625
631
|
}
|
|
@@ -1590,14 +1596,10 @@ function createOfflineQueue(config = {}) {
|
|
|
1590
1596
|
});
|
|
1591
1597
|
break;
|
|
1592
1598
|
}
|
|
1593
|
-
const permanent = result.error?.code === "HTTP_400" || result.error?.code === "HTTP_413" || result.error?.code === "HTTP_422" || result.error?.code === "INGEST_ERROR" || result.error?.code === "VALIDATION_ERROR" ||
|
|
1594
|
-
// retrying re-serialises the multi-MB body every sync tick and wedges
|
|
1595
|
-
// the queue (it matches neither permanent nor transient otherwise).
|
|
1596
|
-
// SERIALIZE_FAILED (circular ref) is likewise unrecoverable on retry.
|
|
1597
|
-
result.error?.code === "PAYLOAD_TOO_LARGE" || result.error?.code === "SERIALIZE_FAILED" || typeof result.error?.message === "string" && /invalid payload|description must be at least|validation/i.test(
|
|
1599
|
+
const permanent = result.error?.code === "HTTP_400" || result.error?.status === 401 || result.error?.status === 403 || result.error?.code === "HTTP_401" || result.error?.code === "HTTP_403" || result.error?.code === "HTTP_413" || result.error?.code === "HTTP_422" || result.error?.code === "INGEST_ERROR" || result.error?.code === "VALIDATION_ERROR" || result.error?.code === "PAYLOAD_TOO_LARGE" || result.error?.code === "SERIALIZE_FAILED" || typeof result.error?.message === "string" && /invalid payload|description must be at least|validation/i.test(
|
|
1598
1600
|
result.error.message
|
|
1599
1601
|
);
|
|
1600
|
-
const transient = !permanent && (result.error?.code === "NETWORK_ERROR" || result.error?.code === "
|
|
1602
|
+
const transient = !permanent && (result.error?.code === "NETWORK_ERROR" || result.error?.code === "HTTP_429" || result.error?.code === "HTTP_502" || result.error?.code === "HTTP_503" || result.error?.code === "HTTP_504" || typeof result.error?.code === "string" && result.error.code.startsWith("HTTP_5"));
|
|
1601
1603
|
if (permanent) {
|
|
1602
1604
|
await removeRow(backend, rowId);
|
|
1603
1605
|
} else {
|
|
@@ -2042,7 +2044,7 @@ function randomSuffix() {
|
|
|
2042
2044
|
}
|
|
2043
2045
|
let n = 0;
|
|
2044
2046
|
for (const b of bytes) n = n * 256 + b >>> 0;
|
|
2045
|
-
return n.toString(36).padStart(6, "0")
|
|
2047
|
+
return (n % 36 ** 6).toString(36).padStart(6, "0");
|
|
2046
2048
|
}
|
|
2047
2049
|
|
|
2048
2050
|
// src/analytics-gate.ts
|
|
@@ -2114,7 +2116,9 @@ var _sdkVersion;
|
|
|
2114
2116
|
var _userIdHash = null;
|
|
2115
2117
|
var _reporterToken = null;
|
|
2116
2118
|
var _pageViewCount = 0;
|
|
2117
|
-
var _heartbeatTimer
|
|
2119
|
+
var _heartbeatTimer;
|
|
2120
|
+
var _lastRoute = null;
|
|
2121
|
+
var _endSent = false;
|
|
2118
2122
|
var _initialized = false;
|
|
2119
2123
|
var _active = false;
|
|
2120
2124
|
var _started = false;
|
|
@@ -2156,30 +2160,62 @@ function send(payload) {
|
|
|
2156
2160
|
if (!_client || !_active) return;
|
|
2157
2161
|
_client.postSessionEvent(payload).catch(() => {
|
|
2158
2162
|
});
|
|
2163
|
+
scheduleHeartbeat();
|
|
2164
|
+
}
|
|
2165
|
+
function clearHeartbeat() {
|
|
2166
|
+
clearTimeout(_heartbeatTimer);
|
|
2167
|
+
}
|
|
2168
|
+
function scheduleHeartbeat() {
|
|
2169
|
+
clearHeartbeat();
|
|
2170
|
+
if (!_active || globalThis.document?.visibilityState === "hidden") return;
|
|
2171
|
+
_heartbeatTimer = setTimeout(() => {
|
|
2172
|
+
send(buildPayload("session_heartbeat", { route: currentRoute() }));
|
|
2173
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
2159
2174
|
}
|
|
2160
2175
|
function recordPageView(route) {
|
|
2161
2176
|
if (!_active) return;
|
|
2177
|
+
if (route === _lastRoute) return;
|
|
2178
|
+
_lastRoute = route;
|
|
2162
2179
|
_pageViewCount += 1;
|
|
2163
2180
|
send(buildPayload("page_view", { route }));
|
|
2164
2181
|
}
|
|
2182
|
+
function sendSessionEnd() {
|
|
2183
|
+
if (_endSent || !_active) return;
|
|
2184
|
+
_endSent = true;
|
|
2185
|
+
send(buildPayload("session_end", { route: currentRoute() }));
|
|
2186
|
+
clearHeartbeat();
|
|
2187
|
+
}
|
|
2165
2188
|
function activate() {
|
|
2166
2189
|
if (_active || !_initialized) return;
|
|
2167
2190
|
_active = true;
|
|
2168
2191
|
if (!_started) {
|
|
2169
2192
|
_started = true;
|
|
2170
2193
|
_pageViewCount = 1;
|
|
2171
|
-
|
|
2194
|
+
_lastRoute = currentRoute();
|
|
2195
|
+
send(buildPayload("session_start", { route: _lastRoute, referrer: referrerOrigin() }));
|
|
2196
|
+
} else {
|
|
2197
|
+
scheduleHeartbeat();
|
|
2172
2198
|
}
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2199
|
+
}
|
|
2200
|
+
function onHide() {
|
|
2201
|
+
if (document.visibilityState === "hidden") {
|
|
2202
|
+
sendSessionEnd();
|
|
2203
|
+
} else {
|
|
2204
|
+
_endSent = false;
|
|
2205
|
+
scheduleHeartbeat();
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
function onPagehide() {
|
|
2209
|
+
sendSessionEnd();
|
|
2210
|
+
}
|
|
2211
|
+
function onPageshow(event) {
|
|
2212
|
+
if (!event.persisted) return;
|
|
2213
|
+
_endSent = false;
|
|
2214
|
+
scheduleHeartbeat();
|
|
2176
2215
|
}
|
|
2177
2216
|
function deactivate() {
|
|
2178
2217
|
_active = false;
|
|
2179
|
-
|
|
2180
|
-
clearInterval(_heartbeatTimer);
|
|
2181
|
-
_heartbeatTimer = null;
|
|
2182
|
-
}
|
|
2218
|
+
clearHeartbeat();
|
|
2183
2219
|
}
|
|
2184
2220
|
function initSessionTracker(opts) {
|
|
2185
2221
|
if (_initialized || typeof window === "undefined") return;
|
|
@@ -2189,17 +2225,11 @@ function initSessionTracker(opts) {
|
|
|
2189
2225
|
_sdkVersion = opts.sdkVersion;
|
|
2190
2226
|
_reporterToken = opts.reporterToken ?? opts.reporterTokenHash ?? null;
|
|
2191
2227
|
_userIdHash = opts.userIdHash ?? null;
|
|
2192
|
-
const onHide = () => {
|
|
2193
|
-
if (typeof document !== "undefined" && document.visibilityState === "hidden") {
|
|
2194
|
-
send(buildPayload("session_end", { route: currentRoute() }));
|
|
2195
|
-
}
|
|
2196
|
-
};
|
|
2197
2228
|
if (typeof document !== "undefined") {
|
|
2198
2229
|
document.addEventListener("visibilitychange", onHide, { passive: true });
|
|
2199
2230
|
}
|
|
2200
|
-
window.addEventListener("pagehide",
|
|
2201
|
-
|
|
2202
|
-
}, { passive: true });
|
|
2231
|
+
window.addEventListener("pagehide", onPagehide, { passive: true });
|
|
2232
|
+
window.addEventListener("pageshow", onPageshow, { passive: true });
|
|
2203
2233
|
if (opts.patchHistory !== false) {
|
|
2204
2234
|
patchHistoryForPageViews();
|
|
2205
2235
|
}
|
|
@@ -2214,6 +2244,7 @@ function trackPageView(route) {
|
|
|
2214
2244
|
recordPageView(route ?? currentRoute());
|
|
2215
2245
|
}
|
|
2216
2246
|
function updateSessionIdentity(userIdHash) {
|
|
2247
|
+
if (userIdHash && userIdHash !== _userIdHash) _lastRoute = null;
|
|
2217
2248
|
_userIdHash = userIdHash;
|
|
2218
2249
|
}
|
|
2219
2250
|
function destroySessionTracker() {
|
|
@@ -2222,6 +2253,8 @@ function destroySessionTracker() {
|
|
|
2222
2253
|
_unsubscribeConsent = null;
|
|
2223
2254
|
_initialized = false;
|
|
2224
2255
|
_started = false;
|
|
2256
|
+
_lastRoute = null;
|
|
2257
|
+
_endSent = false;
|
|
2225
2258
|
_client = null;
|
|
2226
2259
|
}
|
|
2227
2260
|
var _historyPatched = false;
|
|
@@ -2543,10 +2576,10 @@ function initEventTracker(opts) {
|
|
|
2543
2576
|
_flushTimer = setInterval(() => {
|
|
2544
2577
|
void flushNow();
|
|
2545
2578
|
}, interval);
|
|
2546
|
-
const
|
|
2579
|
+
const onHide2 = () => {
|
|
2547
2580
|
if (typeof document !== "undefined" && document.visibilityState === "hidden") void flushNow();
|
|
2548
2581
|
};
|
|
2549
|
-
if (typeof document !== "undefined") document.addEventListener("visibilitychange",
|
|
2582
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", onHide2, { passive: true });
|
|
2550
2583
|
window.addEventListener("pagehide", () => {
|
|
2551
2584
|
void flushNow();
|
|
2552
2585
|
}, { passive: true });
|
|
@@ -3010,7 +3043,7 @@ function resolveWidgetAccent(mode, accent = "", accentText = "") {
|
|
|
3010
3043
|
return { accent: resolvedAccent, accentWash, accentInk };
|
|
3011
3044
|
}
|
|
3012
3045
|
var MUSHI_COPY = {
|
|
3013
|
-
bannerLabel: "
|
|
3046
|
+
bannerLabel: "Feedback",
|
|
3014
3047
|
bannerMessage: "Found a bug? Tap to report it.",
|
|
3015
3048
|
bugCta: "Report a bug",
|
|
3016
3049
|
featureCta: "Feature request",
|