@mushi-mushi/core 1.27.1 → 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/dist/index.js CHANGED
@@ -84,7 +84,92 @@ async function hmacSha256Hex(secret, value) {
84
84
  return bytesToHex(result);
85
85
  }
86
86
 
87
+ // src/unload-transport.ts
88
+ var MUSHI_BEACON_MAX_BYTES = 60 * 1024;
89
+ function isMushiBeaconEnvelope(value) {
90
+ if (!value || typeof value !== "object") return false;
91
+ const rec = value;
92
+ return rec.mushiBeacon === true && typeof rec.path === "string" && rec.headers !== null && typeof rec.headers === "object";
93
+ }
94
+ function buildBeaconEnvelope(opts) {
95
+ return {
96
+ mushiBeacon: true,
97
+ path: opts.path,
98
+ headers: opts.headers,
99
+ body: opts.body
100
+ };
101
+ }
102
+ function isSameOriginOrRelative(url, origin = typeof location !== "undefined" ? location.origin : "") {
103
+ if (!url) return false;
104
+ if (url.startsWith("/")) return true;
105
+ if (!origin) return false;
106
+ try {
107
+ return new URL(url, origin).origin === origin;
108
+ } catch {
109
+ return false;
110
+ }
111
+ }
112
+ function extractTunnelPath(url) {
113
+ try {
114
+ const parsed = url.startsWith("/") ? new URL(url, "https://tunnel.local") : new URL(url);
115
+ return `${parsed.pathname}${parsed.search}`;
116
+ } catch {
117
+ return url;
118
+ }
119
+ }
120
+ function sendOnUnload(opts) {
121
+ const fetchImpl = opts.fetchImpl ?? (typeof fetch === "function" ? fetch : void 0);
122
+ if (fetchImpl) {
123
+ try {
124
+ void fetchImpl(opts.url, {
125
+ method: "POST",
126
+ headers: {
127
+ "Content-Type": "application/json",
128
+ ...opts.headers
129
+ },
130
+ body: opts.body,
131
+ keepalive: true
132
+ });
133
+ return true;
134
+ } catch {
135
+ }
136
+ }
137
+ const beacon = opts.sendBeacon ?? (typeof navigator !== "undefined" ? navigator.sendBeacon?.bind(navigator) : void 0);
138
+ if (!beacon || !isSameOriginOrRelative(opts.url)) return false;
139
+ let parsedBody = opts.body;
140
+ try {
141
+ parsedBody = JSON.parse(opts.body);
142
+ } catch {
143
+ parsedBody = opts.body;
144
+ }
145
+ const envelope = JSON.stringify(
146
+ buildBeaconEnvelope({
147
+ path: opts.path ?? extractTunnelPath(opts.url),
148
+ headers: opts.headers,
149
+ body: parsedBody
150
+ })
151
+ );
152
+ if (envelope.length > MUSHI_BEACON_MAX_BYTES) return false;
153
+ try {
154
+ return beacon(opts.url, new Blob([envelope], { type: "application/json" }));
155
+ } catch {
156
+ return false;
157
+ }
158
+ }
159
+ var pageUnloading = false;
160
+ function markPageUnloading() {
161
+ pageUnloading = true;
162
+ }
163
+ function isPageUnloading() {
164
+ return pageUnloading;
165
+ }
166
+
87
167
  // src/api-client.ts
168
+ var lastOutbound = null;
169
+ function flushLastOutboundOnUnload() {
170
+ if (!lastOutbound) return false;
171
+ return sendOnUnload(lastOutbound);
172
+ }
88
173
  var _credWarningEmitted = false;
89
174
  var MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
90
175
  var MUSHI_PROJECT_HEADER = "X-Mushi-Project";
