@mushi-mushi/core 1.21.0 → 1.22.1

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 CHANGED
@@ -1,6 +1,8 @@
1
1
  # @mushi-mushi/core
2
2
 
3
- Core types, API client, and utilities for the Mushi Mushi SDK.
3
+ > **Your AI wrote it. Mushi tells you why it broke.**
4
+
5
+ Core types, API client, and shared utilities for every Mushi SDK package.
4
6
 
5
7
  > **You almost certainly don't need to install this directly.** Run `npx mushi-mushi` and the wizard will pick the right framework SDK ([`@mushi-mushi/react`](https://npmjs.com/package/@mushi-mushi/react), [`@mushi-mushi/vue`](https://npmjs.com/package/@mushi-mushi/vue), [`@mushi-mushi/svelte`](https://npmjs.com/package/@mushi-mushi/svelte), [`@mushi-mushi/angular`](https://npmjs.com/package/@mushi-mushi/angular), [`@mushi-mushi/react-native`](https://npmjs.com/package/@mushi-mushi/react-native), [`@mushi-mushi/capacitor`](https://npmjs.com/package/@mushi-mushi/capacitor), or [`@mushi-mushi/web`](https://npmjs.com/package/@mushi-mushi/web)) which depends on this package.
6
8
 
@@ -70,4 +72,4 @@ MIT
70
72
  <!-- mushi-readme-stats-footer -->
71
73
  ---
72
74
 
73
- <sub>Monorepo scale (June 2026): 47 edge functions · 256 SQL migrations · 13 outbound plugins · 11 inbound adapters · 18 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>
75
+ <sub>Monorepo scale (June 2026): 51 edge functions · 298 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
@@ -106,6 +106,8 @@ var MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
106
106
  var MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
107
107
  var DEFAULT_TIMEOUT = 1e4;
108
108
  var DEFAULT_MAX_RETRIES = 2;
