@mushi-mushi/core 1.16.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 +83 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +83 -5
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -44,6 +44,8 @@ function formatBytes(n) {
|
|
|
44
44
|
|
|
45
45
|
// src/api-client.ts
|
|
46
46
|
var MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
|
|
47
|
+
var MUSHI_SDK_PACKAGE_HEADER = "X-Mushi-SDK-Package";
|
|
48
|
+
var MUSHI_SDK_VERSION_HEADER = "X-Mushi-SDK-Version";
|
|
47
49
|
var DEFAULT_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api";
|
|
48
50
|
var MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
|
|
49
51
|
var MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
|
|
@@ -56,7 +58,9 @@ function createApiClient(options) {
|
|
|
56
58
|
apiEndpoint = DEFAULT_API_ENDPOINT,
|
|
57
59
|
timeout = DEFAULT_TIMEOUT,
|
|
58
60
|
maxRetries = DEFAULT_MAX_RETRIES,
|
|
59
|
-
getUserToken
|
|
61
|
+
getUserToken,
|
|
62
|
+
sdkPackage,
|
|
63
|
+
sdkVersion
|
|
60
64
|
} = options;
|
|
61
65
|
let baseUrl = apiEndpoint.replace(/\/$/, "");
|
|
62
66
|
async function request(method, path, body, retries = maxRetries, internalKind, extraHeaders) {
|
|
@@ -71,6 +75,8 @@ function createApiClient(options) {
|
|
|
71
75
|
"Content-Type": "application/json",
|
|
72
76
|
"X-Mushi-Api-Key": apiKey,
|
|
73
77
|
"X-Mushi-Project": projectId,
|
|
78
|
+
...sdkPackage ? { [MUSHI_SDK_PACKAGE_HEADER]: sdkPackage } : {},
|
|
79
|
+
...sdkVersion ? { [MUSHI_SDK_VERSION_HEADER]: sdkVersion } : {},
|
|
74
80
|
...userToken ? { [MUSHI_USER_TOKEN_HEADER]: userToken } : {},
|
|
75
81
|
...internalKind ? { [MUSHI_INTERNAL_HEADER]: internalKind } : {},
|
|
76
82
|
...extraHeaders
|
|
@@ -133,6 +139,8 @@ function createApiClient(options) {
|
|
|
133
139
|
"Content-Type": "application/json",
|
|
134
140
|
"X-Mushi-Api-Key": apiKey,
|
|
135
141
|
"X-Mushi-Project": projectId,
|
|
142
|
+
...sdkPackage ? { [MUSHI_SDK_PACKAGE_HEADER]: sdkPackage } : {},
|
|
143
|
+
...sdkVersion ? { [MUSHI_SDK_VERSION_HEADER]: sdkVersion } : {},
|
|
136
144
|
[MUSHI_INTERNAL_HEADER]: "reporter-poll",
|
|
137
145
|
"X-Reporter-Token-Hash": tokenHash,
|
|
138
146
|
"X-Reporter-Ts": ts,
|
|
@@ -834,6 +842,8 @@ var LS_KEY = "mushi_offline_queue";
|
|
|
834
842
|
var BATCH_SIZE = 10;
|
|
835
843
|
var MAX_BACKOFF_MS = 6e4;
|
|
836
844
|
var AUTO_FLUSH_INTERVAL_MS = 3e4;
|
|
845
|
+
var MAX_DELIVERY_ATTEMPTS = 8;
|
|
846
|
+
var MAX_QUEUE_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
837
847
|
function createOfflineQueue(config = {}) {
|
|
838
848
|
const { enabled = true, maxQueueSize = 50, syncOnReconnect = true, encryptAtRest = true } = config;
|
|
839
849
|
let syncCleanup = null;
|
|
@@ -866,6 +876,17 @@ function createOfflineQueue(config = {}) {
|
|
|
866
876
|
function isEncryptedRecord(row) {
|
|
867
877
|
return !!row.payload && isEncryptedPayload(row.payload);
|
|
868
878
|
}
|
|
879
|
+
function rowAttempts(row) {
|
|
880
|
+
const n = row.attempts;
|
|
881
|
+
return typeof n === "number" && Number.isFinite(n) ? n : 0;
|
|
882
|
+
}
|
|
883
|
+
function isExpired(row, now) {
|
|
884
|
+
const queuedAt = row.queuedAt;
|
|
885
|
+
if (!queuedAt) return false;
|
|
886
|
+
const ts = Date.parse(queuedAt);
|
|
887
|
+
if (Number.isNaN(ts)) return false;
|
|
888
|
+
return now - ts > MAX_QUEUE_AGE_MS;
|
|
889
|
+
}
|
|
869
890
|
function detectBackend() {
|
|
870
891
|
if (backendType) return backendType;
|
|
871
892
|
if (typeof indexedDB !== "undefined") {
|
|
@@ -921,6 +942,15 @@ function createOfflineQueue(config = {}) {
|
|
|
921
942
|
tx.onerror = () => reject(tx.error);
|
|
922
943
|
});
|
|
923
944
|
}
|
|
945
|
+
async function idbPutRow(row) {
|
|
946
|
+
const db = await openDb();
|
|
947
|
+
return new Promise((resolve, reject) => {
|
|
948
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
949
|
+
tx.objectStore(STORE_NAME).put(row);
|
|
950
|
+
tx.oncomplete = () => resolve();
|
|
951
|
+
tx.onerror = () => reject(tx.error);
|
|
952
|
+
});
|
|
953
|
+
}
|
|
924
954
|
async function idbSize() {
|
|
925
955
|
const db = await openDb();
|
|
926
956
|
return new Promise((resolve, reject) => {
|
|
@@ -962,6 +992,14 @@ function createOfflineQueue(config = {}) {
|
|
|
962
992
|
const rows = lsRead().filter((r) => r.id !== id);
|
|
963
993
|
lsWrite(rows);
|
|
964
994
|
}
|
|
995
|
+
function lsUpdateRow(row) {
|
|
996
|
+
const rows = lsRead();
|
|
997
|
+
const idx = rows.findIndex((r) => r.id === row.id);
|
|
998
|
+
if (idx >= 0) {
|
|
999
|
+
rows[idx] = row;
|
|
1000
|
+
lsWrite(rows);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
965
1003
|
async function enqueue(report) {
|
|
966
1004
|
if (!enabled) return;
|
|
967
1005
|
const currentSize = await size();
|
|
@@ -1002,6 +1040,23 @@ function createOfflineQueue(config = {}) {
|
|
|
1002
1040
|
} else {
|
|
1003
1041
|
rows = lsRead();
|
|
1004
1042
|
}
|
|
1043
|
+
const now = Date.now();
|
|
1044
|
+
const fresh = [];
|
|
1045
|
+
for (const row of rows) {
|
|
1046
|
+
if (isExpired(row, now)) {
|
|
1047
|
+
const rowId = row.id;
|
|
1048
|
+
try {
|
|
1049
|
+
if (backend === "indexeddb") await idbDelete(rowId);
|
|
1050
|
+
else lsDelete(rowId);
|
|
1051
|
+
} catch {
|
|
1052
|
+
lsDelete(rowId);
|
|
1053
|
+
}
|
|
1054
|
+
queueLog.debug("Offline queue: evicting stale report", { id: rowId });
|
|
1055
|
+
} else {
|
|
1056
|
+
fresh.push(row);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
rows = fresh;
|
|
1005
1060
|
const batch = rows.slice(0, BATCH_SIZE);
|
|
1006
1061
|
let sent = 0;
|
|
1007
1062
|
let failed = 0;
|
|
@@ -1045,10 +1100,33 @@ function createOfflineQueue(config = {}) {
|
|
|
1045
1100
|
lsDelete(rowId);
|
|
1046
1101
|
}
|
|
1047
1102
|
} else if (transient) {
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1103
|
+
const nextAttempts = rowAttempts(row) + 1;
|
|
1104
|
+
if (nextAttempts >= MAX_DELIVERY_ATTEMPTS) {
|
|
1105
|
+
try {
|
|
1106
|
+
if (backend === "indexeddb") await idbDelete(rowId);
|
|
1107
|
+
else lsDelete(rowId);
|
|
1108
|
+
} catch {
|
|
1109
|
+
lsDelete(rowId);
|
|
1110
|
+
}
|
|
1111
|
+
queueLog.warn("Offline queue: giving up on report after repeated failures", {
|
|
1112
|
+
id: rowId,
|
|
1113
|
+
attempts: nextAttempts,
|
|
1114
|
+
code: result.error?.code
|
|
1115
|
+
});
|
|
1116
|
+
} else {
|
|
1117
|
+
row.attempts = nextAttempts;
|
|
1118
|
+
try {
|
|
1119
|
+
if (backend === "indexeddb") await idbPutRow(row);
|
|
1120
|
+
else lsUpdateRow(row);
|
|
1121
|
+
} catch {
|
|
1122
|
+
lsUpdateRow(row);
|
|
1123
|
+
}
|
|
1124
|
+
queueLog.debug("Offline queue: transient failure, will retry", {
|
|
1125
|
+
id: rowId,
|
|
1126
|
+
attempts: nextAttempts,
|
|
1127
|
+
code: result.error?.code
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1052
1130
|
}
|
|
1053
1131
|
failed++;
|
|
1054
1132
|
if (i < batch.length - 1) {
|