@mushi-mushi/core 1.9.0 → 1.10.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.cjs CHANGED
@@ -194,6 +194,15 @@ function createApiClient(options) {
194
194
  1,
195
195
  "reporter-poll"
196
196
  );
197
+ },
198
+ async getHallOfFame(limit = 10) {
199
+ return request(
200
+ "GET",
201
+ `/v1/sdk/hall-of-fame?limit=${limit}`,
202
+ void 0,
203
+ 1,
204
+ "reporter-poll"
205
+ );
197
206
  }
198
207
  };
199
208
  }
@@ -292,8 +301,10 @@ var SPAM_PATTERNS = [
292
301
  // numbers only
293
302
  /^[^a-zA-Z\u00C0-\u024F\u4E00-\u9FFF\u3040-\u309F\u30A0-\u30FF]{10,}$/,
294
303
  // no real letters
295
- /\b(test|asdf|qwerty|lorem ipsum)\b/i
296
- // common test strings
304
+ // "test" removed — users legitimately write "I was testing…" in real reports.
305
+ // Keep clearly-nonsense patterns that are never real sentences.
306
+ /^(asdf|qwerty|lorem ipsum)[.,!?\s]*$/i
307
+ // standalone keyboard-mash or placeholder
297
308
  ];
298
309
  var GIBBERISH_PATTERN = /^[bcdfghjklmnpqrstvwxz]{6,}/i;
299
310
  function createPreFilter(config = {}) {
@@ -583,9 +594,11 @@ var DB_VERSION = 1;
583
594
  var LS_KEY = "mushi_offline_queue";
584
595
  var BATCH_SIZE = 10;
585
596
  var MAX_BACKOFF_MS = 6e4;
597
+ var AUTO_FLUSH_INTERVAL_MS = 3e4;
586
598
  function createOfflineQueue(config = {}) {
587
599
  const { enabled = true, maxQueueSize = 50, syncOnReconnect = true, encryptAtRest = true } = config;
588
600
  let syncCleanup = null;
601
+ let flushInterval = null;
589
602
  let backendType = null;
590
603
  async function wrapForStorage(report) {
591
604
  const queuedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -780,6 +793,7 @@ function createOfflineQueue(config = {}) {
780
793
  const permanent = result.error?.code === "HTTP_400" || result.error?.code === "HTTP_422" || result.error?.code === "INGEST_ERROR" || result.error?.code === "VALIDATION_ERROR" || typeof result.error?.message === "string" && /invalid payload|description must be at least|validation/i.test(
781
794
  result.error.message
782
795
  );
796
+ 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"));
783
797
  if (permanent) {
784
798
  try {
785
799
  if (backend === "indexeddb") await idbDelete(rowId);
@@ -787,6 +801,11 @@ function createOfflineQueue(config = {}) {
787
801
  } catch {
788
802
  lsDelete(rowId);
789
803
  }
804
+ } else if (transient) {
805
+ queueLog.debug("Offline queue: transient failure, will retry", {
806
+ id: rowId,
807
+ code: result.error?.code
808
+ });
790
809
  }
791
810
  failed++;
792
811
  if (i < batch.length - 1) {
@@ -822,14 +841,25 @@ function createOfflineQueue(config = {}) {
822
841
  }
823
842
  function startAutoSync(client) {
824
843
  if (!enabled || !syncOnReconnect || typeof window === "undefined") return;
825
- const handler = () => {
844
+ const tryFlush = () => {
826
845
  if (navigator.onLine) {
827
846
  flush(client).catch(() => {
828
847
  });
829
848
  }
830
849
  };
831
- window.addEventListener("online", handler);
832
- syncCleanup = () => window.removeEventListener("online", handler);
850
+ window.addEventListener("online", tryFlush);
851
+ flushInterval = setInterval(() => {
852
+ void size().then((n) => {
853
+ if (n > 0) tryFlush();
854
+ });
855
+ }, AUTO_FLUSH_INTERVAL_MS);
856
+ syncCleanup = () => {
857
+ window.removeEventListener("online", tryFlush);
858
+ if (flushInterval) {
859
+ clearInterval(flushInterval);
860
+ flushInterval = null;
861
+ }
862
+ };
833
863
  }
834
864
  function stopAutoSync() {
835
865
  syncCleanup?.();