109
+ var DEFAULT_CIRCUIT_THRESHOLD = 4;
110
+ var DEFAULT_CIRCUIT_COOLDOWN_MS = 3e4;
109
111
  function createApiClient(options) {
110
112
  const {
111
113
  projectId,
@@ -115,10 +117,29 @@ function createApiClient(options) {
115
117
  maxRetries = DEFAULT_MAX_RETRIES,
116
118
  getUserToken,
117
119
  sdkPackage,
118
- sdkVersion
120
+ sdkVersion,
121
+ circuitBreaker
119
122
  } = options;
120
123
  let baseUrl = apiEndpoint.replace(/\/$/, "");
124
+ const cbEnabled = circuitBreaker?.enabled !== false;
125
+ const cbThreshold = Math.max(1, circuitBreaker?.threshold ?? DEFAULT_CIRCUIT_THRESHOLD);
126
+ const cbCooldownMs = Math.max(1e3, circuitBreaker?.cooldownMs ?? DEFAULT_CIRCUIT_COOLDOWN_MS);
127
+ let cbFailures = 0;
128
+ let cbOpenUntil = 0;
129
+ const cbIsOpen = () => cbEnabled && cbOpenUntil > Date.now();
130
+ const cbRecordReachable = () => {
131
+ cbFailures = 0;
132
+ cbOpenUntil = 0;
133
+ };
134
+ const cbRecordUnreachable = () => {
135
+ if (!cbEnabled) return;
136
+ cbFailures += 1;
137
+ if (cbFailures >= cbThreshold) cbOpenUntil = Date.now() + cbCooldownMs;
138
+ };
121
139
  async function request(method, path, body, retries = maxRetries, internalKind, extraHeaders) {
140
+ if (cbIsOpen()) {
141
+ return { ok: false, error: { code: "CIRCUIT_OPEN", message: "Endpoint temporarily unavailable; retrying later." } };
142
+ }
122
143
  const url = `${baseUrl}${path}`;
123
144
  const controller = new AbortController();
124
145
  const timer = setTimeout(() => controller.abort(), timeout);
@@ -165,6 +186,8 @@ function createApiClient(options) {
165
186
  await sleep(getBackoffDelay(maxRetries - retries));
166
187
  return request(method, path, body, retries - 1, internalKind, extraHeaders);
167
188
  }
189
+ if (response.status >= 500) cbRecordUnreachable();
190
+ else cbRecordReachable();
168
191
  return {
169
192
  ok: false,
170
193
  error: {
@@ -175,6 +198,7 @@ function createApiClient(options) {
175
198
  }
176
199
  const payload = await response.json();
177
200
  const data = payload && typeof payload === "object" && "ok" in payload && "data" in payload ? payload.data : payload;
201
+ cbRecordReachable();
178
202
  return { ok: true, data };
179
203
  } catch (error) {
180
204
  clearTimeout(timer);
@@ -182,6 +206,7 @@ function createApiClient(options) {
182
206
  await sleep(getBackoffDelay(maxRetries - retries));
183
207
  return request(method, path, body, retries - 1, internalKind);
184
208
  }
209
+ cbRecordUnreachable();
185
210
  return {
186
211
  ok: false,
187
212
  error: {
@@ -466,9 +491,9 @@ function isRetryable(error) {
466
491
 
467
492
  // src/region.ts
468
493
  var REGION_ENDPOINTS = {
469
- us: "https://api.us.mushimushi.dev/functions/v1/api",
470
- eu: "https://api.eu.mushimushi.dev/functions/v1/api",
471
- jp: "https://api.jp.mushimushi.dev/functions/v1/api"
494
+ us: "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api",
495
+ eu: "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api",
496
+ jp: "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api"
472
497
  };
473
498
  var ROUTING_CACHE_KEY = "mushi_region_v1";
474
499
  var ROUTING_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -1214,7 +1239,8 @@ function createOfflineQueue(config = {}) {
1214
1239
  if (!enabled || !syncOnReconnect || typeof window === "undefined") return;
1215
1240
  const tryFlush = () => {
1216
1241
  if (navigator.onLine) {
1217
- flush(client).catch(() => {
1242
+ flush(client).catch((err) => {
1243
+ queueLog.warn("Offline queue auto-flush failed", { err: String(err) });
1218
1244
  });
1219
1245
  }
1220
1246
  };
@@ -1247,6 +1273,15 @@ function captureEnvironment() {
1247
1273
  const scr = typeof screen !== "undefined" ? screen : void 0;
1248
1274
  void kickOffUserAgentData(nav);
1249
1275
  const connection = nav && "connection" in nav ? nav.connection : void 0;
1276
+ const w = win;
1277
+ const isCapacitor = !!w?.Capacitor;
1278
+ const isCordova = !!w?.cordova;
1279
+ const isReactNative = nav?.product === "ReactNative" || typeof globalThis.HermesInternal !== "undefined";
1280
+ const native = isCapacitor || isCordova || isReactNative ? {
1281
+ ...isCapacitor ? { capacitor: true } : {},
1282
+ ...isCordova ? { cordova: true } : {},
1283
+ ...isReactNative ? { reactNative: true } : {}
1284
+ } : void 0;
1250
1285
  return {
1251
1286
  userAgent: nav?.userAgent ?? "unknown",
1252
1287
  platform: nav?.platform ?? "unknown",
@@ -1279,7 +1314,8 @@ function captureEnvironment() {
1279
1314
  displayMode: matchDisplayMode(win),
1280
1315
  documentTitle: doc?.title?.slice(0, 200),
1281
1316
  buildId: readBuildIdMeta(doc),
1282
- pageLoadTiming: capturePageLoadTiming(win)
1317
+ pageLoadTiming: capturePageLoadTiming(win),
1318
+ ...native ? { native } : {}
1283
1319
  };
1284
1320
  }
1285
1321
  function findNearestTestidFromActive(doc) {
@@ -1551,8 +1587,21 @@ function getSessionId() {
1551
1587
  }
1552
1588
  function generateSessionId() {
1553
1589
  const timestamp = Date.now().toString(36);
1554
- const random = Math.random().toString(36).slice(2, 8);
1555
- return `ms_${timestamp}_${random}`;
1590
+ return `ms_${timestamp}_${randomSuffix()}`;
1591
+ }
1592
+ function randomSuffix() {
1593
+ const c = typeof crypto !== "undefined" ? crypto : void 0;
1594
+ const bytes = new Uint8Array(4);
1595
+ if (c?.getRandomValues) {
1596
+ c.getRandomValues(bytes);
1597
+ } else {
1598
+ for (let i = 0; i < bytes.length; i++) {
1599
+ bytes[i] = Math.floor(Math.random() * 256);
1600
+ }
1601
+ }
1602
+ let n = 0;
1603
+ for (const b of bytes) n = n * 256 + b >>> 0;
1604
+ return n.toString(36).padStart(6, "0").slice(0, 6);
1556
1605
  }
1557
1606
 
1558
1607
  // src/rate-limiter.ts
@@ -1933,7 +1982,7 @@ var SLUG_DOMAIN_HINTS = {
1933
1982
  "glot-it": "glot.it",
1934
1983
  glotit: "glot.it",
1935
1984
  "solo-boss-cloud": "sbc-front.vercel.app",
1936
- "mushi-mushi": "mushimushi.dev"
1985
+ "mushi-mushi": "kensaur.us"
1937
1986
  };
1938
1987
  var SLUG_ICON_URL_HINTS = {
1939
1988
  "mushi-mushi": "https://kensaur.us/mushi-mushi/admin/favicon.svg",
@@ -2112,6 +2161,8 @@ function isSafeFaviconHref(href) {
2112
2161
  }
2113
2162
 
2114
2163
  exports.DEFAULT_API_ENDPOINT = DEFAULT_API_ENDPOINT;
2164
+ exports.DEFAULT_MAX_RETRIES = DEFAULT_MAX_RETRIES;
2165
+ exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
2115
2166
  exports.MAX_REPORT_PAYLOAD_BYTES = MAX_REPORT_PAYLOAD_BYTES;
2116
2167
  exports.MAX_SCREENSHOT_DATA_URL_BYTES = MAX_SCREENSHOT_DATA_URL_BYTES;
2117
2168
  exports.MUSHI_ACCENT_SHADOW = MUSHI_ACCENT_SHADOW;