@mushi-mushi/core 1.17.0 → 1.18.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 +74 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +74 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -840,6 +840,8 @@ var LS_KEY = "mushi_offline_queue";
|
|
|
840
840
|
var BATCH_SIZE = 10;
|
|
841
841
|
var MAX_BACKOFF_MS = 6e4;
|
|
842
842
|
var AUTO_FLUSH_INTERVAL_MS = 3e4;
|
|
843
|
+
var MAX_DELIVERY_ATTEMPTS = 8;
|
|
844
|
+
var MAX_QUEUE_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
843
845
|
function createOfflineQueue(config = {}) {
|
|
844
846
|
const { enabled = true, maxQueueSize = 50, syncOnReconnect = true, encryptAtRest = true } = config;
|
|
845
847
|
let syncCleanup = null;
|
|
@@ -872,6 +874,17 @@ function createOfflineQueue(config = {}) {
|
|
|
872
874
|
function isEncryptedRecord(row) {
|
|
873
875
|
return !!row.payload && isEncryptedPayload(row.payload);
|
|
874
876
|
}
|
|
877
|
+
function rowAttempts(row) {
|
|
878
|
+
const n = row.attempts;
|
|
879
|
+
return typeof n === "number" && Number.isFinite(n) ? n : 0;
|
|
880
|
+
}
|
|
881
|
+
function isExpired(row, now) {
|
|
882
|
+
const queuedAt = row.queuedAt;
|
|
883
|
+
if (!queuedAt) return false;
|
|
884
|
+
const ts = Date.parse(queuedAt);
|
|
885
|
+
if (Number.isNaN(ts)) return false;
|
|
886
|
+
return now - ts > MAX_QUEUE_AGE_MS;
|
|
887
|
+
}
|
|
875
888
|
function detectBackend() {
|
|
876
889
|
if (backendType) return backendType;
|
|
877
890
|
if (typeof indexedDB !== "undefined") {
|
|
@@ -927,6 +940,15 @@ function createOfflineQueue(config = {}) {
|
|
|
927
940
|
tx.onerror = () => reject(tx.error);
|
|
928
941
|
});
|
|
929
942
|
}
|
|
943
|
+
async function idbPutRow(row) {
|
|
944
|
+
const db = await openDb();
|
|
945
|
+
return new Promise((resolve, reject) => {
|
|
946
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
947
|
+
tx.objectStore(STORE_NAME).put(row);
|
|
948
|
+
tx.oncomplete = () => resolve();
|
|
949
|
+
tx.onerror = () => reject(tx.error);
|
|
950
|
+
});
|
|
951
|
+
}
|
|
930
952
|
async function idbSize() {
|
|
931
953
|
const db = await openDb();
|
|
932
954
|
return new Promise((resolve, reject) => {
|
|
@@ -968,6 +990,14 @@ function createOfflineQueue(config = {}) {
|
|
|
968
990
|
const rows = lsRead().filter((r) => r.id !== id);
|
|
969
991
|
lsWrite(rows);
|
|
970
992
|
}
|
|
993
|
+
function lsUpdateRow(row) {
|
|
994
|
+
const rows = lsRead();
|
|
995
|
+
const idx = rows.findIndex((r) => r.id === row.id);
|
|
996
|
+
if (idx >= 0) {
|
|
997
|
+
rows[idx] = row;
|
|
998
|
+
lsWrite(rows);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
971
1001
|
async function enqueue(report) {
|
|
972
1002
|
if (!enabled) return;
|
|
973
1003
|
const currentSize = await size();
|
|
@@ -1008,6 +1038,23 @@ function createOfflineQueue(config = {}) {
|
|
|
1008
1038
|
} else {
|
|
1009
1039
|
rows = lsRead();
|
|
1010
1040
|
}
|
|
1041
|
+
const now = Date.now();
|
|
1042
|
+
const fresh = [];
|
|
1043
|
+
for (const row of rows) {
|
|
1044
|
+
if (isExpired(row, now)) {
|
|
1045
|
+
const rowId = row.id;
|
|
1046
|
+
try {
|
|
1047
|
+
if (backend === "indexeddb") await idbDelete(rowId);
|
|
1048
|
+
else lsDelete(rowId);
|
|
1049
|
+
} catch {
|
|
1050
|
+
lsDelete(rowId);
|
|
1051
|
+
}
|
|
1052
|
+
queueLog.debug("Offline queue: evicting stale report", { id: rowId });
|
|
1053
|
+
} else {
|
|
1054
|
+
fresh.push(row);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
rows = fresh;
|
|
1011
1058
|
const batch = rows.slice(0, BATCH_SIZE);
|
|
1012
1059
|
let sent = 0;
|
|
1013
1060
|
let failed = 0;
|
|
@@ -1051,10 +1098,33 @@ function createOfflineQueue(config = {}) {
|
|
|
1051
1098
|
lsDelete(rowId);
|
|
1052
1099
|
}
|
|
1053
1100
|
} else if (transient) {
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1101
|
+
const nextAttempts = rowAttempts(row) + 1;
|
|
1102
|
+
if (nextAttempts >= MAX_DELIVERY_ATTEMPTS) {
|
|
1103
|
+
try {
|
|
1104
|
+
if (backend === "indexeddb") await idbDelete(rowId);
|
|
1105
|
+
else lsDelete(rowId);
|
|
1106
|
+
} catch {
|
|
1107
|
+
lsDelete(rowId);
|
|
1108
|
+
}
|
|
1109
|
+
queueLog.warn("Offline queue: giving up on report after repeated failures", {
|
|
1110
|
+
id: rowId,
|
|
1111
|
+
attempts: nextAttempts,
|
|
1112
|
+
code: result.error?.code
|
|
1113
|
+
});
|
|
1114
|
+
} else {
|
|
1115
|
+
row.attempts = nextAttempts;
|
|
1116
|
+
try {
|
|
1117
|
+
if (backend === "indexeddb") await idbPutRow(row);
|
|
1118
|
+
else lsUpdateRow(row);
|
|
1119
|
+
} catch {
|
|
1120
|
+
lsUpdateRow(row);
|
|
1121
|
+
}
|
|
1122
|
+
queueLog.debug("Offline queue: transient failure, will retry", {
|
|
1123
|
+
id: rowId,
|
|
1124
|
+
attempts: nextAttempts,
|
|
1125
|
+
code: result.error?.code
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1058
1128
|
}
|
|
1059
1129
|
failed++;
|
|
1060
1130
|
if (i < batch.length - 1) {
|