@prototypevip/baileys 0.1.0 → 0.1.2
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/lib/Defaults/index.js +3 -3
- package/lib/Defaults/index.js.bak-1788476907801 +187 -0
- package/lib/Defaults/index.js.bak-1788479166288 +187 -0
- package/lib/Socket/groups.js.bak-1788476973954 +475 -0
- package/lib/Socket/index.js +42 -126
- package/lib/Socket/index.js.bak-1788479281092 +38 -0
- package/lib/Socket/messages-send.js +88 -51
- package/lib/Store/prototype-store.js +34 -22
- package/lib/Store/prototype-store.js.bak-1788477006895 +983 -0
- package/lib/Utils/index.js +2 -0
- package/lib/Utils/integrity-guard.js +281 -0
- package/lib/Utils/interactive-message-handler.js +28 -8
- package/lib/Utils/interactive-message-handler.js.bak-1788476898661 +478 -0
- package/lib/Utils/socket-guard.js +154 -0
- package/package.json +2 -2
- package/lib/AntiBan/antiban.js +0 -922
- package/lib/AntiBan/banRecoveryOrchestrator.js +0 -284
- package/lib/AntiBan/cli.js +0 -177
- package/lib/AntiBan/contactGraph.js +0 -236
- package/lib/AntiBan/contentVariator.js +0 -150
- package/lib/AntiBan/credsSnapshot.js +0 -121
- package/lib/AntiBan/deliveryTracker.js +0 -107
- package/lib/AntiBan/deviceFingerprint.js +0 -106
- package/lib/AntiBan/fleetEventStore.js +0 -157
- package/lib/AntiBan/groupOperationGuard.js +0 -116
- package/lib/AntiBan/health.js +0 -207
- package/lib/AntiBan/humanEntropy.js +0 -337
- package/lib/AntiBan/index.js +0 -77
- package/lib/AntiBan/instanceCoordinator.js +0 -175
- package/lib/AntiBan/jidCanonicalizer.js +0 -256
- package/lib/AntiBan/jidCircuitBreaker.js +0 -186
- package/lib/AntiBan/legitimacySignalInjector.js +0 -231
- package/lib/AntiBan/lidFirstResolver.js +0 -174
- package/lib/AntiBan/lidResolver.js +0 -324
- package/lib/AntiBan/messageQueue.js +0 -187
- package/lib/AntiBan/messageRecovery.js +0 -283
- package/lib/AntiBan/messageTypeRegistry.js +0 -369
- package/lib/AntiBan/observability.js +0 -145
- package/lib/AntiBan/patch.js +0 -302
- package/lib/AntiBan/persist.js +0 -87
- package/lib/AntiBan/presenceChoreographer.js +0 -430
- package/lib/AntiBan/presets.js +0 -105
- package/lib/AntiBan/profiles.js +0 -31
- package/lib/AntiBan/proxyRotator.js +0 -306
- package/lib/AntiBan/rateLimiter.js +0 -261
- package/lib/AntiBan/readReceiptVariance.js +0 -88
- package/lib/AntiBan/reconnectThrottle.js +0 -180
- package/lib/AntiBan/replyRatio.js +0 -161
- package/lib/AntiBan/reputationVoucher.js +0 -373
- package/lib/AntiBan/retryReason.js +0 -91
- package/lib/AntiBan/retryTracker.js +0 -172
- package/lib/AntiBan/scheduler.js +0 -111
- package/lib/AntiBan/sessionFingerprint.js +0 -248
- package/lib/AntiBan/sessionStability.js +0 -330
- package/lib/AntiBan/stateAdapter.js +0 -73
- package/lib/AntiBan/stateExport.js +0 -152
- package/lib/AntiBan/stealthConnect.js +0 -130
- package/lib/AntiBan/timelockGuard.js +0 -181
- package/lib/AntiBan/topologyThrottler.js +0 -339
- package/lib/AntiBan/warmup.js +0 -140
- package/lib/AntiBan/webhooks.js +0 -80
- package/lib/AntiBan/wrapper.js +0 -456
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DEFAULT_CONNECTION_CONFIG } from "../Defaults/index.js";
|
|
2
|
+
import { makeCommunitiesSocket } from "./communities.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create a WhatsApp socket.
|
|
6
|
+
* Clean version — without AntiBan.
|
|
7
|
+
*/
|
|
8
|
+
const makeWASocket = (config = {}) => {
|
|
9
|
+
const restConfig = { ...(config || {}) };
|
|
10
|
+
|
|
11
|
+
// strip any leftover antiBan keys if present
|
|
12
|
+
delete restConfig.antiBan;
|
|
13
|
+
delete restConfig.antiBanWarmUpState;
|
|
14
|
+
delete restConfig.antiBanWrapOptions;
|
|
15
|
+
delete restConfig.userDevicesCache;
|
|
16
|
+
|
|
17
|
+
const newConfig = { ...DEFAULT_CONNECTION_CONFIG, ...restConfig };
|
|
18
|
+
|
|
19
|
+
let sock;
|
|
20
|
+
const originalGetMessage = newConfig.getMessage;
|
|
21
|
+
if (typeof originalGetMessage === "function") {
|
|
22
|
+
newConfig.getMessage = async function (key) {
|
|
23
|
+
return originalGetMessage.call(sock || this, key);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
sock = makeCommunitiesSocket(newConfig);
|
|
28
|
+
return sock;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** Stubs kept for API compatibility (no-op without AntiBan) */
|
|
32
|
+
const wrapSocket = (sock) => sock;
|
|
33
|
+
const wrapSocketWithFingerprint = (makeSock, opts) =>
|
|
34
|
+
typeof makeSock === "function" ? makeSock(opts || {}) : makeSock;
|
|
35
|
+
const PRESETS = {};
|
|
36
|
+
|
|
37
|
+
export default makeWASocket;
|
|
38
|
+
export { makeWASocket, wrapSocket, wrapSocketWithFingerprint, PRESETS };
|
|
@@ -466,6 +466,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
466
466
|
content: undefined,
|
|
467
467
|
},
|
|
468
468
|
],
|
|
469
|
+
skipStoreEmit: true,
|
|
469
470
|
},
|
|
470
471
|
);
|
|
471
472
|
};
|
|
@@ -540,6 +541,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
540
541
|
const msgId = await relayMessage(meJid, message, {
|
|
541
542
|
additionalAttributes: { category: "peer", push_priority: "high_force" },
|
|
542
543
|
additionalNodes: [{ tag: "meta", attrs: { appdata: "default" } }],
|
|
544
|
+
skipStoreEmit: true,
|
|
543
545
|
});
|
|
544
546
|
return msgId;
|
|
545
547
|
};
|
|
@@ -647,6 +649,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
647
649
|
useCachedGroupMetadata,
|
|
648
650
|
addBizAttributes,
|
|
649
651
|
statusJidList,
|
|
652
|
+
skipStoreEmit,
|
|
650
653
|
},
|
|
651
654
|
) => {
|
|
652
655
|
// --- PN-First API Resolver: Resolve Mentions ---
|
|
@@ -845,31 +848,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
845
848
|
return {};
|
|
846
849
|
})(),
|
|
847
850
|
]);
|
|
848
|
-
//
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
const addParticipantJid = (jid) => {
|
|
853
|
-
if (!jid || typeof jid !== "string") return;
|
|
854
|
-
const normalized = jidNormalizedUser(jid);
|
|
855
|
-
const user = jidDecode(normalized)?.user;
|
|
856
|
-
if (!user || seenParticipantUsers.has(user + ":" + (normalized.split("@")[1] || ""))) {
|
|
857
|
-
// نسمح بنفس الـ user بصيغتين مختلفتين (pn + lid) بس نمنع التكرار الحرفي
|
|
858
|
-
}
|
|
859
|
-
if (participantsList.includes(normalized) || participantsList.includes(jid)) return;
|
|
860
|
-
participantsList.push(normalized);
|
|
861
|
-
if (user) seenParticipantUsers.add(user);
|
|
862
|
-
};
|
|
863
|
-
if (groupData?.participants) {
|
|
864
|
-
for (const p of groupData.participants) {
|
|
865
|
-
addParticipantJid(p.id);
|
|
866
|
-
// بديل LID لو الـ id رقم (PN) — مهم لحسابات اليوزرنيم
|
|
867
|
-
if (p.lid) addParticipantJid(p.lid);
|
|
868
|
-
// بديل الرقم لو الـ id LID
|
|
869
|
-
if (p.phoneNumber) addParticipantJid(p.phoneNumber);
|
|
870
|
-
if (p.jid && p.jid !== p.id) addParticipantJid(p.jid);
|
|
871
|
-
}
|
|
872
|
-
}
|
|
851
|
+
// قائمة المشاركين الأساسية (زي الرسمي) — p.id بس عشان ميأثرش على الناس العادية
|
|
852
|
+
const participantsList = groupData?.participants
|
|
853
|
+
? groupData.participants.map((p) => p.id)
|
|
854
|
+
: [];
|
|
873
855
|
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
874
856
|
additionalAttributes = {
|
|
875
857
|
...additionalAttributes,
|
|
@@ -877,42 +859,46 @@ export const makeMessagesSocket = (config) => {
|
|
|
877
859
|
};
|
|
878
860
|
}
|
|
879
861
|
if (isStatus && statusJidList) {
|
|
880
|
-
|
|
862
|
+
participantsList.push(...statusJidList);
|
|
881
863
|
}
|
|
882
864
|
let additionalDevices = await getUSyncDevices(
|
|
883
865
|
participantsList,
|
|
884
866
|
!!useUserDevicesCache,
|
|
885
867
|
false,
|
|
886
868
|
);
|
|
887
|
-
//
|
|
888
|
-
// (
|
|
889
|
-
// على الـ JIDs الناقصة فقط — من غير ما نأثر على باقي الجروب
|
|
869
|
+
// Fallback لأصحاب اليوزرنيم/LID اللي p.id بتاعهم مرجعش أجهزة:
|
|
870
|
+
// نجرب الصيغة البديلة (lid أو phoneNumber) بس للناقصين — من غير ما نلوّث القائمة الأساسية
|
|
890
871
|
if (groupData?.participants?.length) {
|
|
891
872
|
const coveredUsers = new Set(
|
|
892
873
|
additionalDevices
|
|
893
874
|
.map((d) => d.user || jidDecode(d.jid)?.user)
|
|
894
875
|
.filter(Boolean),
|
|
895
876
|
);
|
|
896
|
-
const
|
|
877
|
+
const missingAlts = [];
|
|
878
|
+
const seenAlt = new Set();
|
|
897
879
|
for (const p of groupData.participants) {
|
|
898
|
-
const
|
|
899
|
-
const
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
880
|
+
const idNorm = p.id ? jidNormalizedUser(p.id) : null;
|
|
881
|
+
const idUser = idNorm ? jidDecode(idNorm)?.user : null;
|
|
882
|
+
if (idUser && coveredUsers.has(idUser)) continue;
|
|
883
|
+
// جرب البدائل المختلفة عن p.id فقط
|
|
884
|
+
const alts = [p.lid, p.phoneNumber, p.jid].filter(Boolean);
|
|
885
|
+
for (const alt of alts) {
|
|
886
|
+
const altNorm = jidNormalizedUser(alt);
|
|
887
|
+
if (!altNorm || altNorm === idNorm || seenAlt.has(altNorm)) continue;
|
|
888
|
+
const altUser = jidDecode(altNorm)?.user;
|
|
889
|
+
if (altUser && coveredUsers.has(altUser)) continue;
|
|
890
|
+
seenAlt.add(altNorm);
|
|
891
|
+
missingAlts.push(altNorm);
|
|
892
|
+
}
|
|
907
893
|
}
|
|
908
|
-
if (
|
|
894
|
+
if (missingAlts.length > 0) {
|
|
909
895
|
logger.debug(
|
|
910
|
-
{ missing:
|
|
911
|
-
"retrying USync for participants
|
|
896
|
+
{ missing: missingAlts.length, jids: missingAlts.slice(0, 5) },
|
|
897
|
+
"retrying USync for missing participants (username/LID fallback)",
|
|
912
898
|
);
|
|
913
899
|
try {
|
|
914
900
|
const retryDevices = await getUSyncDevices(
|
|
915
|
-
|
|
901
|
+
missingAlts,
|
|
916
902
|
false, // no cache
|
|
917
903
|
false,
|
|
918
904
|
8000, // longer timeout
|
|
@@ -921,7 +907,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
921
907
|
additionalDevices = [...additionalDevices, ...retryDevices];
|
|
922
908
|
}
|
|
923
909
|
} catch (e) {
|
|
924
|
-
logger.warn({ e }, "USync retry for missing participants failed");
|
|
910
|
+
logger.warn({ e }, "USync retry for missing username/LID participants failed");
|
|
925
911
|
}
|
|
926
912
|
}
|
|
927
913
|
}
|
|
@@ -1314,6 +1300,34 @@ export const makeMessagesSocket = (config) => {
|
|
|
1314
1300
|
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
1315
1301
|
}
|
|
1316
1302
|
}, meId);
|
|
1303
|
+
|
|
1304
|
+
// Ensure ANY call to relayMessage -- not just ones routed through
|
|
1305
|
+
// sendMessage's own wrapper -- respects emitOwnEvents and reaches
|
|
1306
|
+
// the store via messages.upsert. Callers that already build and
|
|
1307
|
+
// upsert a richer fullMsg themselves (sendMessage's internal call
|
|
1308
|
+
// sites) pass skipStoreEmit: true to avoid a duplicate upsert.
|
|
1309
|
+
if (config.emitOwnEvents && !skipStoreEmit && msgId && message) {
|
|
1310
|
+
const relayedKey = {
|
|
1311
|
+
remoteJid: destinationJid,
|
|
1312
|
+
fromMe: true,
|
|
1313
|
+
id: msgId,
|
|
1314
|
+
};
|
|
1315
|
+
if (isGroup) {
|
|
1316
|
+
relayedKey.participant = jidNormalizedUser(meId);
|
|
1317
|
+
} else if (participant?.jid) {
|
|
1318
|
+
relayedKey.participant = jidNormalizedUser(participant.jid);
|
|
1319
|
+
}
|
|
1320
|
+
const relayedMsg = {
|
|
1321
|
+
key: relayedKey,
|
|
1322
|
+
message: message,
|
|
1323
|
+
messageTimestamp: unixTimestampSeconds(),
|
|
1324
|
+
status: 1,
|
|
1325
|
+
};
|
|
1326
|
+
process.nextTick(async () => {
|
|
1327
|
+
await messageMutex.mutex(() => upsertMessage(relayedMsg, "append"));
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1317
1331
|
return msgId;
|
|
1318
1332
|
};
|
|
1319
1333
|
const getMessageType = (message) => {
|
|
@@ -1546,6 +1560,14 @@ export const makeMessagesSocket = (config) => {
|
|
|
1546
1560
|
|
|
1547
1561
|
const userJid = authState.creds.me.id;
|
|
1548
1562
|
|
|
1563
|
+
const emitUpsert = (msg, type = "append") => {
|
|
1564
|
+
if (config.emitOwnEvents && msg && msg.key) {
|
|
1565
|
+
process.nextTick(async () => {
|
|
1566
|
+
await messageMutex.mutex(() => upsertMessage(msg, type));
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1549
1571
|
if (Array.isArray(jid)) {
|
|
1550
1572
|
const { delayMs = 1500 } = options;
|
|
1551
1573
|
const allUsers = new Set();
|
|
@@ -1582,6 +1604,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1582
1604
|
await relayMessage("status@broadcast", fullMsg.message, {
|
|
1583
1605
|
messageId: fullMsg.key.id,
|
|
1584
1606
|
statusJidList: Array.from(allUsers),
|
|
1607
|
+
skipStoreEmit: true,
|
|
1585
1608
|
additionalNodes: [
|
|
1586
1609
|
{
|
|
1587
1610
|
tag: "meta",
|
|
@@ -1621,6 +1644,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
1621
1644
|
{ userJid: userJid },
|
|
1622
1645
|
);
|
|
1623
1646
|
await relayMessage(id, mentionMsg.message, {
|
|
1647
|
+
messageId: mentionMsg.key.id,
|
|
1648
|
+
skipStoreEmit: true,
|
|
1624
1649
|
additionalNodes: [
|
|
1625
1650
|
{
|
|
1626
1651
|
tag: "meta",
|
|
@@ -1651,29 +1676,39 @@ export const makeMessagesSocket = (config) => {
|
|
|
1651
1676
|
: disappearingMessagesInChat;
|
|
1652
1677
|
await groupToggleEphemeral(jid, value);
|
|
1653
1678
|
} else {
|
|
1654
|
-
const interactiveHandler = new InteractiveMessageHandler(Utils_1, waUploadToServer, relayMessage);
|
|
1679
|
+
const interactiveHandler = new InteractiveMessageHandler(Utils_1, waUploadToServer, relayMessage, emitUpsert);
|
|
1655
1680
|
const messageType = interactiveHandler.detectType(content);
|
|
1656
1681
|
if (messageType) {
|
|
1657
1682
|
switch (messageType) {
|
|
1658
1683
|
case 'PAYMENT': {
|
|
1659
1684
|
const paymentContent = await interactiveHandler.handlePayment(content, options.quoted);
|
|
1660
|
-
|
|
1661
|
-
|
|
1685
|
+
const paymentMsg = generateWAMessageFromContent(jid, paymentContent, { userJid: userJid });
|
|
1686
|
+
await relayMessage(jid, paymentMsg.message, {
|
|
1687
|
+
messageId: paymentMsg.key.id,
|
|
1688
|
+
skipStoreEmit: true
|
|
1662
1689
|
});
|
|
1690
|
+
emitUpsert(paymentMsg);
|
|
1691
|
+
return paymentMsg;
|
|
1663
1692
|
}
|
|
1664
1693
|
case 'PRODUCT': {
|
|
1665
1694
|
const productContent = await interactiveHandler.handleProduct(content, jid, options.quoted);
|
|
1666
1695
|
const productMsg = await generateWAMessageFromContent(jid, productContent, { quoted: options.quoted });
|
|
1667
|
-
|
|
1668
|
-
messageId: productMsg.key.id
|
|
1696
|
+
await relayMessage(jid, productMsg.message, {
|
|
1697
|
+
messageId: productMsg.key.id,
|
|
1698
|
+
skipStoreEmit: true
|
|
1669
1699
|
});
|
|
1700
|
+
emitUpsert(productMsg);
|
|
1701
|
+
return productMsg;
|
|
1670
1702
|
}
|
|
1671
1703
|
case 'INTERACTIVE': {
|
|
1672
1704
|
const interactiveContent = await interactiveHandler.handleInteractive(content, jid, options.quoted);
|
|
1673
1705
|
const interactiveMsg = await generateWAMessageFromContent(jid, interactiveContent, { quoted: options.quoted });
|
|
1674
|
-
|
|
1675
|
-
messageId: interactiveMsg.key.id
|
|
1706
|
+
await relayMessage(jid, interactiveMsg.message, {
|
|
1707
|
+
messageId: interactiveMsg.key.id,
|
|
1708
|
+
skipStoreEmit: true
|
|
1676
1709
|
});
|
|
1710
|
+
emitUpsert(interactiveMsg);
|
|
1711
|
+
return interactiveMsg;
|
|
1677
1712
|
}
|
|
1678
1713
|
case 'ALBUM':
|
|
1679
1714
|
return await interactiveHandler.handleAlbum(content, jid, options.quoted);
|
|
@@ -1801,6 +1836,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1801
1836
|
statusJidList: options.statusJidList,
|
|
1802
1837
|
additionalAttributes: additionalAttributes,
|
|
1803
1838
|
additionalNodes: additionalNodes,
|
|
1839
|
+
skipStoreEmit: true,
|
|
1804
1840
|
});
|
|
1805
1841
|
if (config.emitOwnEvents) {
|
|
1806
1842
|
process.nextTick(async () => {
|
|
@@ -1842,6 +1878,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1842
1878
|
statusJidList: options.statusJidList,
|
|
1843
1879
|
additionalAttributes: additionalAttributes,
|
|
1844
1880
|
additionalNodes: additionalNodes,
|
|
1881
|
+
skipStoreEmit: true,
|
|
1845
1882
|
});
|
|
1846
1883
|
if (config.emitOwnEvents) {
|
|
1847
1884
|
process.nextTick(async () => {
|
|
@@ -736,30 +736,42 @@ export const makePrototypeStore = (config = {}) => {
|
|
|
736
736
|
|
|
737
737
|
listen("messages.upsert", async ({ messages }) => {
|
|
738
738
|
for (let msg of messages) {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
);
|
|
745
|
-
if (!chatId) continue;
|
|
746
|
-
const chat = store.chats[chatId];
|
|
747
|
-
if (!chat) continue;
|
|
748
|
-
if (!chat.messages || typeof chat.messages.upsert !== "function") {
|
|
749
|
-
chat.messages = makeMessagesStore();
|
|
750
|
-
}
|
|
751
|
-
chat.messages.upsert(cloneM(msg));
|
|
752
|
-
|
|
753
|
-
if (db) {
|
|
754
|
-
const msgKey = getMessageKey(
|
|
755
|
-
msg,
|
|
756
|
-
{},
|
|
739
|
+
try {
|
|
740
|
+
const rawChatId = msg?.key?.remoteJid;
|
|
741
|
+
if (!rawChatId) continue;
|
|
742
|
+
const chatId = await resolveJIDAsync(
|
|
743
|
+
rawChatId,
|
|
757
744
|
store.signalRepository?.lidMapping,
|
|
758
745
|
);
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
746
|
+
if (!chatId) continue;
|
|
747
|
+
const chat = store.chats[chatId];
|
|
748
|
+
if (!chat) continue;
|
|
749
|
+
if (!chat.messages || typeof chat.messages.upsert !== "function") {
|
|
750
|
+
chat.messages = makeMessagesStore();
|
|
751
|
+
}
|
|
752
|
+
chat.messages.upsert(cloneM(msg));
|
|
753
|
+
|
|
754
|
+
if (db) {
|
|
755
|
+
const msgKey = getMessageKey(
|
|
756
|
+
msg,
|
|
757
|
+
{},
|
|
758
|
+
store.signalRepository?.lidMapping,
|
|
759
|
+
);
|
|
760
|
+
pendingUpdates.set(`m:${chatId}:${msgKey}`, {
|
|
761
|
+
type: "message",
|
|
762
|
+
data: cloneM(msg),
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
} catch (err) {
|
|
766
|
+
// مهم: من غير try/catch هنا، اي رساله واحده تفشل (JID غريب،
|
|
767
|
+
// مهله lidMapping، اي حاجه) كانت بتوقف اللوب وبتفقد كل الرسايل
|
|
768
|
+
// الباقيه في نفس الـ upsert batch من غير أي خطأ ظاهر.
|
|
769
|
+
console.error(
|
|
770
|
+
"PrototypeStore messages.upsert item error (id:",
|
|
771
|
+
msg?.key?.id,
|
|
772
|
+
"):",
|
|
773
|
+
err?.message || err,
|
|
774
|
+
);
|
|
763
775
|
}
|
|
764
776
|
}
|
|
765
777
|
});
|