@mushi-mushi/core 1.27.2 → 1.28.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 +4 -1
- package/dist/index.cjs +168 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +122 -1
- package/dist/index.d.ts +122 -1
- package/dist/index.js +155 -16
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -96,6 +96,9 @@ Top-level `MushiConfig` fields (consumed by `@mushi-mushi/web` and framework wra
|
|
|
96
96
|
|-------|---------|----------|
|
|
97
97
|
| `sampleRate` | `1` | Probabilistic gate for **automatic** error reports (`0`–`1`). User-initiated feedback always sends. |
|
|
98
98
|
| `replaySampleRate` | `1` | Probabilistic gate for session replay; decided once at session init. Independent of `sampleRate`. |
|
|
99
|
+
| `replaysOnErrorSampleRate` | `0` | Start a replay buffer on automatic errors when session sample missed. Keep `0` unless you explicitly want rrweb. |
|
|
100
|
+
| `tunnel` | — | Same-origin ingest base (e.g. `/api/mushi-tunnel`). Wins over `apiEndpoint` so browser calls stay first-party. Pagehide uses `fetch` keepalive, then a `{ mushiBeacon, path, headers, body }` envelope because `sendBeacon` cannot set headers. |
|
|
101
|
+
| `ignoreErrors` / `denyUrls` / `allowUrls` | — | Drop **automatic** captures only. Never applied to user widget feedback. |
|
|
99
102
|
| `beforeSend` | — | `(report) => report \| null \| Promise<…>` after built-in PII scrub. Return `null` to drop. |
|
|
100
103
|
| `beforeSendFeedback` | — | Deprecated feedback-only hook; ignored when `beforeSend` is set. |
|
|
101
104
|
|
|
@@ -138,4 +141,4 @@ MIT
|
|
|
138
141
|
<!-- mushi-readme-stats-footer -->
|
|
139
142
|
---
|
|
140
143
|
|
|
141
|
-
<sub>Monorepo scale (July 2026):
|
|
144
|
+
<sub>Monorepo scale (July 2026): 58 edge functions · 347 SQL migrations · 13 outbound plugins · 11 inbound adapters · 19 pipeline agents. Canonical counts: <a href="https://github.com/kensaurus/mushi-mushi/blob/master/docs/stats.md">docs/stats.md</a> · <code>pnpm docs-stats</code></sub>
|
package/dist/index.cjs
CHANGED
|
@@ -86,7 +86,92 @@ async function hmacSha256Hex(secret, value) {
|
|
|
86
86
|
return bytesToHex(result);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
// src/unload-transport.ts
|
|
90
|
+
var MUSHI_BEACON_MAX_BYTES = 60 * 1024;
|
|
91
|
+
function isMushiBeaconEnvelope(value) {
|
|
92
|
+
if (!value || typeof value !== "object") return false;
|
|
93
|
+
const rec = value;
|
|
94
|
+
return rec.mushiBeacon === true && typeof rec.path === "string" && rec.headers !== null && typeof rec.headers === "object";
|
|
95
|
+
}
|
|
96
|
+
function buildBeaconEnvelope(opts) {
|
|
97
|
+
return {
|
|
98
|
+
mushiBeacon: true,
|
|
99
|
+
path: opts.path,
|
|
100
|
+
headers: opts.headers,
|
|
101
|
+
body: opts.body
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function isSameOriginOrRelative(url, origin = typeof location !== "undefined" ? location.origin : "") {
|
|
105
|
+
if (!url) return false;
|
|
106
|
+
if (url.startsWith("/")) return true;
|
|
107
|
+
if (!origin) return false;
|
|
108
|
+
try {
|
|
109
|
+
return new URL(url, origin).origin === origin;
|
|
110
|
+
} catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function extractTunnelPath(url) {
|
|
115
|
+
try {
|
|
116
|
+
const parsed = url.startsWith("/") ? new URL(url, "https://tunnel.local") : new URL(url);
|
|
117
|
+
return `${parsed.pathname}${parsed.search}`;
|
|
118
|
+
} catch {
|
|
119
|
+
return url;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function sendOnUnload(opts) {
|
|
123
|
+
const fetchImpl = opts.fetchImpl ?? (typeof fetch === "function" ? fetch : void 0);
|
|
124
|
+
if (fetchImpl) {
|
|
125
|
+
try {
|
|
126
|
+
void fetchImpl(opts.url, {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: {
|
|
129
|
+
"Content-Type": "application/json",
|
|
130
|
+
...opts.headers
|
|
131
|
+
},
|
|
132
|
+
body: opts.body,
|
|
133
|
+
keepalive: true
|
|
134
|
+
});
|
|
135
|
+
return true;
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const beacon = opts.sendBeacon ?? (typeof navigator !== "undefined" ? navigator.sendBeacon?.bind(navigator) : void 0);
|
|
140
|
+
if (!beacon || !isSameOriginOrRelative(opts.url)) return false;
|
|
141
|
+
let parsedBody = opts.body;
|
|
142
|
+
try {
|
|
143
|
+
parsedBody = JSON.parse(opts.body);
|
|
144
|
+
} catch {
|
|
145
|
+
parsedBody = opts.body;
|
|
146
|
+
}
|
|
147
|
+
const envelope = JSON.stringify(
|
|
148
|
+
buildBeaconEnvelope({
|
|
149
|
+
path: opts.path ?? extractTunnelPath(opts.url),
|
|
150
|
+
headers: opts.headers,
|
|
151
|
+
body: parsedBody
|
|
152
|
+
})
|
|
153
|
+
);
|
|
154
|
+
if (envelope.length > MUSHI_BEACON_MAX_BYTES) return false;
|
|
155
|
+
try {
|
|
156
|
+
return beacon(opts.url, new Blob([envelope], { type: "application/json" }));
|
|
157
|
+
} catch {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
var pageUnloading = false;
|
|
162
|
+
function markPageUnloading() {
|
|
163
|
+
pageUnloading = true;
|
|
164
|
+
}
|
|
165
|
+
function isPageUnloading() {
|
|
166
|
+
return pageUnloading;
|
|
167
|
+
}
|
|
168
|
+
|
|
89
169
|
// src/api-client.ts
|
|
170
|
+
var lastOutbound = null;
|
|
171
|
+
function flushLastOutboundOnUnload() {
|
|
172
|
+
if (!lastOutbound) return false;
|
|
173
|
+
return sendOnUnload(lastOutbound);
|
|
174
|
+
}
|
|
90
175
|
var _credWarningEmitted = false;
|
|
91
176
|
var MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
|
|
92
177
|
var MUSHI_PROJECT_HEADER = "X-Mushi-Project";
|
|
@@ -107,6 +192,11 @@ function buildSdkIngestHeaders(opts) {
|
|
|
107
192
|
var DEFAULT_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api";
|
|
108
193
|
var MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
|
|
109
194
|
var MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
|
|
195
|
+
function resolveRequestBaseUrl(apiEndpoint, tunnel) {
|
|
196
|
+
const trimmedTunnel = tunnel?.trim();
|
|
197
|
+
if (trimmedTunnel) return trimmedTunnel.replace(/\/$/, "");
|
|
198
|
+
return (apiEndpoint ?? DEFAULT_API_ENDPOINT).replace(/\/$/, "");
|
|
199
|
+
}
|
|
110
200
|
var DEFAULT_TIMEOUT = 1e4;
|
|
111
201
|
var DEFAULT_MAX_RETRIES = 2;
|
|
112
202
|
var DEFAULT_CIRCUIT_THRESHOLD = 4;
|
|
@@ -117,6 +207,7 @@ function createApiClient(options) {
|
|
|
117
207
|
projectId,
|
|
118
208
|
apiKey,
|
|
119
209
|
apiEndpoint = DEFAULT_API_ENDPOINT,
|
|
210
|
+
tunnel,
|
|
120
211
|
timeout = DEFAULT_TIMEOUT,
|
|
121
212
|
maxRetries = DEFAULT_MAX_RETRIES,
|
|
122
213
|
getUserToken,
|
|
@@ -124,7 +215,7 @@ function createApiClient(options) {
|
|
|
124
215
|
sdkVersion,
|
|
125
216
|
circuitBreaker
|
|
126
217
|
} = options;
|
|
127
|
-
let baseUrl = apiEndpoint
|
|
218
|
+
let baseUrl = resolveRequestBaseUrl(apiEndpoint, tunnel);
|
|
128
219
|
const cbEnabled = circuitBreaker?.enabled !== false;
|
|
129
220
|
const cbThreshold = Math.max(1, circuitBreaker?.threshold ?? DEFAULT_CIRCUIT_THRESHOLD);
|
|
130
221
|
const cbCooldownMs = Math.max(1e3, circuitBreaker?.cooldownMs ?? DEFAULT_CIRCUIT_COOLDOWN_MS);
|
|
@@ -148,21 +239,27 @@ function createApiClient(options) {
|
|
|
148
239
|
const controller = new AbortController();
|
|
149
240
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
150
241
|
const userToken = getUserToken?.() ?? null;
|
|
242
|
+
const headers = {
|
|
243
|
+
...buildSdkIngestHeaders({
|
|
244
|
+
apiKey,
|
|
245
|
+
projectId,
|
|
246
|
+
sdkPackage,
|
|
247
|
+
sdkVersion,
|
|
248
|
+
userToken,
|
|
249
|
+
internalKind
|
|
250
|
+
}),
|
|
251
|
+
...extraHeaders
|
|
252
|
+
};
|
|
253
|
+
const serialized = body ? JSON.stringify(body) : void 0;
|
|
254
|
+
if (serialized && method !== "GET") {
|
|
255
|
+
lastOutbound = { url, headers, body: serialized, path };
|
|
256
|
+
}
|
|
151
257
|
try {
|
|
152
258
|
const response = await fetch(url, {
|
|
153
259
|
method,
|
|
154
|
-
headers
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
projectId,
|
|
158
|
-
sdkPackage,
|
|
159
|
-
sdkVersion,
|
|
160
|
-
userToken,
|
|
161
|
-
internalKind
|
|
162
|
-
}),
|
|
163
|
-
...extraHeaders
|
|
164
|
-
},
|
|
165
|
-
body: body ? JSON.stringify(body) : void 0,
|
|
260
|
+
headers,
|
|
261
|
+
body: serialized,
|
|
262
|
+
keepalive: isPageUnloading(),
|
|
166
263
|
signal: controller.signal,
|
|
167
264
|
...internalKind ? { [MUSHI_INTERNAL_INIT_MARKER]: internalKind } : {}
|
|
168
265
|
});
|
|
@@ -243,6 +340,7 @@ function createApiClient(options) {
|
|
|
243
340
|
"X-Reporter-Hmac": hmac
|
|
244
341
|
},
|
|
245
342
|
body: body ? JSON.stringify(body) : void 0,
|
|
343
|
+
keepalive: isPageUnloading(),
|
|
246
344
|
[MUSHI_INTERNAL_INIT_MARKER]: "reporter-poll"
|
|
247
345
|
});
|
|
248
346
|
if (!response.ok) {
|
|
@@ -518,6 +616,32 @@ function isRetryable(error) {
|
|
|
518
616
|
return false;
|
|
519
617
|
}
|
|
520
618
|
|
|
619
|
+
// src/error-filters.ts
|
|
620
|
+
function matchesErrorFilter(value, filters) {
|
|
621
|
+
if (!value || !filters || filters.length === 0) return false;
|
|
622
|
+
for (const filter of filters) {
|
|
623
|
+
if (typeof filter === "string") {
|
|
624
|
+
if (value.includes(filter)) return true;
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
try {
|
|
628
|
+
if (filter.test(value)) return true;
|
|
629
|
+
} catch {
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
function shouldDropCapturedError(input) {
|
|
635
|
+
if (matchesErrorFilter(input.message, input.ignoreErrors)) return true;
|
|
636
|
+
const filename = input.filename?.trim() || "";
|
|
637
|
+
if (filename && matchesErrorFilter(filename, input.denyUrls)) return true;
|
|
638
|
+
if (input.allowUrls && input.allowUrls.length > 0) {
|
|
639
|
+
if (!filename) return true;
|
|
640
|
+
if (!matchesErrorFilter(filename, input.allowUrls)) return true;
|
|
641
|
+
}
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
|
|
521
645
|
// src/region.ts
|
|
522
646
|
var REGION_ENDPOINTS = {
|
|
523
647
|
us: DEFAULT_API_ENDPOINT,
|
|
@@ -696,6 +820,7 @@ var KNOWN_CONFIG_KEYS = [
|
|
|
696
820
|
"projectId",
|
|
697
821
|
"apiKey",
|
|
698
822
|
"apiEndpoint",
|
|
823
|
+
"tunnel",
|
|
699
824
|
"timeout",
|
|
700
825
|
"maxRetries",
|
|
701
826
|
"circuitBreaker",
|
|
@@ -715,8 +840,13 @@ var KNOWN_CONFIG_KEYS = [
|
|
|
715
840
|
"enabled",
|
|
716
841
|
"appVersion",
|
|
717
842
|
"sampleRate",
|
|
843
|
+
"replaySampleRate",
|
|
844
|
+
"replaysOnErrorSampleRate",
|
|
718
845
|
"beforeSend",
|
|
719
846
|
"beforeSendFeedback",
|
|
847
|
+
"ignoreErrors",
|
|
848
|
+
"denyUrls",
|
|
849
|
+
"allowUrls",
|
|
720
850
|
"onCrashedLastRun"
|
|
721
851
|
];
|
|
722
852
|
function presetDefaults(preset) {
|
|
@@ -2486,13 +2616,22 @@ var SLUG_DOMAIN_HINTS = {
|
|
|
2486
2616
|
"glot-it": "glot.it",
|
|
2487
2617
|
glotit: "glot.it",
|
|
2488
2618
|
"solo-boss-cloud": "solo-boss.kensaur.us",
|
|
2489
|
-
"mushi-mushi": "kensaur.us"
|
|
2619
|
+
"mushi-mushi": "kensaur.us",
|
|
2620
|
+
"how-to-talk-to-girls": "talk.kensaur.us",
|
|
2621
|
+
htttg: "talk.kensaur.us",
|
|
2622
|
+
tsumagoi: "tsumagoi.kensaur.us"
|
|
2490
2623
|
};
|
|
2491
2624
|
var SLUG_ICON_URL_HINTS = {
|
|
2492
2625
|
"mushi-mushi": "https://kensaur.us/mushi-mushi/admin/favicon.svg",
|
|
2493
2626
|
"solo-boss-cloud": "https://solo-boss.kensaur.us/favicon.svg",
|
|
2494
2627
|
"glot-it": "https://kensaur.us/glot-it/apple-touch-icon.png",
|
|
2495
|
-
glotit: "https://kensaur.us/glot-it/apple-touch-icon.png"
|
|
2628
|
+
glotit: "https://kensaur.us/glot-it/apple-touch-icon.png",
|
|
2629
|
+
"the-wanting-mind": "https://kensaur.us/the-wanting-mind/pwa-512x512.png",
|
|
2630
|
+
"how-to-talk-to-girls": "https://talk.kensaur.us/pwa-192.png",
|
|
2631
|
+
htttg: "https://talk.kensaur.us/pwa-192.png",
|
|
2632
|
+
tsumagoi: "https://tsumagoi.kensaur.us/apple-touch-icon.png",
|
|
2633
|
+
"help-her-take-photo": "https://kensaur.us/help-her-take-photo/assets/apple-touch-icon.png",
|
|
2634
|
+
"yen-yen": "https://kensaur.us/yen-yen/icon.svg"
|
|
2496
2635
|
};
|
|
2497
2636
|
var UNTRUSTED_FAVICON_HOSTS = [
|
|
2498
2637
|
"www.google.com",
|
|
@@ -2672,6 +2811,7 @@ exports.MAX_SCREENSHOT_DATA_URL_BYTES = MAX_SCREENSHOT_DATA_URL_BYTES;
|
|
|
2672
2811
|
exports.MUSHI_ACCENT_SHADOW = MUSHI_ACCENT_SHADOW;
|
|
2673
2812
|
exports.MUSHI_BANNER_BRAND_BORDER = MUSHI_BANNER_BRAND_BORDER;
|
|
2674
2813
|
exports.MUSHI_BANNER_NEON = MUSHI_BANNER_NEON;
|
|
2814
|
+
exports.MUSHI_BEACON_MAX_BYTES = MUSHI_BEACON_MAX_BYTES;
|
|
2675
2815
|
exports.MUSHI_BORDER = MUSHI_BORDER;
|
|
2676
2816
|
exports.MUSHI_COLORS_DARK = MUSHI_COLORS_DARK;
|
|
2677
2817
|
exports.MUSHI_COLORS_LIGHT = MUSHI_COLORS_LIGHT;
|
|
@@ -2699,6 +2839,7 @@ exports.MUSHI_TYPE = MUSHI_TYPE;
|
|
|
2699
2839
|
exports.MUSHI_USER_TOKEN_HEADER = MUSHI_USER_TOKEN_HEADER;
|
|
2700
2840
|
exports.MUSHI_Z = MUSHI_Z;
|
|
2701
2841
|
exports.REGION_ENDPOINTS = REGION_ENDPOINTS;
|
|
2842
|
+
exports.buildBeaconEnvelope = buildBeaconEnvelope;
|
|
2702
2843
|
exports.buildIdentityClaims = buildIdentityClaims;
|
|
2703
2844
|
exports.buildSdkIngestHeaders = buildSdkIngestHeaders;
|
|
2704
2845
|
exports.captureEnvironment = captureEnvironment;
|
|
@@ -2714,8 +2855,11 @@ exports.destroySessionTracker = destroySessionTracker;
|
|
|
2714
2855
|
exports.diagnoseEnvConfig = diagnoseEnvConfig;
|
|
2715
2856
|
exports.estimateJsonBytes = estimateJsonBytes;
|
|
2716
2857
|
exports.expandPreset = expandPreset;
|
|
2858
|
+
exports.extractTunnelPath = extractTunnelPath;
|
|
2717
2859
|
exports.faviconUrlCandidates = faviconUrlCandidates;
|
|
2860
|
+
exports.flushLastOutboundOnUnload = flushLastOutboundOnUnload;
|
|
2718
2861
|
exports.formatBytes = formatBytes;
|
|
2862
|
+
exports.getBackoffDelay = getBackoffDelay;
|
|
2719
2863
|
exports.getDeviceFingerprintHash = getDeviceFingerprintHash;
|
|
2720
2864
|
exports.getReporterToken = getReporterToken;
|
|
2721
2865
|
exports.getSessionId = getSessionId;
|
|
@@ -2723,7 +2867,12 @@ exports.githubRepoDomainHint = githubRepoDomainHint;
|
|
|
2723
2867
|
exports.hmacSha256Hex = hmacSha256Hex;
|
|
2724
2868
|
exports.initSessionTracker = initSessionTracker;
|
|
2725
2869
|
exports.isLikelyGenericFavicon = isLikelyGenericFavicon;
|
|
2870
|
+
exports.isMushiBeaconEnvelope = isMushiBeaconEnvelope;
|
|
2871
|
+
exports.isPageUnloading = isPageUnloading;
|
|
2872
|
+
exports.isSameOriginOrRelative = isSameOriginOrRelative;
|
|
2726
2873
|
exports.isUntrustedFaviconUrl = isUntrustedFaviconUrl;
|
|
2874
|
+
exports.markPageUnloading = markPageUnloading;
|
|
2875
|
+
exports.matchesErrorFilter = matchesErrorFilter;
|
|
2727
2876
|
exports.mushiPalette = mushiPalette;
|
|
2728
2877
|
exports.mushiTokens = mushiTokens;
|
|
2729
2878
|
exports.newUuid = newUuid;
|
|
@@ -2731,6 +2880,7 @@ exports.noopLogger = noopLogger;
|
|
|
2731
2880
|
exports.normaliseThrown = normaliseThrown;
|
|
2732
2881
|
exports.originToDomain = originToDomain;
|
|
2733
2882
|
exports.parseIdentityToken = parseIdentityToken;
|
|
2883
|
+
exports.parseRetryAfter = parseRetryAfter;
|
|
2734
2884
|
exports.projectFaviconUrlCandidates = projectFaviconUrlCandidates;
|
|
2735
2885
|
exports.projectInitials = projectInitials;
|
|
2736
2886
|
exports.projectInitialsThemeIndex = projectInitialsThemeIndex;
|
|
@@ -2739,11 +2889,14 @@ exports.resolveEnvConfig = resolveEnvConfig;
|
|
|
2739
2889
|
exports.resolveProjectDomain = resolveProjectDomain;
|
|
2740
2890
|
exports.resolveProjectFaviconDomains = resolveProjectFaviconDomains;
|
|
2741
2891
|
exports.resolveRegionEndpoint = resolveRegionEndpoint;
|
|
2892
|
+
exports.resolveRequestBaseUrl = resolveRequestBaseUrl;
|
|
2742
2893
|
exports.resolveWidgetAccent = resolveWidgetAccent;
|
|
2743
2894
|
exports.safeWidgetHex = safeWidgetHex;
|
|
2744
2895
|
exports.scrubPii = scrubPii;
|
|
2745
2896
|
exports.scrubUrl = scrubUrl;
|
|
2897
|
+
exports.sendOnUnload = sendOnUnload;
|
|
2746
2898
|
exports.sha256Hex = sha256Hex;
|
|
2899
|
+
exports.shouldDropCapturedError = shouldDropCapturedError;
|
|
2747
2900
|
exports.trackPageView = trackPageView;
|
|
2748
2901
|
exports.updateSessionIdentity = updateSessionIdentity;
|
|
2749
2902
|
exports.validateConfig = validateConfig;
|