@fer2809fl/baileys 7.0.2 → 7.0.4
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 +100 -20
- package/lib/Defaults/index.js +2 -1
- package/lib/Signal/libsignal.js +19 -0
- package/lib/Socket/business.d.ts +213 -532
- package/lib/Socket/business.js +359 -401
- package/lib/Socket/chats.d.ts +16 -2
- package/lib/Socket/chats.js +247 -40
- package/lib/Socket/groups.d.ts +16 -0
- package/lib/Socket/groups.js +101 -18
- package/lib/Socket/messages-recv.js +18 -1
- package/lib/Socket/newsletter.js +3 -3
- package/lib/Socket/socket.js +50 -6
- package/lib/Types/Newsletter.d.ts +13 -4
- package/lib/Types/Newsletter.js +12 -2
- package/lib/Utils/chat-utils.d.ts +34 -4
- package/lib/Utils/chat-utils.js +80 -20
- package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/event-buffer.js +49 -1
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/message-retry-manager.js +40 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/index.js +1 -0
- package/lib/WAUSync/USyncQuery.js +5 -1
- package/package.json +6 -6
- package/lib/Defaults/index.d.ts.map +0 -1
- package/lib/Defaults/index.js.map +0 -1
- package/lib/Signal/Group/ciphertext-message.d.ts.map +0 -1
- package/lib/Signal/Group/ciphertext-message.js.map +0 -1
- package/lib/Signal/Group/group-session-builder.d.ts.map +0 -1
- package/lib/Signal/Group/group-session-builder.js.map +0 -1
- package/lib/Signal/Group/group_cipher.d.ts.map +0 -1
- package/lib/Signal/Group/group_cipher.js.map +0 -1
- package/lib/Signal/Group/index.d.ts.map +0 -1
- package/lib/Signal/Group/index.js.map +0 -1
- package/lib/Signal/Group/keyhelper.d.ts.map +0 -1
- package/lib/Signal/Group/keyhelper.js.map +0 -1
- package/lib/Signal/Group/sender-chain-key.d.ts.map +0 -1
- package/lib/Signal/Group/sender-chain-key.js.map +0 -1
- package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-distribution-message.js.map +0 -1
- package/lib/Signal/Group/sender-key-message.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-message.js.map +0 -1
- package/lib/Signal/Group/sender-key-name.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-name.js.map +0 -1
- package/lib/Signal/Group/sender-key-record.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-record.js.map +0 -1
- package/lib/Signal/Group/sender-key-state.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-state.js.map +0 -1
- package/lib/Signal/Group/sender-message-key.d.ts.map +0 -1
- package/lib/Signal/Group/sender-message-key.js.map +0 -1
- package/lib/Signal/libsignal.d.ts.map +0 -1
- package/lib/Signal/libsignal.js.map +0 -1
- package/lib/Signal/lid-mapping.d.ts.map +0 -1
- package/lib/Signal/lid-mapping.js.map +0 -1
- package/lib/Socket/Client/index.d.ts.map +0 -1
- package/lib/Socket/Client/index.js.map +0 -1
- package/lib/Socket/Client/types.d.ts.map +0 -1
- package/lib/Socket/Client/types.js.map +0 -1
- package/lib/Socket/Client/websocket.d.ts.map +0 -1
- package/lib/Socket/Client/websocket.js.map +0 -1
- package/lib/Socket/business.d.ts.map +0 -1
- package/lib/Socket/business.js.map +0 -1
- package/lib/Socket/chats.d.ts.map +0 -1
- package/lib/Socket/chats.js.map +0 -1
- package/lib/Socket/communities.d.ts.map +0 -1
- package/lib/Socket/communities.js.map +0 -1
- package/lib/Socket/dugong.d.ts.map +0 -1
- package/lib/Socket/dugong.js.map +0 -1
- package/lib/Socket/groups.d.ts.map +0 -1
- package/lib/Socket/groups.js.map +0 -1
- package/lib/Socket/index.d.ts.map +0 -1
- package/lib/Socket/index.js.map +0 -1
- package/lib/Socket/messages-recv.d.ts.map +0 -1
- package/lib/Socket/messages-recv.js.map +0 -1
- package/lib/Socket/messages-send.d.ts.map +0 -1
- package/lib/Socket/messages-send.js.map +0 -1
- package/lib/Socket/mex.d.ts.map +0 -1
- package/lib/Socket/mex.js.map +0 -1
- package/lib/Socket/newsletter.d.ts.map +0 -1
- package/lib/Socket/newsletter.js.map +0 -1
- package/lib/Socket/socket.d.ts.map +0 -1
- package/lib/Socket/socket.js.map +0 -1
- package/lib/Types/Auth.d.ts.map +0 -1
- package/lib/Types/Auth.js.map +0 -1
- package/lib/Types/Bussines.d.ts.map +0 -1
- package/lib/Types/Bussines.js.map +0 -1
- package/lib/Types/Call.d.ts.map +0 -1
- package/lib/Types/Call.js.map +0 -1
- package/lib/Types/Chat.d.ts.map +0 -1
- package/lib/Types/Chat.js.map +0 -1
- package/lib/Types/Contact.d.ts.map +0 -1
- package/lib/Types/Contact.js.map +0 -1
- package/lib/Types/Events.d.ts.map +0 -1
- package/lib/Types/Events.js.map +0 -1
- package/lib/Types/GroupMetadata.d.ts.map +0 -1
- package/lib/Types/GroupMetadata.js.map +0 -1
- package/lib/Types/Label.d.ts.map +0 -1
- package/lib/Types/Label.js.map +0 -1
- package/lib/Types/LabelAssociation.d.ts.map +0 -1
- package/lib/Types/LabelAssociation.js.map +0 -1
- package/lib/Types/Message.d.ts.map +0 -1
- package/lib/Types/Message.js.map +0 -1
- package/lib/Types/Newsletter.d.ts.map +0 -1
- package/lib/Types/Newsletter.js.map +0 -1
- package/lib/Types/Product.d.ts.map +0 -1
- package/lib/Types/Product.js.map +0 -1
- package/lib/Types/Signal.d.ts.map +0 -1
- package/lib/Types/Signal.js.map +0 -1
- package/lib/Types/Socket.d.ts.map +0 -1
- package/lib/Types/Socket.js.map +0 -1
- package/lib/Types/State.d.ts.map +0 -1
- package/lib/Types/State.js.map +0 -1
- package/lib/Types/USync.d.ts.map +0 -1
- package/lib/Types/USync.js.map +0 -1
- package/lib/Types/index.d.ts.map +0 -1
- package/lib/Types/index.js.map +0 -1
- package/lib/Utils/auth-utils.d.ts.map +0 -1
- package/lib/Utils/auth-utils.js.map +0 -1
- package/lib/Utils/browser-utils.d.ts.map +0 -1
- package/lib/Utils/browser-utils.js.map +0 -1
- package/lib/Utils/business.d.ts.map +0 -1
- package/lib/Utils/business.js.map +0 -1
- package/lib/Utils/chat-utils.d.ts.map +0 -1
- package/lib/Utils/chat-utils.js.map +0 -1
- package/lib/Utils/crypto.d.ts.map +0 -1
- package/lib/Utils/crypto.js.map +0 -1
- package/lib/Utils/decode-wa-message.d.ts.map +0 -1
- package/lib/Utils/decode-wa-message.js.map +0 -1
- package/lib/Utils/event-buffer.d.ts.map +0 -1
- package/lib/Utils/event-buffer.js.map +0 -1
- package/lib/Utils/generics.d.ts.map +0 -1
- package/lib/Utils/generics.js.map +0 -1
- package/lib/Utils/history.d.ts.map +0 -1
- package/lib/Utils/history.js.map +0 -1
- package/lib/Utils/identity-change-handler.d.ts.map +0 -1
- package/lib/Utils/identity-change-handler.js.map +0 -1
- package/lib/Utils/index.d.ts.map +0 -1
- package/lib/Utils/index.js.map +0 -1
- package/lib/Utils/link-preview.d.ts.map +0 -1
- package/lib/Utils/link-preview.js.map +0 -1
- package/lib/Utils/logger.d.ts.map +0 -1
- package/lib/Utils/logger.js.map +0 -1
- package/lib/Utils/lt-hash.d.ts.map +0 -1
- package/lib/Utils/lt-hash.js.map +0 -1
- package/lib/Utils/make-mutex.d.ts.map +0 -1
- package/lib/Utils/make-mutex.js.map +0 -1
- package/lib/Utils/message-retry-manager.d.ts.map +0 -1
- package/lib/Utils/message-retry-manager.js.map +0 -1
- package/lib/Utils/messages-media.d.ts.map +0 -1
- package/lib/Utils/messages-media.js.map +0 -1
- package/lib/Utils/messages.d.ts.map +0 -1
- package/lib/Utils/messages.js.map +0 -1
- package/lib/Utils/noise-handler.d.ts.map +0 -1
- package/lib/Utils/noise-handler.js.map +0 -1
- package/lib/Utils/offline-node-processor.d.ts.map +0 -1
- package/lib/Utils/offline-node-processor.js.map +0 -1
- package/lib/Utils/pre-key-manager.d.ts.map +0 -1
- package/lib/Utils/pre-key-manager.js.map +0 -1
- package/lib/Utils/process-message.d.ts.map +0 -1
- package/lib/Utils/process-message.js.map +0 -1
- package/lib/Utils/reporting-utils.d.ts.map +0 -1
- package/lib/Utils/reporting-utils.js.map +0 -1
- package/lib/Utils/rich-messages.d.ts.map +0 -1
- package/lib/Utils/rich-messages.js.map +0 -1
- package/lib/Utils/signal.d.ts.map +0 -1
- package/lib/Utils/signal.js.map +0 -1
- package/lib/Utils/stanza-ack.d.ts.map +0 -1
- package/lib/Utils/stanza-ack.js.map +0 -1
- package/lib/Utils/sync-action-utils.d.ts.map +0 -1
- package/lib/Utils/sync-action-utils.js.map +0 -1
- package/lib/Utils/tc-token-utils.d.ts.map +0 -1
- package/lib/Utils/tc-token-utils.js.map +0 -1
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +0 -1
- package/lib/Utils/use-multi-file-auth-state.js.map +0 -1
- package/lib/Utils/validate-connection.d.ts.map +0 -1
- package/lib/Utils/validate-connection.js.map +0 -1
- package/lib/WABinary/constants.d.ts.map +0 -1
- package/lib/WABinary/constants.js.map +0 -1
- package/lib/WABinary/decode.d.ts.map +0 -1
- package/lib/WABinary/decode.js.map +0 -1
- package/lib/WABinary/encode.d.ts.map +0 -1
- package/lib/WABinary/encode.js.map +0 -1
- package/lib/WABinary/generic-utils.d.ts.map +0 -1
- package/lib/WABinary/generic-utils.js.map +0 -1
- package/lib/WABinary/index.d.ts.map +0 -1
- package/lib/WABinary/index.js.map +0 -1
- package/lib/WABinary/jid-utils.d.ts.map +0 -1
- package/lib/WABinary/jid-utils.js.map +0 -1
- package/lib/WABinary/types.d.ts.map +0 -1
- package/lib/WABinary/types.js.map +0 -1
- package/lib/WAM/BinaryInfo.d.ts.map +0 -1
- package/lib/WAM/BinaryInfo.js.map +0 -1
- package/lib/WAM/constants.d.ts.map +0 -1
- package/lib/WAM/constants.js.map +0 -1
- package/lib/WAM/encode.d.ts.map +0 -1
- package/lib/WAM/encode.js.map +0 -1
- package/lib/WAM/index.d.ts.map +0 -1
- package/lib/WAM/index.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/index.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/index.js.map +0 -1
- package/lib/WAUSync/USyncQuery.d.ts.map +0 -1
- package/lib/WAUSync/USyncQuery.js.map +0 -1
- package/lib/WAUSync/USyncUser.d.ts.map +0 -1
- package/lib/WAUSync/USyncUser.js.map +0 -1
- package/lib/WAUSync/index.d.ts.map +0 -1
- package/lib/WAUSync/index.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
package/lib/Socket/chats.d.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { Boom } from '@hapi/boom';
|
|
2
2
|
import { proto } from '../../WAProto/index.js';
|
|
3
|
-
import type { BotListInfo, ChatModification, MessageUpsertType, SocketConfig, WABusinessProfile, WAMediaUpload, WAMessage, WAPatchCreate, WAPresence, WAPrivacyCallValue, WAPrivacyGroupAddValue, WAPrivacyMessagesValue, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '../Types/index.js';
|
|
3
|
+
import type { BotListInfo, CacheStore, ChatModification, MessageUpsertType, SocketConfig, WABusinessProfile, WAMediaUpload, WAMessage, WAPatchCreate, WAPresence, WAPrivacyCallValue, WAPrivacyGroupAddValue, WAPrivacyMessagesValue, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '../Types/index.js';
|
|
4
4
|
import type { QuickReplyAction } from '../Types/Bussines.js';
|
|
5
5
|
import type { LabelActionBody } from '../Types/Label.js';
|
|
6
6
|
import { type BinaryNode } from '../WABinary/index.js';
|
|
7
7
|
import { USyncQuery } from '../WAUSync/index.js';
|
|
8
|
+
export declare const buildProfilePictureQueryContent: (type: "preview" | "image", tcTokenContent?: BinaryNode[]) => BinaryNode[];
|
|
8
9
|
export declare const makeChatsSocket: (config: SocketConfig) => {
|
|
10
|
+
serverProps: {
|
|
11
|
+
/** AB prop 10518: gate tctoken on 1:1 messages. Default true (safe: avoids 463). */
|
|
12
|
+
privacyTokenOn1to1: boolean;
|
|
13
|
+
/** AB prop 9666: gate tctoken on profile picture IQs. WA Web default: true. */
|
|
14
|
+
profilePicPrivacyToken: boolean;
|
|
15
|
+
/** AB prop 14303: issue tctokens to LID instead of PN. WA Web default: false. */
|
|
16
|
+
lidTrustedTokenIssueToLid: boolean;
|
|
17
|
+
};
|
|
9
18
|
createCallLink: (type: "audio" | "video", event?: {
|
|
10
19
|
startTime: number;
|
|
11
20
|
}, timeoutMs?: number) => Promise<string | undefined>;
|
|
@@ -57,6 +66,7 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
|
|
|
57
66
|
cleanDirtyBits: (type: "account_sync" | "groups", fromTimestamp?: number | string) => Promise<void>;
|
|
58
67
|
addOrEditContact: (jid: string, contact: proto.SyncActionValue.IContactAction) => Promise<void>;
|
|
59
68
|
removeContact: (jid: string) => Promise<void>;
|
|
69
|
+
placeholderResendCache: CacheStore;
|
|
60
70
|
addLabel: (jid: string, labels: LabelActionBody) => Promise<void>;
|
|
61
71
|
addChatLabel: (jid: string, labelId: string) => Promise<void>;
|
|
62
72
|
removeChatLabel: (jid: string, labelId: string) => Promise<void>;
|
|
@@ -76,6 +86,7 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
|
|
|
76
86
|
createBufferedFunction<A extends any[], T>(work: (...args: A) => Promise<T>): (...args: A) => Promise<T>;
|
|
77
87
|
flush(): boolean;
|
|
78
88
|
isBuffering(): boolean;
|
|
89
|
+
destroy(): void;
|
|
79
90
|
};
|
|
80
91
|
authState: {
|
|
81
92
|
creds: import("../Types/index.js").AuthenticationCreds;
|
|
@@ -91,8 +102,9 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
|
|
|
91
102
|
sendNode: (frame: BinaryNode) => Promise<void>;
|
|
92
103
|
logout: (msg?: string) => Promise<void>;
|
|
93
104
|
end: (error: Error | undefined) => Promise<void>;
|
|
105
|
+
registerSocketEndHandler: (handler: (error: Error | undefined) => void | Promise<void>) => void;
|
|
94
106
|
onUnexpectedError: (err: Error | Boom, msg: string) => void;
|
|
95
|
-
uploadPreKeys: (count?: number
|
|
107
|
+
uploadPreKeys: (count?: number) => Promise<void>;
|
|
96
108
|
uploadPreKeysToServerIfRequired: () => Promise<void>;
|
|
97
109
|
digestKeyBundle: () => Promise<void>;
|
|
98
110
|
rotateSignedPreKey: () => Promise<void>;
|
|
@@ -107,5 +119,7 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
|
|
|
107
119
|
jid: string;
|
|
108
120
|
exists: boolean;
|
|
109
121
|
}[] | undefined>;
|
|
122
|
+
fetchAccountReachoutTimelock: () => Promise<import("../Types/index.js").ReachoutTimelockState>;
|
|
123
|
+
fetchNewChatMessageCap: () => Promise<import("../Types/index.js").NewChatMessageCapInfo>;
|
|
110
124
|
};
|
|
111
125
|
//# sourceMappingURL=chats.d.ts.map
|
package/lib/Socket/chats.js
CHANGED
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
import NodeCache from '@cacheable/node-cache';
|
|
2
2
|
import { Boom } from '@hapi/boom';
|
|
3
3
|
import { proto } from '../../WAProto/index.js';
|
|
4
|
-
import { DEFAULT_CACHE_TTLS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js';
|
|
4
|
+
import { DEFAULT_CACHE_TTLS, HISTORY_SYNC_PAUSED_TIMEOUT_MS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js';
|
|
5
5
|
import { ALL_WA_PATCH_NAMES } from '../Types/index.js';
|
|
6
6
|
import { SyncState } from '../Types/State.js';
|
|
7
|
-
import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, extractSyncdPatches, generateProfilePicture, getHistoryMsg, newLTHashState, processSyncAction } from '../Utils/index.js';
|
|
7
|
+
import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, ensureLTHashStateVersion, extractSyncdPatches, generateProfilePicture, getHistoryMsg, isAppStateSyncIrrecoverable, isMissingKeyError, MAX_SYNC_ATTEMPTS, newLTHashState, processSyncAction } from '../Utils/index.js';
|
|
8
8
|
import { makeMutex } from '../Utils/make-mutex.js';
|
|
9
9
|
import processMessage from '../Utils/process-message.js';
|
|
10
10
|
import { buildTcTokenFromJid } from '../Utils/tc-token-utils.js';
|
|
11
|
-
import { getBinaryNodeChild, getBinaryNodeChildren, jidDecode, jidNormalizedUser, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
11
|
+
import { getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isLidUser, isPnUser, jidDecode, jidNormalizedUser, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
12
12
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
13
13
|
import { makeSocket } from './socket.js';
|
|
14
|
-
const
|
|
14
|
+
export const buildProfilePictureQueryContent = (type, tcTokenContent) => {
|
|
15
|
+
const picture = { tag: 'picture', attrs: { type, query: 'url' } };
|
|
16
|
+
if (tcTokenContent?.length) {
|
|
17
|
+
picture.content = tcTokenContent;
|
|
18
|
+
}
|
|
19
|
+
return [picture];
|
|
20
|
+
};
|
|
15
21
|
export const makeChatsSocket = (config) => {
|
|
16
22
|
const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, getMessage } = config;
|
|
17
23
|
const sock = makeSocket(config);
|
|
18
|
-
const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession } = sock;
|
|
24
|
+
const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession, registerSocketEndHandler } = sock;
|
|
25
|
+
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
|
|
19
26
|
let privacySettings;
|
|
27
|
+
/** Server-assigned AB props for protocol behavior. */
|
|
28
|
+
const serverProps = {
|
|
29
|
+
/** AB prop 10518: gate tctoken on 1:1 messages. Default true (safe: avoids 463). */
|
|
30
|
+
privacyTokenOn1to1: true,
|
|
31
|
+
/** AB prop 9666: gate tctoken on profile picture IQs. WA Web default: true. */
|
|
32
|
+
profilePicPrivacyToken: true,
|
|
33
|
+
/** AB prop 14303: issue tctokens to LID instead of PN. WA Web default: false. */
|
|
34
|
+
lidTrustedTokenIssueToLid: false
|
|
35
|
+
};
|
|
20
36
|
let syncState = SyncState.Connecting;
|
|
21
37
|
/** this mutex ensures that messages are processed in order */
|
|
22
38
|
const messageMutex = makeMutex();
|
|
@@ -28,14 +44,20 @@ export const makeChatsSocket = (config) => {
|
|
|
28
44
|
const notificationMutex = makeMutex();
|
|
29
45
|
// Timeout for AwaitingInitialSync state
|
|
30
46
|
let awaitingSyncTimeout;
|
|
47
|
+
// In-memory history sync completion tracking (resets on reconnection)
|
|
48
|
+
const historySyncStatus = {
|
|
49
|
+
initialBootstrapComplete: false,
|
|
50
|
+
recentSyncComplete: false
|
|
51
|
+
};
|
|
52
|
+
let historySyncPausedTimeout;
|
|
53
|
+
// Collections blocked on missing app state sync keys (mirrors WA Web's "Blocked" state).
|
|
54
|
+
// When a key arrives via APP_STATE_SYNC_KEY_SHARE, these are re-synced.
|
|
55
|
+
const blockedCollections = new Set();
|
|
31
56
|
const placeholderResendCache = config.placeholderResendCache ||
|
|
32
57
|
new NodeCache({
|
|
33
58
|
stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
34
59
|
useClones: false
|
|
35
60
|
});
|
|
36
|
-
if (!config.placeholderResendCache) {
|
|
37
|
-
config.placeholderResendCache = placeholderResendCache;
|
|
38
|
-
}
|
|
39
61
|
/** helper function to fetch the given app state sync key */
|
|
40
62
|
const getAppStateSyncKey = async (keyId) => {
|
|
41
63
|
const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId]);
|
|
@@ -258,6 +280,42 @@ export const makeChatsSocket = (config) => {
|
|
|
258
280
|
return getBinaryNodeChildren(listNode, 'item').map(n => n.attrs.jid);
|
|
259
281
|
};
|
|
260
282
|
const updateBlockStatus = async (jid, action) => {
|
|
283
|
+
const normalizedJid = jidNormalizedUser(jid);
|
|
284
|
+
let lid;
|
|
285
|
+
let pn_jid;
|
|
286
|
+
if (isLidUser(normalizedJid) || isHostedLidUser(normalizedJid)) {
|
|
287
|
+
lid = normalizedJid;
|
|
288
|
+
if (action === 'block') {
|
|
289
|
+
const pn = await signalRepository.lidMapping.getPNForLID(normalizedJid);
|
|
290
|
+
if (!pn) {
|
|
291
|
+
throw new Boom(`Unable to resolve PN JID for LID: ${jid}`, { statusCode: 400 });
|
|
292
|
+
}
|
|
293
|
+
pn_jid = jidNormalizedUser(pn);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else if (isPnUser(normalizedJid) || isHostedPnUser(normalizedJid)) {
|
|
297
|
+
const mapped = await signalRepository.lidMapping.getLIDForPN(normalizedJid);
|
|
298
|
+
if (!mapped) {
|
|
299
|
+
throw new Boom(`Unable to resolve LID for PN JID: ${jid}`, { statusCode: 400 });
|
|
300
|
+
}
|
|
301
|
+
lid = mapped;
|
|
302
|
+
if (action === 'block') {
|
|
303
|
+
pn_jid = jidNormalizedUser(normalizedJid);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
throw new Boom(`Invalid jid: ${jid}`, { statusCode: 400 });
|
|
308
|
+
}
|
|
309
|
+
const itemAttrs = {
|
|
310
|
+
action,
|
|
311
|
+
jid: lid
|
|
312
|
+
};
|
|
313
|
+
if (action === 'block') {
|
|
314
|
+
if (!pn_jid) {
|
|
315
|
+
throw new Boom(`pn_jid required for block: ${jid}`, { statusCode: 400 });
|
|
316
|
+
}
|
|
317
|
+
itemAttrs.pn_jid = pn_jid;
|
|
318
|
+
}
|
|
261
319
|
await query({
|
|
262
320
|
tag: 'iq',
|
|
263
321
|
attrs: {
|
|
@@ -268,10 +326,7 @@ export const makeChatsSocket = (config) => {
|
|
|
268
326
|
content: [
|
|
269
327
|
{
|
|
270
328
|
tag: 'item',
|
|
271
|
-
attrs:
|
|
272
|
-
action,
|
|
273
|
-
jid
|
|
274
|
-
}
|
|
329
|
+
attrs: itemAttrs
|
|
275
330
|
}
|
|
276
331
|
]
|
|
277
332
|
});
|
|
@@ -370,6 +425,9 @@ export const makeChatsSocket = (config) => {
|
|
|
370
425
|
const collectionsToHandle = new Set(collections);
|
|
371
426
|
// in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
|
|
372
427
|
const attemptsMap = {};
|
|
428
|
+
// collections that failed and need a full snapshot on retry
|
|
429
|
+
// mirrors WA Web's ErrorFatal -> force snapshot behavior
|
|
430
|
+
const forceSnapshotCollections = new Set();
|
|
373
431
|
// keep executing till all collections are done
|
|
374
432
|
// sometimes a single patch request will not return all the patches (God knows why)
|
|
375
433
|
// so we fetch till they're all done (this is determined by the "has_more_patches" flag)
|
|
@@ -380,6 +438,7 @@ export const makeChatsSocket = (config) => {
|
|
|
380
438
|
const result = await authState.keys.get('app-state-sync-version', [name]);
|
|
381
439
|
let state = result[name];
|
|
382
440
|
if (state) {
|
|
441
|
+
state = ensureLTHashStateVersion(state);
|
|
383
442
|
if (typeof initialVersionMap[name] === 'undefined') {
|
|
384
443
|
initialVersionMap[name] = state.version;
|
|
385
444
|
}
|
|
@@ -388,14 +447,18 @@ export const makeChatsSocket = (config) => {
|
|
|
388
447
|
state = newLTHashState();
|
|
389
448
|
}
|
|
390
449
|
states[name] = state;
|
|
391
|
-
|
|
450
|
+
const shouldForceSnapshot = forceSnapshotCollections.has(name);
|
|
451
|
+
if (shouldForceSnapshot) {
|
|
452
|
+
forceSnapshotCollections.delete(name);
|
|
453
|
+
}
|
|
454
|
+
logger.info(`resyncing ${name} from v${state.version}${shouldForceSnapshot ? ' (forcing snapshot)' : ''}`);
|
|
392
455
|
nodes.push({
|
|
393
456
|
tag: 'collection',
|
|
394
457
|
attrs: {
|
|
395
458
|
name,
|
|
396
459
|
version: state.version.toString(),
|
|
397
|
-
// return snapshot if
|
|
398
|
-
return_snapshot: (!state.version).toString()
|
|
460
|
+
// return snapshot if syncing from scratch or forcing after a failed attempt
|
|
461
|
+
return_snapshot: (shouldForceSnapshot || !state.version).toString()
|
|
399
462
|
}
|
|
400
463
|
});
|
|
401
464
|
}
|
|
@@ -421,7 +484,7 @@ export const makeChatsSocket = (config) => {
|
|
|
421
484
|
const { patches, hasMorePatches, snapshot } = decoded[name];
|
|
422
485
|
try {
|
|
423
486
|
if (snapshot) {
|
|
424
|
-
const { state: newState, mutationMap } = await decodeSyncdSnapshot(name, snapshot, getCachedAppStateSyncKey, initialVersionMap[name], appStateMacVerification.snapshot);
|
|
487
|
+
const { state: newState, mutationMap } = await decodeSyncdSnapshot(name, snapshot, getCachedAppStateSyncKey, initialVersionMap[name], appStateMacVerification.snapshot, logger);
|
|
425
488
|
states[name] = newState;
|
|
426
489
|
Object.assign(globalMutationMap, mutationMap);
|
|
427
490
|
logger.info(`restored state of ${name} from snapshot to v${newState.version} with mutations`);
|
|
@@ -444,19 +507,37 @@ export const makeChatsSocket = (config) => {
|
|
|
444
507
|
}
|
|
445
508
|
}
|
|
446
509
|
catch (error) {
|
|
447
|
-
// if retry attempts overshoot
|
|
448
|
-
// or key not found
|
|
449
|
-
const isIrrecoverableError = attemptsMap[name] >= MAX_SYNC_ATTEMPTS ||
|
|
450
|
-
error.output?.statusCode === 404 ||
|
|
451
|
-
error.name === 'TypeError';
|
|
452
|
-
logger.info({ name, error: error.stack }, `failed to sync state from version${isIrrecoverableError ? '' : ', removing and trying from scratch'}`);
|
|
453
|
-
await authState.keys.set({ 'app-state-sync-version': { [name]: null } });
|
|
454
|
-
// increment number of retries
|
|
455
510
|
attemptsMap[name] = (attemptsMap[name] || 0) + 1;
|
|
456
|
-
|
|
457
|
-
|
|
511
|
+
const logData = {
|
|
512
|
+
name,
|
|
513
|
+
attempt: attemptsMap[name],
|
|
514
|
+
version: states[name].version,
|
|
515
|
+
statusCode: error.output?.statusCode,
|
|
516
|
+
errorType: error.name,
|
|
517
|
+
error: error.stack
|
|
518
|
+
};
|
|
519
|
+
if (isMissingKeyError(error) && attemptsMap[name] >= MAX_SYNC_ATTEMPTS) {
|
|
520
|
+
// WA Web treats missing keys as "Blocked" — park the collection
|
|
521
|
+
// until the key arrives via APP_STATE_SYNC_KEY_SHARE.
|
|
522
|
+
logger.warn(logData, `${name} blocked on missing key from v${states[name].version}, parking after ${attemptsMap[name]} attempts`);
|
|
523
|
+
blockedCollections.add(name);
|
|
524
|
+
collectionsToHandle.delete(name);
|
|
525
|
+
}
|
|
526
|
+
else if (isMissingKeyError(error)) {
|
|
527
|
+
// Retry with a snapshot which may use a different key.
|
|
528
|
+
logger.info(logData, `${name} blocked on missing key from v${states[name].version}, retrying with snapshot`);
|
|
529
|
+
forceSnapshotCollections.add(name);
|
|
530
|
+
}
|
|
531
|
+
else if (isAppStateSyncIrrecoverable(error, attemptsMap[name])) {
|
|
532
|
+
logger.warn(logData, `failed to sync ${name} from v${states[name].version}, giving up`);
|
|
458
533
|
collectionsToHandle.delete(name);
|
|
459
534
|
}
|
|
535
|
+
else {
|
|
536
|
+
logger.info(logData, `failed to sync ${name} from v${states[name].version}, forcing snapshot retry`);
|
|
537
|
+
// force a full snapshot on retry to recover from
|
|
538
|
+
// corrupted local state (e.g. LTHash MAC mismatch)
|
|
539
|
+
forceSnapshotCollections.add(name);
|
|
540
|
+
}
|
|
460
541
|
}
|
|
461
542
|
}
|
|
462
543
|
}
|
|
@@ -472,8 +553,21 @@ export const makeChatsSocket = (config) => {
|
|
|
472
553
|
* type = "image for the high res picture"
|
|
473
554
|
*/
|
|
474
555
|
const profilePictureUrl = async (jid, type = 'preview', timeoutMs) => {
|
|
475
|
-
|
|
476
|
-
|
|
556
|
+
// WA Web only includes tctoken for user JIDs (not groups/newsletters)
|
|
557
|
+
// and never for own profile pic (Chat model for self has no tcToken).
|
|
558
|
+
// Including tctoken for own JID causes the server to never respond.
|
|
559
|
+
const normalizedJid = jidNormalizedUser(jid);
|
|
560
|
+
const isUserJid = isPnUser(normalizedJid) || isLidUser(normalizedJid);
|
|
561
|
+
const me = authState.creds.me;
|
|
562
|
+
const isSelf = me && (normalizedJid === jidNormalizedUser(me.id) || (me.lid && normalizedJid === jidNormalizedUser(me.lid)));
|
|
563
|
+
let tcTokenContent;
|
|
564
|
+
if (serverProps.profilePicPrivacyToken && isUserJid && !isSelf) {
|
|
565
|
+
tcTokenContent = await buildTcTokenFromJid({
|
|
566
|
+
authState,
|
|
567
|
+
jid: normalizedJid,
|
|
568
|
+
getLIDForPN
|
|
569
|
+
});
|
|
570
|
+
}
|
|
477
571
|
jid = jidNormalizedUser(jid);
|
|
478
572
|
const result = await query({
|
|
479
573
|
tag: 'iq',
|
|
@@ -483,7 +577,7 @@ export const makeChatsSocket = (config) => {
|
|
|
483
577
|
type: 'get',
|
|
484
578
|
xmlns: 'w:profile:picture'
|
|
485
579
|
},
|
|
486
|
-
content: tcTokenContent
|
|
580
|
+
content: buildProfilePictureQueryContent(type, tcTokenContent)
|
|
487
581
|
}, timeoutMs);
|
|
488
582
|
const child = getBinaryNodeChild(result, 'picture');
|
|
489
583
|
return child?.attrs?.url;
|
|
@@ -549,7 +643,12 @@ export const makeChatsSocket = (config) => {
|
|
|
549
643
|
* @param tcToken token for subscription, use if present
|
|
550
644
|
*/
|
|
551
645
|
const presenceSubscribe = async (toJid) => {
|
|
552
|
-
|
|
646
|
+
// Only include tctoken for user JIDs — groups/newsletters don't use tctokens
|
|
647
|
+
const normalizedToJid = jidNormalizedUser(toJid);
|
|
648
|
+
const isUserJid = isPnUser(normalizedToJid) || isLidUser(normalizedToJid);
|
|
649
|
+
const tcTokenContent = isUserJid
|
|
650
|
+
? await buildTcTokenFromJid({ authState, jid: normalizedToJid, getLIDForPN })
|
|
651
|
+
: undefined;
|
|
553
652
|
return sendNode({
|
|
554
653
|
tag: 'presence',
|
|
555
654
|
attrs: {
|
|
@@ -570,7 +669,8 @@ export const makeChatsSocket = (config) => {
|
|
|
570
669
|
if (tag === 'presence') {
|
|
571
670
|
presence = {
|
|
572
671
|
lastKnownPresence: attrs.type === 'unavailable' ? 'unavailable' : 'available',
|
|
573
|
-
lastSeen: attrs.last && attrs.last !== 'deny' ? +attrs.last : undefined
|
|
672
|
+
lastSeen: attrs.last && attrs.last !== 'deny' ? +attrs.last : undefined,
|
|
673
|
+
groupOnlineCount: attrs.count ? +attrs.count : undefined
|
|
574
674
|
};
|
|
575
675
|
}
|
|
576
676
|
else if (Array.isArray(content)) {
|
|
@@ -604,7 +704,7 @@ export const makeChatsSocket = (config) => {
|
|
|
604
704
|
logger.debug({ patch: patchCreate }, 'applying app patch');
|
|
605
705
|
await resyncAppState([name], false);
|
|
606
706
|
const { [name]: currentSyncVersion } = await authState.keys.get('app-state-sync-version', [name]);
|
|
607
|
-
initial = currentSyncVersion
|
|
707
|
+
initial = currentSyncVersion ? ensureLTHashStateVersion(currentSyncVersion) : newLTHashState();
|
|
608
708
|
encodeResult = await encodeSyncdPatch(patchCreate, myAppStateKeyId, initial, getAppStateSyncKey);
|
|
609
709
|
const { patch, state } = encodeResult;
|
|
610
710
|
const node = {
|
|
@@ -650,22 +750,21 @@ export const makeChatsSocket = (config) => {
|
|
|
650
750
|
}
|
|
651
751
|
}
|
|
652
752
|
};
|
|
653
|
-
/**
|
|
753
|
+
/** fetch AB props */
|
|
654
754
|
const fetchProps = async () => {
|
|
655
|
-
//TODO: implement both protocol 1 and protocol 2 prop fetching, specially for abKey for WM
|
|
656
755
|
const resultNode = await query({
|
|
657
756
|
tag: 'iq',
|
|
658
757
|
attrs: {
|
|
659
758
|
to: S_WHATSAPP_NET,
|
|
660
|
-
xmlns: '
|
|
759
|
+
xmlns: 'abt',
|
|
661
760
|
type: 'get'
|
|
662
761
|
},
|
|
663
762
|
content: [
|
|
664
763
|
{
|
|
665
764
|
tag: 'props',
|
|
666
765
|
attrs: {
|
|
667
|
-
protocol: '
|
|
668
|
-
hash: authState
|
|
766
|
+
protocol: '1',
|
|
767
|
+
...(authState?.creds?.lastPropHash ? { hash: authState.creds.lastPropHash } : {})
|
|
669
768
|
}
|
|
670
769
|
}
|
|
671
770
|
]
|
|
@@ -680,7 +779,20 @@ export const makeChatsSocket = (config) => {
|
|
|
680
779
|
}
|
|
681
780
|
props = reduceBinaryNodeToDictionary(propsNode, 'prop');
|
|
682
781
|
}
|
|
683
|
-
|
|
782
|
+
// Extract protocol-relevant AB props (only the ones we need)
|
|
783
|
+
const privacyTokenProp = props['10518'] ?? props['privacy_token_sending_on_all_1_on_1_messages'];
|
|
784
|
+
if (privacyTokenProp !== undefined) {
|
|
785
|
+
serverProps.privacyTokenOn1to1 = privacyTokenProp === 'true' || privacyTokenProp === '1';
|
|
786
|
+
}
|
|
787
|
+
const profilePicProp = props['9666'] ?? props['profile_scraping_privacy_token_in_photo_iq'];
|
|
788
|
+
if (profilePicProp !== undefined) {
|
|
789
|
+
serverProps.profilePicPrivacyToken = profilePicProp === 'true' || profilePicProp === '1';
|
|
790
|
+
}
|
|
791
|
+
const lidIssueProp = props['14303'] ?? props['lid_trusted_token_issue_to_lid'];
|
|
792
|
+
if (lidIssueProp !== undefined) {
|
|
793
|
+
serverProps.lidTrustedTokenIssueToLid = lidIssueProp === 'true' || lidIssueProp === '1';
|
|
794
|
+
}
|
|
795
|
+
logger.debug({ serverProps }, 'fetched props');
|
|
684
796
|
return props;
|
|
685
797
|
};
|
|
686
798
|
/**
|
|
@@ -820,6 +932,47 @@ export const makeChatsSocket = (config) => {
|
|
|
820
932
|
? shouldSyncHistoryMessage(historyMsg) &&
|
|
821
933
|
PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)
|
|
822
934
|
: false;
|
|
935
|
+
if (historyMsg && shouldProcessHistoryMsg) {
|
|
936
|
+
const syncType = historyMsg.syncType;
|
|
937
|
+
// INITIAL_BOOTSTRAP — fire immediately, no progress check (same as WA Web K function)
|
|
938
|
+
if (syncType === proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP &&
|
|
939
|
+
!historySyncStatus.initialBootstrapComplete) {
|
|
940
|
+
historySyncStatus.initialBootstrapComplete = true;
|
|
941
|
+
ev.emit('messaging-history.status', {
|
|
942
|
+
syncType,
|
|
943
|
+
status: 'complete',
|
|
944
|
+
explicit: true
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
// RECENT with progress === 100 — explicit completion
|
|
948
|
+
if (syncType === proto.HistorySync.HistorySyncType.RECENT &&
|
|
949
|
+
historyMsg.progress === 100 &&
|
|
950
|
+
!historySyncStatus.recentSyncComplete) {
|
|
951
|
+
historySyncStatus.recentSyncComplete = true;
|
|
952
|
+
clearTimeout(historySyncPausedTimeout);
|
|
953
|
+
historySyncPausedTimeout = undefined;
|
|
954
|
+
ev.emit('messaging-history.status', {
|
|
955
|
+
syncType,
|
|
956
|
+
status: 'complete',
|
|
957
|
+
explicit: true
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
// Reset 120s paused timeout on any RECENT chunk (like WA Web's handleChunkProgress)
|
|
961
|
+
if (syncType === proto.HistorySync.HistorySyncType.RECENT && !historySyncStatus.recentSyncComplete) {
|
|
962
|
+
clearTimeout(historySyncPausedTimeout);
|
|
963
|
+
historySyncPausedTimeout = setTimeout(() => {
|
|
964
|
+
if (!historySyncStatus.recentSyncComplete) {
|
|
965
|
+
historySyncStatus.recentSyncComplete = true;
|
|
966
|
+
ev.emit('messaging-history.status', {
|
|
967
|
+
syncType: proto.HistorySync.HistorySyncType.RECENT,
|
|
968
|
+
status: 'paused',
|
|
969
|
+
explicit: false
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
historySyncPausedTimeout = undefined;
|
|
973
|
+
}, HISTORY_SYNC_PAUSED_TIMEOUT_MS);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
823
976
|
// State machine: decide on sync and flush
|
|
824
977
|
if (historyMsg && syncState === SyncState.AwaitingInitialSync) {
|
|
825
978
|
if (awaitingSyncTimeout) {
|
|
@@ -839,6 +992,8 @@ export const makeChatsSocket = (config) => {
|
|
|
839
992
|
}
|
|
840
993
|
const doAppStateSync = async () => {
|
|
841
994
|
if (syncState === SyncState.Syncing) {
|
|
995
|
+
// All collections will be synced, so clear any blocked ones
|
|
996
|
+
blockedCollections.clear();
|
|
842
997
|
logger.info('Doing app state sync');
|
|
843
998
|
await resyncAppState(ALL_WA_PATCH_NAMES, true);
|
|
844
999
|
// Sync is complete, go online and flush everything
|
|
@@ -898,6 +1053,11 @@ export const makeChatsSocket = (config) => {
|
|
|
898
1053
|
}
|
|
899
1054
|
});
|
|
900
1055
|
ev.on('connection.update', ({ connection, receivedPendingNotifications }) => {
|
|
1056
|
+
if (connection === 'close') {
|
|
1057
|
+
blockedCollections.clear();
|
|
1058
|
+
clearTimeout(historySyncPausedTimeout);
|
|
1059
|
+
historySyncPausedTimeout = undefined;
|
|
1060
|
+
}
|
|
901
1061
|
if (connection === 'open') {
|
|
902
1062
|
if (fireInitQueries) {
|
|
903
1063
|
executeInitQueries().catch(error => onUnexpectedError(error, 'init queries'));
|
|
@@ -907,6 +1067,10 @@ export const makeChatsSocket = (config) => {
|
|
|
907
1067
|
if (!receivedPendingNotifications || syncState !== SyncState.Connecting) {
|
|
908
1068
|
return;
|
|
909
1069
|
}
|
|
1070
|
+
historySyncStatus.initialBootstrapComplete = false;
|
|
1071
|
+
historySyncStatus.recentSyncComplete = false;
|
|
1072
|
+
clearTimeout(historySyncPausedTimeout);
|
|
1073
|
+
historySyncPausedTimeout = undefined;
|
|
910
1074
|
syncState = SyncState.AwaitingInitialSync;
|
|
911
1075
|
logger.info('Connection is now AwaitingInitialSync, buffering events');
|
|
912
1076
|
ev.buffer();
|
|
@@ -919,19 +1083,49 @@ export const makeChatsSocket = (config) => {
|
|
|
919
1083
|
setTimeout(() => ev.flush(), 0);
|
|
920
1084
|
return;
|
|
921
1085
|
}
|
|
922
|
-
|
|
1086
|
+
// On reconnection (accountSyncCounter > 0), the server does not push
|
|
1087
|
+
// history sync notifications — the device already has its data.
|
|
1088
|
+
// Skip the 20s wait and go online immediately.
|
|
1089
|
+
if (authState.creds.accountSyncCounter > 0) {
|
|
1090
|
+
logger.info('Reconnection with existing sync data, skipping history sync wait. Transitioning to Online.');
|
|
1091
|
+
syncState = SyncState.Online;
|
|
1092
|
+
setTimeout(() => ev.flush(), 0);
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
logger.info('First connection, awaiting history sync notification with a 20s timeout.');
|
|
923
1096
|
if (awaitingSyncTimeout) {
|
|
924
1097
|
clearTimeout(awaitingSyncTimeout);
|
|
925
1098
|
}
|
|
926
1099
|
awaitingSyncTimeout = setTimeout(() => {
|
|
927
1100
|
if (syncState === SyncState.AwaitingInitialSync) {
|
|
928
|
-
// TODO: investigate
|
|
929
1101
|
logger.warn('Timeout in AwaitingInitialSync, forcing state to Online and flushing buffer');
|
|
930
1102
|
syncState = SyncState.Online;
|
|
931
1103
|
ev.flush();
|
|
1104
|
+
// Increment so subsequent reconnections skip the 20s wait.
|
|
1105
|
+
// Late-arriving history is still processed via processMessage
|
|
1106
|
+
// regardless of the state machine phase.
|
|
1107
|
+
const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
|
|
1108
|
+
ev.emit('creds.update', { accountSyncCounter });
|
|
932
1109
|
}
|
|
933
1110
|
}, 20000);
|
|
934
1111
|
});
|
|
1112
|
+
// When an app state sync key arrives (myAppStateKeyId is set) and there are
|
|
1113
|
+
// collections blocked on a missing key, trigger a re-sync for just those collections.
|
|
1114
|
+
// This mirrors WA Web's Blocked → retry-on-key-arrival behavior.
|
|
1115
|
+
ev.on('creds.update', ({ myAppStateKeyId }) => {
|
|
1116
|
+
if (!myAppStateKeyId || blockedCollections.size === 0) {
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
// If we're in the middle of a full sync, doAppStateSync handles all collections
|
|
1120
|
+
if (syncState === SyncState.Syncing) {
|
|
1121
|
+
blockedCollections.clear();
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
const collections = [...blockedCollections];
|
|
1125
|
+
blockedCollections.clear();
|
|
1126
|
+
logger.info({ collections }, 'app state sync key arrived, re-syncing blocked collections');
|
|
1127
|
+
resyncAppState(collections, false).catch(error => onUnexpectedError(error, 'blocked collections resync'));
|
|
1128
|
+
});
|
|
935
1129
|
ev.on('lid-mapping.update', async ({ lid, pn }) => {
|
|
936
1130
|
try {
|
|
937
1131
|
await signalRepository.lidMapping.storeLIDPNMappings([{ lid, pn }]);
|
|
@@ -940,8 +1134,20 @@ export const makeChatsSocket = (config) => {
|
|
|
940
1134
|
logger.warn({ lid, pn, error }, 'Failed to store LID-PN mapping');
|
|
941
1135
|
}
|
|
942
1136
|
});
|
|
1137
|
+
registerSocketEndHandler(() => {
|
|
1138
|
+
if (awaitingSyncTimeout) {
|
|
1139
|
+
clearTimeout(awaitingSyncTimeout);
|
|
1140
|
+
awaitingSyncTimeout = undefined;
|
|
1141
|
+
}
|
|
1142
|
+
if (!config.placeholderResendCache && placeholderResendCache.close) {
|
|
1143
|
+
placeholderResendCache.close();
|
|
1144
|
+
}
|
|
1145
|
+
syncState = SyncState.Connecting;
|
|
1146
|
+
privacySettings = undefined;
|
|
1147
|
+
});
|
|
943
1148
|
return {
|
|
944
1149
|
...sock,
|
|
1150
|
+
serverProps,
|
|
945
1151
|
createCallLink,
|
|
946
1152
|
getBotListV2,
|
|
947
1153
|
messageMutex,
|
|
@@ -978,6 +1184,7 @@ export const makeChatsSocket = (config) => {
|
|
|
978
1184
|
cleanDirtyBits,
|
|
979
1185
|
addOrEditContact,
|
|
980
1186
|
removeContact,
|
|
1187
|
+
placeholderResendCache,
|
|
981
1188
|
addLabel,
|
|
982
1189
|
addChatLabel,
|
|
983
1190
|
removeChatLabel,
|
package/lib/Socket/groups.d.ts
CHANGED
|
@@ -3,6 +3,22 @@ import type { GroupMetadata, ParticipantAction, SocketConfig, WAMessageKey } fro
|
|
|
3
3
|
import { type BinaryNode } from '../WABinary/index.js';
|
|
4
4
|
export declare const makeGroupsSocket: (config: SocketConfig) => {
|
|
5
5
|
groupMetadata: (jid: string) => Promise<GroupMetadata>;
|
|
6
|
+
/** groupMetadata con cache de 30s, invalidado automáticamente ante cambios reales de participantes. */
|
|
7
|
+
groupMetadataCached: (jid: string) => Promise<GroupMetadata>;
|
|
8
|
+
/**
|
|
9
|
+
* Resuelve un jid/@lid a su jid de número de teléfono real usando primero los participantes
|
|
10
|
+
* del grupo y, si no hay coincidencia, el mapeo LID↔PN nativo de Baileys (signalRepository).
|
|
11
|
+
* @param jidOrChatId el chatId del grupo, o directamente el array de participantes ya obtenido
|
|
12
|
+
* @param targetJid el jid/lid a resolver
|
|
13
|
+
*/
|
|
14
|
+
resolveParticipantJid: (jidOrChatId: string | GroupMetadata["participants"], targetJid: string) => Promise<string>;
|
|
15
|
+
/** true si el participante (jid o @lid) es admin/superadmin del grupo. */
|
|
16
|
+
isGroupAdmin: (jid: string, participantJid: string) => Promise<boolean>;
|
|
17
|
+
/** Lista de admins del grupo ya resueltos a jid de número de teléfono. */
|
|
18
|
+
getGroupAdmins: (jid: string) => Promise<{
|
|
19
|
+
jid: string;
|
|
20
|
+
admin: "admin" | "superadmin" | null;
|
|
21
|
+
}[]>;
|
|
6
22
|
groupCreate: (subject: string, participants: string[]) => Promise<GroupMetadata>;
|
|
7
23
|
groupLeave: (id: string) => Promise<void>;
|
|
8
24
|
groupUpdateSubject: (jid: string, subject: string) => Promise<void>;
|