@mushi-mushi/core 1.20.2 → 1.22.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 -2
- package/dist/index.cjs +146 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +159 -7
- package/dist/index.d.ts +159 -7
- package/dist/index.js +134 -25
- package/dist/index.js.map +1 -1
- package/package.json +12 -13
package/dist/index.js
CHANGED
|
@@ -104,6 +104,8 @@ var MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
|
|
|
104
104
|
var MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
|
|
105
105
|
var DEFAULT_TIMEOUT = 1e4;
|
|
106
106
|
var DEFAULT_MAX_RETRIES = 2;
|
|
107
|
+
var DEFAULT_CIRCUIT_THRESHOLD = 4;
|
|
108
|
+
var DEFAULT_CIRCUIT_COOLDOWN_MS = 3e4;
|
|
107
109
|
function createApiClient(options) {
|
|
108
110
|
const {
|
|
109
111
|
projectId,
|
|
@@ -113,10 +115,29 @@ function createApiClient(options) {
|
|
|
113
115
|
maxRetries = DEFAULT_MAX_RETRIES,
|
|
114
116
|
getUserToken,
|
|
115
117
|
sdkPackage,
|
|
116
|
-
sdkVersion
|
|
118
|
+
sdkVersion,
|
|
119
|
+
circuitBreaker
|
|
117
120
|
} = options;
|
|
118
121
|
let baseUrl = apiEndpoint.replace(/\/$/, "");
|
|
122
|
+
const cbEnabled = circuitBreaker?.enabled !== false;
|
|
123
|
+
const cbThreshold = Math.max(1, circuitBreaker?.threshold ?? DEFAULT_CIRCUIT_THRESHOLD);
|
|
124
|
+
const cbCooldownMs = Math.max(1e3, circuitBreaker?.cooldownMs ?? DEFAULT_CIRCUIT_COOLDOWN_MS);
|
|
125
|
+
let cbFailures = 0;
|
|
126
|
+
let cbOpenUntil = 0;
|
|
127
|
+
const cbIsOpen = () => cbEnabled && cbOpenUntil > Date.now();
|
|
128
|
+
const cbRecordReachable = () => {
|
|
129
|
+
cbFailures = 0;
|
|
130
|
+
cbOpenUntil = 0;
|
|
131
|
+
};
|
|
132
|
+
const cbRecordUnreachable = () => {
|
|
133
|
+
if (!cbEnabled) return;
|
|
134
|
+
cbFailures += 1;
|
|
135
|
+
if (cbFailures >= cbThreshold) cbOpenUntil = Date.now() + cbCooldownMs;
|
|
136
|
+
};
|
|
119
137
|
async function request(method, path, body, retries = maxRetries, internalKind, extraHeaders) {
|
|
138
|
+
if (cbIsOpen()) {
|
|
139
|
+
return { ok: false, error: { code: "CIRCUIT_OPEN", message: "Endpoint temporarily unavailable; retrying later." } };
|
|
140
|
+
}
|
|
120
141
|
const url = `${baseUrl}${path}`;
|
|
121
142
|
const controller = new AbortController();
|
|
122
143
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
@@ -163,6 +184,8 @@ function createApiClient(options) {
|
|
|
163
184
|
await sleep(getBackoffDelay(maxRetries - retries));
|
|
164
185
|
return request(method, path, body, retries - 1, internalKind, extraHeaders);
|
|
165
186
|
}
|
|
187
|
+
if (response.status >= 500) cbRecordUnreachable();
|
|
188
|
+
else cbRecordReachable();
|
|
166
189
|
return {
|
|
167
190
|
ok: false,
|
|
168
191
|
error: {
|
|
@@ -173,6 +196,7 @@ function createApiClient(options) {
|
|
|
173
196
|
}
|
|
174
197
|
const payload = await response.json();
|
|
175
198
|
const data = payload && typeof payload === "object" && "ok" in payload && "data" in payload ? payload.data : payload;
|
|
199
|
+
cbRecordReachable();
|
|
176
200
|
return { ok: true, data };
|
|
177
201
|
} catch (error) {
|
|
178
202
|
clearTimeout(timer);
|
|
@@ -180,6 +204,7 @@ function createApiClient(options) {
|
|
|
180
204
|
await sleep(getBackoffDelay(maxRetries - retries));
|
|
181
205
|
return request(method, path, body, retries - 1, internalKind);
|
|
182
206
|
}
|
|
207
|
+
cbRecordUnreachable();
|
|
183
208
|
return {
|
|
184
209
|
ok: false,
|
|
185
210
|
error: {
|
|
@@ -464,9 +489,9 @@ function isRetryable(error) {
|
|
|
464
489
|
|
|
465
490
|
// src/region.ts
|
|
466
491
|
var REGION_ENDPOINTS = {
|
|
467
|
-
us: "https://
|
|
468
|
-
eu: "https://
|
|
469
|
-
jp: "https://
|
|
492
|
+
us: "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api",
|
|
493
|
+
eu: "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api",
|
|
494
|
+
jp: "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api"
|
|
470
495
|
};
|
|
471
496
|
var ROUTING_CACHE_KEY = "mushi_region_v1";
|
|
472
497
|
var ROUTING_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -1212,7 +1237,8 @@ function createOfflineQueue(config = {}) {
|
|
|
1212
1237
|
if (!enabled || !syncOnReconnect || typeof window === "undefined") return;
|
|
1213
1238
|
const tryFlush = () => {
|
|
1214
1239
|
if (navigator.onLine) {
|
|
1215
|
-
flush(client).catch(() => {
|
|
1240
|
+
flush(client).catch((err) => {
|
|
1241
|
+
queueLog.warn("Offline queue auto-flush failed", { err: String(err) });
|
|
1216
1242
|
});
|
|
1217
1243
|
}
|
|
1218
1244
|
};
|
|
@@ -1245,6 +1271,15 @@ function captureEnvironment() {
|
|
|
1245
1271
|
const scr = typeof screen !== "undefined" ? screen : void 0;
|
|
1246
1272
|
void kickOffUserAgentData(nav);
|
|
1247
1273
|
const connection = nav && "connection" in nav ? nav.connection : void 0;
|
|
1274
|
+
const w = win;
|
|
1275
|
+
const isCapacitor = !!w?.Capacitor;
|
|
1276
|
+
const isCordova = !!w?.cordova;
|
|
1277
|
+
const isReactNative = nav?.product === "ReactNative" || typeof globalThis.HermesInternal !== "undefined";
|
|
1278
|
+
const native = isCapacitor || isCordova || isReactNative ? {
|
|
1279
|
+
...isCapacitor ? { capacitor: true } : {},
|
|
1280
|
+
...isCordova ? { cordova: true } : {},
|
|
1281
|
+
...isReactNative ? { reactNative: true } : {}
|
|
1282
|
+
} : void 0;
|
|
1248
1283
|
return {
|
|
1249
1284
|
userAgent: nav?.userAgent ?? "unknown",
|
|
1250
1285
|
platform: nav?.platform ?? "unknown",
|
|
@@ -1277,7 +1312,8 @@ function captureEnvironment() {
|
|
|
1277
1312
|
displayMode: matchDisplayMode(win),
|
|
1278
1313
|
documentTitle: doc?.title?.slice(0, 200),
|
|
1279
1314
|
buildId: readBuildIdMeta(doc),
|
|
1280
|
-
pageLoadTiming: capturePageLoadTiming(win)
|
|
1315
|
+
pageLoadTiming: capturePageLoadTiming(win),
|
|
1316
|
+
...native ? { native } : {}
|
|
1281
1317
|
};
|
|
1282
1318
|
}
|
|
1283
1319
|
function findNearestTestidFromActive(doc) {
|
|
@@ -1405,20 +1441,9 @@ function capturePageLoadTiming(win) {
|
|
|
1405
1441
|
}
|
|
1406
1442
|
|
|
1407
1443
|
// src/reporter-token.ts
|
|
1408
|
-
var
|
|
1409
|
-
function
|
|
1410
|
-
|
|
1411
|
-
const existing = localStorage.getItem(STORAGE_KEY);
|
|
1412
|
-
if (existing) return existing;
|
|
1413
|
-
}
|
|
1414
|
-
const token = generateToken();
|
|
1415
|
-
if (typeof localStorage !== "undefined") {
|
|
1416
|
-
try {
|
|
1417
|
-
localStorage.setItem(STORAGE_KEY, token);
|
|
1418
|
-
} catch {
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
return token;
|
|
1444
|
+
var LEGACY_STORAGE_KEY = "mushi_reporter_token";
|
|
1445
|
+
function storageKey(projectId) {
|
|
1446
|
+
return `mushi:reporter-token:${projectId}`;
|
|
1422
1447
|
}
|
|
1423
1448
|
function generateToken() {
|
|
1424
1449
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
@@ -1435,6 +1460,38 @@ function generateToken() {
|
|
|
1435
1460
|
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1436
1461
|
return `mushi_${hex}`;
|
|
1437
1462
|
}
|
|
1463
|
+
function readStoredToken(key) {
|
|
1464
|
+
if (typeof localStorage === "undefined") return null;
|
|
1465
|
+
try {
|
|
1466
|
+
const existing = localStorage.getItem(key);
|
|
1467
|
+
return existing && existing.length > 0 ? existing : null;
|
|
1468
|
+
} catch {
|
|
1469
|
+
return null;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
function writeStoredToken(key, token) {
|
|
1473
|
+
if (typeof localStorage === "undefined") return;
|
|
1474
|
+
try {
|
|
1475
|
+
localStorage.setItem(key, token);
|
|
1476
|
+
} catch {
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
function getReporterToken(projectId) {
|
|
1480
|
+
if (!projectId) {
|
|
1481
|
+
const legacy2 = readStoredToken(LEGACY_STORAGE_KEY);
|
|
1482
|
+
if (legacy2) return legacy2;
|
|
1483
|
+
const token2 = generateToken();
|
|
1484
|
+
writeStoredToken(LEGACY_STORAGE_KEY, token2);
|
|
1485
|
+
return token2;
|
|
1486
|
+
}
|
|
1487
|
+
const key = storageKey(projectId);
|
|
1488
|
+
const scoped = readStoredToken(key);
|
|
1489
|
+
if (scoped) return scoped;
|
|
1490
|
+
const legacy = readStoredToken(LEGACY_STORAGE_KEY);
|
|
1491
|
+
const token = legacy ?? generateToken();
|
|
1492
|
+
writeStoredToken(key, token);
|
|
1493
|
+
return token;
|
|
1494
|
+
}
|
|
1438
1495
|
|
|
1439
1496
|
// src/uuid.ts
|
|
1440
1497
|
function newUuid() {
|
|
@@ -1730,6 +1787,42 @@ var MUSHI_COLORS_DARK = {
|
|
|
1730
1787
|
ok: "#4ADE80",
|
|
1731
1788
|
danger: "#F87171"
|
|
1732
1789
|
};
|
|
1790
|
+
var MUSHI_TIER_COLORS = {
|
|
1791
|
+
free: MUSHI_COLORS_LIGHT.inkMuted,
|
|
1792
|
+
explorer: "#2563EB",
|
|
1793
|
+
contributor: "#7C3AED",
|
|
1794
|
+
champion: "#D97706",
|
|
1795
|
+
default: MUSHI_COLORS_LIGHT.accent
|
|
1796
|
+
};
|
|
1797
|
+
var MUSHI_BANNER_NEON = {
|
|
1798
|
+
bg: "#0FFF50",
|
|
1799
|
+
fg: "#0a1a0a",
|
|
1800
|
+
border: "#00C43A"
|
|
1801
|
+
};
|
|
1802
|
+
var MUSHI_ON_ACCENT = "#FAF7F0";
|
|
1803
|
+
var MUSHI_INVERSE = "#ffffff";
|
|
1804
|
+
var MUSHI_ACCENT_SHADOW = {
|
|
1805
|
+
light: "#9A2A1E",
|
|
1806
|
+
dark: "#7A1F15"
|
|
1807
|
+
};
|
|
1808
|
+
var MUSHI_BANNER_BRAND_BORDER = {
|
|
1809
|
+
light: "#B52F1F",
|
|
1810
|
+
dark: "#C4321E"
|
|
1811
|
+
};
|
|
1812
|
+
var MUSHI_REPORTER_STATUS = {
|
|
1813
|
+
light: {
|
|
1814
|
+
sent: { fg: "#1E4A8C", bg: "rgba(30,74,140,0.08)", border: "rgba(30,74,140,0.16)" },
|
|
1815
|
+
review: { fg: "#8A5A00", bg: "rgba(180,120,0,0.10)", border: "rgba(180,120,0,0.18)" },
|
|
1816
|
+
fixing: { fg: "#9A3D12", bg: "rgba(224,60,44,0.10)", border: "rgba(224,60,44,0.18)" },
|
|
1817
|
+
fixed: { fg: "#1F6B3A", bg: "rgba(31,107,58,0.10)", border: "rgba(31,107,58,0.18)" }
|
|
1818
|
+
},
|
|
1819
|
+
dark: {
|
|
1820
|
+
sent: { fg: "#A8C4FF", bg: "rgba(120,160,255,0.12)", border: "rgba(120,160,255,0.22)" },
|
|
1821
|
+
review: { fg: "#FFD27A", bg: "rgba(255,190,90,0.12)", border: "rgba(255,190,90,0.22)" },
|
|
1822
|
+
fixing: { fg: "#FFB899", bg: "rgba(255,120,60,0.12)", border: "rgba(255,120,60,0.24)" },
|
|
1823
|
+
fixed: { fg: "#8FE3B0", bg: "rgba(80,200,130,0.12)", border: "rgba(80,200,130,0.22)" }
|
|
1824
|
+
}
|
|
1825
|
+
};
|
|
1733
1826
|
function mushiPalette(mode) {
|
|
1734
1827
|
return mode === "dark" ? MUSHI_COLORS_DARK : MUSHI_COLORS_LIGHT;
|
|
1735
1828
|
}
|
|
@@ -1776,16 +1869,32 @@ var MUSHI_MOTION = {
|
|
|
1776
1869
|
var MUSHI_GEOMETRY = {
|
|
1777
1870
|
bannerHeight: 36,
|
|
1778
1871
|
fabSize: 52,
|
|
1779
|
-
|
|
1872
|
+
/** edge-tab launcher width (px) */
|
|
1873
|
+
edgeTabWidth: 32,
|
|
1780
1874
|
/** default gutter from the screen edge (added on top of safe-area insets) */
|
|
1781
1875
|
gutter: 24,
|
|
1782
|
-
|
|
1876
|
+
/** Web panel width (px) — matches shipped Shadow DOM widget */
|
|
1877
|
+
panelWidth: 360,
|
|
1878
|
+
/** max panel height before keyboard inset (px) */
|
|
1879
|
+
panelMaxHeight: 480,
|
|
1783
1880
|
/** below this viewport width the panel becomes a full-width bottom sheet */
|
|
1784
1881
|
panelSheetBreakpoint: 480
|
|
1785
1882
|
};
|
|
1883
|
+
function safeWidgetHex(v) {
|
|
1884
|
+
return /^#[0-9a-fA-F]{3,8}$/.test(v) ? v : "";
|
|
1885
|
+
}
|
|
1886
|
+
function resolveWidgetAccent(mode, accent = "", accentText = "") {
|
|
1887
|
+
const pal = mushiPalette(mode);
|
|
1888
|
+
const safeAccent = safeWidgetHex(accent);
|
|
1889
|
+
const safeAccentText = safeWidgetHex(accentText);
|
|
1890
|
+
const resolvedAccent = safeAccent || pal.accent;
|
|
1891
|
+
const accentWash = safeAccent ? mode === "dark" ? `${resolvedAccent}1F` : `${resolvedAccent}14` : pal.accentWash;
|
|
1892
|
+
const accentInk = safeAccentText || pal.accentInk;
|
|
1893
|
+
return { accent: resolvedAccent, accentWash, accentInk };
|
|
1894
|
+
}
|
|
1786
1895
|
var MUSHI_COPY = {
|
|
1787
1896
|
bannerLabel: "Beta",
|
|
1788
|
-
bannerMessage: "
|
|
1897
|
+
bannerMessage: "Found a bug? Tap to report it.",
|
|
1789
1898
|
bugCta: "Report a bug",
|
|
1790
1899
|
featureCta: "Feature request",
|
|
1791
1900
|
triggerText: "\u{1F41B}",
|
|
@@ -1858,7 +1967,7 @@ var SLUG_DOMAIN_HINTS = {
|
|
|
1858
1967
|
"glot-it": "glot.it",
|
|
1859
1968
|
glotit: "glot.it",
|
|
1860
1969
|
"solo-boss-cloud": "sbc-front.vercel.app",
|
|
1861
|
-
"mushi-mushi": "
|
|
1970
|
+
"mushi-mushi": "kensaur.us"
|
|
1862
1971
|
};
|
|
1863
1972
|
var SLUG_ICON_URL_HINTS = {
|
|
1864
1973
|
"mushi-mushi": "https://kensaur.us/mushi-mushi/admin/favicon.svg",
|
|
@@ -2036,6 +2145,6 @@ function isSafeFaviconHref(href) {
|
|
|
2036
2145
|
}
|
|
2037
2146
|
}
|
|
2038
2147
|
|
|
2039
|
-
export { DEFAULT_API_ENDPOINT, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_MOTION, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, REGION_ENDPOINTS, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, scrubPii };
|
|
2148
|
+
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_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, REGION_ENDPOINTS, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, sha256Hex };
|
|
2040
2149
|
//# sourceMappingURL=index.js.map
|
|
2041
2150
|
//# sourceMappingURL=index.js.map
|