@@ -105,15 +190,22 @@ function buildSdkIngestHeaders(opts) {
105
190
  var DEFAULT_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api";
106
191
  var MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
107
192
  var MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
193
+ function resolveRequestBaseUrl(apiEndpoint, tunnel) {
194
+ const trimmedTunnel = tunnel?.trim();
195
+ if (trimmedTunnel) return trimmedTunnel.replace(/\/$/, "");
196
+ return (apiEndpoint ?? DEFAULT_API_ENDPOINT).replace(/\/$/, "");
197
+ }
108
198
  var DEFAULT_TIMEOUT = 1e4;
109
199
  var DEFAULT_MAX_RETRIES = 2;
110
200
  var DEFAULT_CIRCUIT_THRESHOLD = 4;
111
201
  var DEFAULT_CIRCUIT_COOLDOWN_MS = 3e4;
202
+ var MAX_INLINE_RETRY_WAIT_MS = 1e4;
112
203
  function createApiClient(options) {
113
204
  const {
114
205
  projectId,
115
206
  apiKey,
116
207
  apiEndpoint = DEFAULT_API_ENDPOINT,
208
+ tunnel,
117
209
  timeout = DEFAULT_TIMEOUT,
118
210
  maxRetries = DEFAULT_MAX_RETRIES,
119
211
  getUserToken,
@@ -121,7 +213,7 @@ function createApiClient(options) {
121
213
  sdkVersion,
122
214
  circuitBreaker
123
215
  } = options;
124
- let baseUrl = apiEndpoint.replace(/\/$/, "");
216
+ let baseUrl = resolveRequestBaseUrl(apiEndpoint, tunnel);
125
217
  const cbEnabled = circuitBreaker?.enabled !== false;
126
218
  const cbThreshold = Math.max(1, circuitBreaker?.threshold ?? DEFAULT_CIRCUIT_THRESHOLD);
127
219
  const cbCooldownMs = Math.max(1e3, circuitBreaker?.cooldownMs ?? DEFAULT_CIRCUIT_COOLDOWN_MS);
@@ -145,21 +237,27 @@ function createApiClient(options) {
145
237
  const controller = new AbortController();
146
238
  const timer = setTimeout(() => controller.abort(), timeout);
147
239
  const userToken = getUserToken?.() ?? null;
240
+ const headers = {
241
+ ...buildSdkIngestHeaders({
242
+ apiKey,
243
+ projectId,
244
+ sdkPackage,
245
+ sdkVersion,
246
+ userToken,
247
+ internalKind
248
+ }),
249
+ ...extraHeaders
250
+ };
251
+ const serialized = body ? JSON.stringify(body) : void 0;
252
+ if (serialized && method !== "GET") {
253
+ lastOutbound = { url, headers, body: serialized, path };
254
+ }
148
255
  try {
149
256
  const response = await fetch(url, {
150
257
  method,
151
- headers: {
152
- ...buildSdkIngestHeaders({
153
- apiKey,
154
- projectId,
155
- sdkPackage,
156
- sdkVersion,
157
- userToken,
158
- internalKind
159
- }),
160
- ...extraHeaders
161
- },
162
- body: body ? JSON.stringify(body) : void 0,
258
+ headers,
259
+ body: serialized,
260
+ keepalive: isPageUnloading(),
163
261
  signal: controller.signal,
164
262
  ...internalKind ? { [MUSHI_INTERNAL_INIT_MARKER]: internalKind } : {}
165
263
  });
@@ -183,11 +281,15 @@ function createApiClient(options) {
183
281
  `[Mushi] Credentials rejected (HTTP ${response.status}). Check your Project ID and API key scope (must be "report:write"). ` + where
184
282
  );
185
283
  }
186
- if (response.status >= 500 && retries > 0) {
187
- await sleep(getBackoffDelay(maxRetries - retries));
284
+ const rateLimited = response.status === 429;
285
+ const unusable = response.status >= 500 || rateLimited;
286
+ const retryAfterMs = rateLimited ? parseRetryAfter(response.headers.get("Retry-After")) : null;
287
+ const canWaitInline = retryAfterMs === null || retryAfterMs <= MAX_INLINE_RETRY_WAIT_MS;
288
+ if (unusable && retries > 0 && canWaitInline) {
289
+ await sleep(retryAfterMs ?? getBackoffDelay(maxRetries - retries));
188
290
  return request(method, path, body, retries - 1, internalKind, extraHeaders);
189
291
  }
190
- if (response.status >= 500) cbRecordUnreachable();
292
+ if (unusable) cbRecordUnreachable();
191
293
  else cbRecordReachable();
192
294
  return {
193
295
  ok: false,
@@ -205,7 +307,7 @@ function createApiClient(options) {
205
307
  clearTimeout(timer);
206
308
  if (retries > 0 && isRetryable(error)) {
207
309
  await sleep(getBackoffDelay(maxRetries - retries));
208
- return request(method, path, body, retries - 1, internalKind);
310
+ return request(method, path, body, retries - 1, internalKind, extraHeaders);
209
311
  }
210
312
  cbRecordUnreachable();
211
313
  return {
@@ -236,6 +338,7 @@ function createApiClient(options) {
236
338
  "X-Reporter-Hmac": hmac
237
339
  },
238
340
  body: body ? JSON.stringify(body) : void 0,
341
+ keepalive: isPageUnloading(),
239
342
  [MUSHI_INTERNAL_INIT_MARKER]: "reporter-poll"
240
343
  });
241
344
  if (!response.ok) {
@@ -495,12 +598,48 @@ function sleep(ms) {
495
598
  function getBackoffDelay(attempt) {
496
599
  return Math.min(1e3 * 2 ** attempt + Math.random() * 500, 1e4);
497
600
  }
601
+ function parseRetryAfter(value, now2 = Date.now()) {
602
+ if (!value) return null;
603
+ const raw = value.trim();
604
+ if (!raw) return null;
605
+ const seconds = Number(raw);
606
+ if (Number.isFinite(seconds)) return seconds < 0 ? null : seconds * 1e3;
607
+ const at = Date.parse(raw);
608
+ if (Number.isNaN(at)) return null;
609
+ return Math.max(at - now2, 0);
610
+ }
498
611
  function isRetryable(error) {
499
612
  if (error instanceof DOMException && error.name === "AbortError") return true;
500
613
  if (error instanceof TypeError) return true;
501
614
  return false;
502
615
  }
503
616
 
617
+ // src/error-filters.ts
618
+ function matchesErrorFilter(value, filters) {
619
+ if (!value || !filters || filters.length === 0) return false;
620
+ for (const filter of filters) {
621
+ if (typeof filter === "string") {
622
+ if (value.includes(filter)) return true;
623
+ continue;
624
+ }
625
+ try {
626
+ if (filter.test(value)) return true;
627
+ } catch {
628
+ }
629
+ }
630
+ return false;
631
+ }
632
+ function shouldDropCapturedError(input) {
633
+ if (matchesErrorFilter(input.message, input.ignoreErrors)) return true;
634
+ const filename = input.filename?.trim() || "";
635
+ if (filename && matchesErrorFilter(filename, input.denyUrls)) return true;
636
+ if (input.allowUrls && input.allowUrls.length > 0) {
637
+ if (!filename) return true;
638
+ if (!matchesErrorFilter(filename, input.allowUrls)) return true;
639
+ }
640
+ return false;
641
+ }
642
+
504
643
  // src/region.ts
505
644
  var REGION_ENDPOINTS = {
506
645
  us: DEFAULT_API_ENDPOINT,
@@ -679,6 +818,7 @@ var KNOWN_CONFIG_KEYS = [
679
818
  "projectId",
680
819
  "apiKey",
681
820
  "apiEndpoint",
821
+ "tunnel",
682
822
  "timeout",
683
823
  "maxRetries",
684
824
  "circuitBreaker",
@@ -698,8 +838,13 @@ var KNOWN_CONFIG_KEYS = [
698
838
  "enabled",
699
839
  "appVersion",
700
840
  "sampleRate",
841
+ "replaySampleRate",
842
+ "replaysOnErrorSampleRate",
701
843
  "beforeSend",
702
844
  "beforeSendFeedback",
845
+ "ignoreErrors",
846
+ "denyUrls",
847
+ "allowUrls",
703
848
  "onCrashedLastRun"
704
849
  ];
705
850
  function presetDefaults(preset) {
@@ -1164,6 +1309,8 @@ function createOfflineQueue(config = {}) {
1164
1309
  let syncCleanup = null;
1165
1310
  let flushInterval = null;
1166
1311
  let backendType = null;
1312
+ let inFlight = null;
1313
+ let followUp = null;
1167
1314
  async function wrapForStorage(report) {
1168
1315
  const queuedAt = (/* @__PURE__ */ new Date()).toISOString();
1169
1316
  if (!encryptAtRest) {
@@ -1316,7 +1463,10 @@ function createOfflineQueue(config = {}) {
1316
1463
  }
1317
1464
  async function lsEnqueue(report) {
1318
1465
  const rows = lsRead();
1319
- rows.push(await wrapForStorage(report));
1466
+ const row = await wrapForStorage(report);
1467
+ const idx = rows.findIndex((r) => r.id === report.id);
1468
+ if (idx >= 0) rows[idx] = row;
1469
+ else rows.push(row);
1320
1470
  lsWrite(rows);
1321
1471
  }
1322
1472
  function lsDelete(id) {
@@ -1355,26 +1505,43 @@ function createOfflineQueue(config = {}) {
1355
1505
  return false;
1356
1506
  }
1357
1507
  }
1358
- async function enqueue(report) {
1359
- if (!enabled) return;
1360
- const currentSize = await size();
1361
- if (currentSize >= maxQueueSize) {
1362
- queueLog.warn("Offline queue full \u2014 dropping report", { maxQueueSize });
1363
- return;
1508
+ async function readRows() {
1509
+ const backend = detectBackend();
1510
+ if (backend === "none") return { backend, rows: [] };
1511
+ if (backend === "indexeddb") {
1512
+ try {
1513
+ return { backend, rows: await idbGetAll() };
1514
+ } catch {
1515
+ backendType = "localstorage";
1516
+ }
1364
1517
  }
1518
+ return { backend: "localstorage", rows: lsRead() };
1519
+ }
1520
+ async function writeRow(report) {
1365
1521
  const backend = detectBackend();
1522
+ if (backend === "none") {
1523
+ queueLog.debug("Offline queue: no storage backend, dropping report", { id: report.id });
1524
+ return backend;
1525
+ }
1366
1526
  if (backend === "indexeddb") {
1367
1527
  try {
1368
1528
  await idbEnqueue(report);
1369
- return;
1529
+ return backend;
1370
1530
  } catch {
1371
1531
  backendType = "localstorage";
1372
1532
  }
1373
1533
  }
1374
- if (backend === "localstorage" || backendType === "localstorage") {
1375
- await lsEnqueue(report);
1534
+ await lsEnqueue(report);
1535
+ return "localstorage";
1536
+ }
1537
+ async function enqueue(report) {
1538
+ if (!enabled) return;
1539
+ const currentSize = await size();
1540
+ if (currentSize >= maxQueueSize) {
1541
+ queueLog.warn("Offline queue full \u2014 dropping report", { maxQueueSize });
1376
1542
  return;
1377
1543
  }
1544
+ await writeRow(report);
1378
1545
  }
1379
1546
  function getBackoffDelay2(attempt) {
1380
1547
  return Math.min(1e3 * 2 ** attempt + Math.random() * 500, MAX_BACKOFF_MS);
@@ -1382,19 +1549,9 @@ function createOfflineQueue(config = {}) {
1382
1549
  function sleep2(ms) {
1383
1550
  return new Promise((resolve) => setTimeout(resolve, ms));
1384
1551
  }
1385
- async function flush(client) {
1386
- if (!enabled) return { sent: 0, failed: 0 };
1387
- let rows;
1388
- const backend = detectBackend();
1389
- if (backend === "indexeddb") {
1390
- try {
1391
- rows = await idbGetAll();
1392
- } catch {
1393
- rows = lsRead();
1394
- }
1395
- } else {
1396
- rows = lsRead();
1397
- }
1552
+ async function runFlush(client) {
1553
+ const { backend, rows: storedRows } = await readRows();
1554
+ let rows = storedRows;
1398
1555
  const now2 = Date.now();
1399
1556
  const fresh = [];
1400
1557
  for (const row of rows) {
@@ -1423,59 +1580,84 @@ function createOfflineQueue(config = {}) {
1423
1580
  if (result.ok) {
1424
1581
  await removeRow(backend, rowId);
1425
1582
  sent++;
1583
+ continue;
1584
+ }
1585
+ failed++;
1586
+ if (result.error?.code === "CIRCUIT_OPEN") {
1587
+ queueLog.debug("Offline queue: circuit open, deferring the rest of the batch", {
1588
+ id: rowId,
1589
+ remaining: batch.length - i
1590
+ });
1591
+ break;
1592
+ }
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" || // A payload that exceeds the size guard will never shrink on its own;
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(
1598
+ result.error.message
1599
+ );
1600
+ const transient = !permanent && (result.error?.code === "NETWORK_ERROR" || result.error?.code === "HTTP_403" || 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
+ if (permanent) {
1602
+ await removeRow(backend, rowId);
1426
1603
  } else {
1427
- 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" || // A payload that exceeds the size guard will never shrink on its own;
1428
- // retrying re-serialises the multi-MB body every sync tick and wedges
1429
- // the queue (it matches neither permanent nor transient otherwise).
1430
- // SERIALIZE_FAILED (circular ref) is likewise unrecoverable on retry.
1431
- 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(
1432
- result.error.message
1433
- );
1434
- const transient = !permanent && (result.error?.code === "NETWORK_ERROR" || result.error?.code === "HTTP_403" || 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"));
1435
- if (permanent) {
1604
+ const nextAttempts = rowAttempts(row) + 1;
1605
+ if (nextAttempts >= MAX_DELIVERY_ATTEMPTS) {
1436
1606
  await removeRow(backend, rowId);
1437
- } else if (transient) {
1438
- const nextAttempts = rowAttempts(row) + 1;
1439
- if (nextAttempts >= MAX_DELIVERY_ATTEMPTS) {
1440
- await removeRow(backend, rowId);
1441
- queueLog.warn("Offline queue: giving up on report after repeated failures", {
1607
+ queueLog.warn("Offline queue: giving up on report after repeated failures", {
1608
+ id: rowId,
1609
+ attempts: nextAttempts,
1610
+ code: result.error?.code
1611
+ });
1612
+ } else {
1613
+ row.attempts = nextAttempts;
1614
+ const persisted = await persistRow(backend, row);
1615
+ if (persisted) {
1616
+ queueLog.debug("Offline queue: delivery failed, will retry", {
1442
1617
  id: rowId,
1443
1618
  attempts: nextAttempts,
1444
- code: result.error?.code
1619
+ code: result.error?.code,
1620
+ classified: transient ? "transient" : "unclassified"
1445
1621
  });
1446
1622
  } else {
1447
- row.attempts = nextAttempts;
1448
- const persisted = await persistRow(backend, row);
1449
- if (persisted) {
1450
- queueLog.debug("Offline queue: transient failure, will retry", {
1451
- id: rowId,
1452
- attempts: nextAttempts,
1453
- code: result.error?.code
1454
- });
1455
- } else {
1456
- await removeRow(backend, rowId);
1457
- queueLog.warn("Offline queue: dropping report (attempt counter unpersistable)", {
1458
- id: rowId,
1459
- code: result.error?.code
1460
- });
1461
- }
1623
+ await removeRow(backend, rowId);
1624
+ queueLog.warn("Offline queue: dropping report (attempt counter unpersistable)", {
1625
+ id: rowId,
1626
+ code: result.error?.code
1627
+ });
1462
1628
  }
1463
1629
  }
1464
- failed++;
1465
- if (i < batch.length - 1) {
1466
- await sleep2(getBackoffDelay2(i));
1467
- }
1630
+ }
1631
+ if (i < batch.length - 1) {
1632
+ await sleep2(getBackoffDelay2(i));
1468
1633
  }
1469
1634
  }
1470
1635
  return { sent, failed };
1471
1636
  }
1637
+ function flush(client) {
1638
+ if (!enabled) return Promise.resolve({ sent: 0, failed: 0 });
1639
+ if (inFlight) {
1640
+ if (!followUp) {
1641
+ followUp = inFlight.catch(() => void 0).then(() => {
1642
+ followUp = null;
1643
+ return flush(client);
1644
+ });
1645
+ }
1646
+ return followUp;
1647
+ }
1648
+ const pass = runFlush(client).finally(() => {
1649
+ if (inFlight === pass) inFlight = null;
1650
+ });
1651
+ inFlight = pass;
1652
+ return pass;
1653
+ }
1472
1654
  async function size() {
1473
1655
  const backend = detectBackend();
1474
1656
  if (backend === "indexeddb") {
1475
1657
  try {
1476
1658
  return await idbSize();
1477
1659
  } catch {
1478
- return lsRead().length;
1660
+ backendType = "localstorage";
1479
1661
  }
1480
1662
  }
1481
1663
  return lsRead().length;
@@ -2432,13 +2614,22 @@ var SLUG_DOMAIN_HINTS = {
2432
2614
  "glot-it": "glot.it",
2433
2615
  glotit: "glot.it",
2434
2616
  "solo-boss-cloud": "solo-boss.kensaur.us",
2435
- "mushi-mushi": "kensaur.us"
2617
+ "mushi-mushi": "kensaur.us",
2618
+ "how-to-talk-to-girls": "talk.kensaur.us",
2619
+ htttg: "talk.kensaur.us",
2620
+ tsumagoi: "tsumagoi.kensaur.us"
2436
2621
  };
2437
2622
  var SLUG_ICON_URL_HINTS = {
2438
2623
  "mushi-mushi": "https://kensaur.us/mushi-mushi/admin/favicon.svg",
2439
2624
  "solo-boss-cloud": "https://solo-boss.kensaur.us/favicon.svg",
2440
2625
  "glot-it": "https://kensaur.us/glot-it/apple-touch-icon.png",
2441
- glotit: "https://kensaur.us/glot-it/apple-touch-icon.png"
2626
+ glotit: "https://kensaur.us/glot-it/apple-touch-icon.png",
2627
+ "the-wanting-mind": "https://kensaur.us/the-wanting-mind/pwa-512x512.png",
2628
+ "how-to-talk-to-girls": "https://talk.kensaur.us/pwa-192.png",
2629
+ htttg: "https://talk.kensaur.us/pwa-192.png",
2630
+ tsumagoi: "https://tsumagoi.kensaur.us/apple-touch-icon.png",
2631
+ "help-her-take-photo": "https://kensaur.us/help-her-take-photo/assets/apple-touch-icon.png",
2632
+ "yen-yen": "https://kensaur.us/yen-yen/icon.svg"
2442
2633
  };
2443
2634
  var UNTRUSTED_FAVICON_HOSTS = [
2444
2635
  "www.google.com",
@@ -2610,6 +2801,6 @@ function isSafeFaviconHref(href) {
2610
2801
  }
2611
2802
  }
2612
2803
 
2613
- 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_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, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroySessionTracker, diagnoseEnvConfig, estimateJsonBytes, expandPreset, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initSessionTracker, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, scrubUrl, sha256Hex, trackPageView, updateSessionIdentity, validateConfig };
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 };
2614
2805
  //# sourceMappingURL=index.js.map
2615
2806
  //# sourceMappingURL=index.js.map