@twsxtd/baileys 7.0.0-rc.9.commit.71ed75d4aae0 → 7.0.0-rc.9.commit.8d1e795328c7
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/WAProto/fix-imports.js +22 -18
- package/WAProto/index.js +22 -18
- package/lib/Defaults/index.d.ts +2 -0
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +3 -1
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +11 -3
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +3 -1
- package/lib/Signal/lid-mapping.d.ts.map +1 -1
- package/lib/Signal/lid-mapping.js +34 -14
- package/lib/Signal/lid-mapping.js.map +1 -1
- package/lib/Socket/Client/websocket.d.ts.map +1 -1
- package/lib/Socket/Client/websocket.js +3 -5
- package/lib/Socket/Client/websocket.js.map +1 -1
- package/lib/Socket/business.d.ts +7 -4
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/chats.d.ts +9 -3
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +252 -35
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +7 -4
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/groups.d.ts +8 -4
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/groups.js +20 -0
- package/lib/Socket/groups.js.map +1 -1
- package/lib/Socket/index.d.ts +7 -4
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/messages-recv.d.ts +7 -4
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +289 -61
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +7 -4
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +106 -12
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +6 -3
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/newsletter.js +2 -2
- package/lib/Socket/newsletter.js.map +1 -1
- package/lib/Socket/socket.d.ts +0 -2
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +15 -8
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +2 -0
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Call.d.ts +1 -1
- package/lib/Types/Call.d.ts.map +1 -1
- package/lib/Types/Contact.d.ts +2 -0
- package/lib/Types/Contact.d.ts.map +1 -1
- package/lib/Types/Events.d.ts +16 -0
- package/lib/Types/Events.d.ts.map +1 -1
- package/lib/Types/GroupMetadata.d.ts +4 -0
- package/lib/Types/GroupMetadata.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +15 -2
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Message.js.map +1 -1
- package/lib/Types/Newsletter.d.ts +4 -2
- package/lib/Types/Newsletter.d.ts.map +1 -1
- package/lib/Types/Newsletter.js +4 -2
- package/lib/Types/Newsletter.js.map +1 -1
- package/lib/Types/Signal.d.ts +1 -1
- package/lib/Types/Signal.d.ts.map +1 -1
- package/lib/Utils/auth-utils.d.ts +5 -0
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +45 -0
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/chat-utils.d.ts +30 -0
- package/lib/Utils/chat-utils.d.ts.map +1 -1
- package/lib/Utils/chat-utils.js +34 -8
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
- package/lib/Utils/companion-reg-client-utils.d.ts.map +1 -0
- package/lib/Utils/companion-reg-client-utils.js +41 -0
- package/lib/Utils/companion-reg-client-utils.js.map +1 -0
- package/lib/Utils/decode-wa-message.d.ts +12 -0
- package/lib/Utils/decode-wa-message.d.ts.map +1 -1
- package/lib/Utils/decode-wa-message.js +22 -0
- package/lib/Utils/decode-wa-message.js.map +1 -1
- package/lib/Utils/event-buffer.d.ts +0 -2
- package/lib/Utils/event-buffer.d.ts.map +1 -1
- package/lib/Utils/event-buffer.js +3 -16
- package/lib/Utils/event-buffer.js.map +1 -1
- package/lib/Utils/generics.d.ts +1 -0
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +22 -1
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/history.d.ts.map +1 -1
- package/lib/Utils/history.js +11 -9
- package/lib/Utils/history.js.map +1 -1
- package/lib/Utils/identity-change-handler.d.ts +7 -0
- package/lib/Utils/identity-change-handler.d.ts.map +1 -1
- package/lib/Utils/identity-change-handler.js +1 -0
- package/lib/Utils/identity-change-handler.js.map +1 -1
- package/lib/Utils/index.d.ts +1 -0
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/message-retry-manager.d.ts +1 -0
- package/lib/Utils/message-retry-manager.d.ts.map +1 -1
- package/lib/Utils/message-retry-manager.js +10 -0
- package/lib/Utils/message-retry-manager.js.map +1 -1
- package/lib/Utils/messages-media.js +1 -1
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +22 -1
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +70 -1
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/Utils/sync-action-utils.d.ts.map +1 -1
- package/lib/Utils/sync-action-utils.js +1 -0
- package/lib/Utils/sync-action-utils.js.map +1 -1
- package/lib/Utils/tc-token-utils.d.ts +26 -1
- package/lib/Utils/tc-token-utils.d.ts.map +1 -1
- package/lib/Utils/tc-token-utils.js +149 -4
- package/lib/Utils/tc-token-utils.js.map +1 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +1 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +26 -3
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +1 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/index.d.ts +1 -0
- package/lib/WAUSync/Protocols/index.d.ts.map +1 -1
- package/lib/WAUSync/Protocols/index.js +1 -0
- package/lib/WAUSync/Protocols/index.js.map +1 -1
- package/lib/WAUSync/USyncQuery.d.ts +1 -0
- package/lib/WAUSync/USyncQuery.d.ts.map +1 -1
- package/lib/WAUSync/USyncQuery.js +5 -1
- package/lib/WAUSync/USyncQuery.js.map +1 -1
- package/lib/WAUSync/USyncUser.d.ts +4 -0
- package/lib/WAUSync/USyncUser.d.ts.map +1 -1
- package/lib/WAUSync/USyncUser.js +8 -0
- package/lib/WAUSync/USyncUser.js.map +1 -1
- package/package.json +3 -3
package/lib/Socket/chats.d.ts
CHANGED
|
@@ -6,6 +6,15 @@ 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
8
|
export declare const makeChatsSocket: (config: SocketConfig) => {
|
|
9
|
+
serverProps: {
|
|
10
|
+
/** AB prop 10518: gate tctoken on 1:1 messages. Default true (safe: avoids 463). */
|
|
11
|
+
privacyTokenOn1to1: boolean;
|
|
12
|
+
/** AB prop 9666: gate tctoken on profile picture IQs. WA Web default: true. */
|
|
13
|
+
profilePicPrivacyToken: boolean;
|
|
14
|
+
/** AB prop 14303: issue tctokens to LID instead of PN. WA Web default: false. */
|
|
15
|
+
lidTrustedTokenIssueToLid: boolean;
|
|
16
|
+
};
|
|
17
|
+
end: (error: Error | undefined) => Promise<void>;
|
|
9
18
|
createCallLink: (type: "audio" | "video", event?: {
|
|
10
19
|
startTime: number;
|
|
11
20
|
}, timeoutMs?: number) => Promise<string | undefined>;
|
|
@@ -76,8 +85,6 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
|
|
|
76
85
|
createBufferedFunction<A extends any[], T>(work: (...args: A) => Promise<T>): (...args: A) => Promise<T>;
|
|
77
86
|
flush(): boolean;
|
|
78
87
|
isBuffering(): boolean;
|
|
79
|
-
release(): void;
|
|
80
|
-
removeAllListeners<T extends keyof import("../Types/index.js").BaileysEventMap>(event?: T): void;
|
|
81
88
|
};
|
|
82
89
|
authState: {
|
|
83
90
|
creds: import("../Types/index.js").AuthenticationCreds;
|
|
@@ -92,7 +99,6 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
|
|
|
92
99
|
sendRawMessage: (data: Uint8Array | Buffer) => Promise<void>;
|
|
93
100
|
sendNode: (frame: BinaryNode) => Promise<void>;
|
|
94
101
|
logout: (msg?: string) => Promise<void>;
|
|
95
|
-
end: (error: Error | undefined) => Promise<void>;
|
|
96
102
|
onUnexpectedError: (err: Error | Boom, msg: string) => void;
|
|
97
103
|
uploadPreKeys: (count?: number, retryCount?: number) => Promise<void>;
|
|
98
104
|
uploadPreKeysToServerIfRequired: () => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chats.d.ts","sourceRoot":"","sources":["../../src/Socket/chats.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAE9C,OAAO,KAAK,EACX,WAAW,EAEX,gBAAgB,EAGhB,iBAAiB,EAEjB,YAAY,EAEZ,iBAAiB,EACjB,aAAa,EACb,SAAS,EACT,aAAa,EAEb,UAAU,EACV,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,MAAM,UAAU,CAAA;AAEjB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"chats.d.ts","sourceRoot":"","sources":["../../src/Socket/chats.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAE9C,OAAO,KAAK,EACX,WAAW,EAEX,gBAAgB,EAGhB,iBAAiB,EAEjB,YAAY,EAEZ,iBAAiB,EACjB,aAAa,EACb,SAAS,EACT,aAAa,EAEb,UAAU,EACV,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,MAAM,UAAU,CAAA;AAEjB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAsBrD,OAAO,EACN,KAAK,UAAU,EAWf,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,UAAU,EAAa,MAAM,YAAY,CAAA;AAGlD,eAAO,MAAM,eAAe,GAAI,QAAQ,YAAY;;QA6BlD,oFAAoF;;QAEpF,+EAA+E;;QAE/E,iFAAiF;;;iBAg3C9D,KAAK,GAAG,SAAS;2BA7qBD,OAAO,GAAG,OAAO,UAAU;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,cAAc,MAAM;;;;;;;;;;;;;;;;;;4BA0HnE,aAAa;+BApGV,UAAU,UAAU,MAAM;+BA8C1B,MAAM;6BA5GR,MAAM,SAAQ,SAAS,GAAG,OAAO,cAA0B,MAAM;;2BAhdnE,MAAM,EAAE;yCAaM,MAAM,EAAE;gCAepD,MAAM,WACF,aAAa,eACT;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;gCAmCN,MAAM;kCA0BJ,MAAM;8BAkBV,MAAM;6BAkBP,MAAM,UAAU,OAAO,GAAG,SAAS;2DAkoBX,OAAO;+BAn1B7B,kBAAkB;mCAJd,sBAAsB;mCAQtB,cAAc;iCAIhB,oBAAoB;yCAIZ,cAAc;iCAItB,cAAc;uCAIR,mBAAmB;oCAItB,sBAAsB;8CAIZ,MAAM;8BAqPtB,MAAM,KAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;;sBA0jBxD,gBAAgB,OAAO,MAAM;2BAxgBlB,cAAc,GAAG,QAAQ,kBAAkB,MAAM,GAAG,MAAM;4BA2iB/D,MAAM,WAAW,KAAK,CAAC,eAAe,CAAC,cAAc;yBAYxD,MAAM;oBAYX,MAAM,UAAU,eAAe;wBAc3B,MAAM,WAAW,MAAM;2BAcpB,MAAM,WAAW,MAAM;2BAcvB,MAAM,aAAa,MAAM,WAAW,MAAM;8BAevC,MAAM,aAAa,MAAM,WAAW,MAAM;gBAhGxD,MAAM,YAAY;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,QAAQ,OAAO;sCA+G7C,gBAAgB;kCAYpB,MAAM;;;;;;0DAvnClB,GAAG,0BACzB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAo8CN,CAAA"}
|
package/lib/Socket/chats.js
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
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, bindCleanupOnConnectionClose, 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, isLidUser, isPnUser, jidDecode, jidNormalizedUser, isHostedLidUser, isHostedPnUser, 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 MAX_SYNC_ATTEMPTS = 2;
|
|
15
14
|
export const makeChatsSocket = (config) => {
|
|
16
15
|
const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, getMessage } = config;
|
|
17
16
|
const sock = makeSocket(config);
|
|
18
17
|
const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession } = sock;
|
|
18
|
+
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
|
|
19
19
|
let privacySettings;
|
|
20
|
+
/** Server-assigned AB props for protocol behavior. */
|
|
21
|
+
const serverProps = {
|
|
22
|
+
/** AB prop 10518: gate tctoken on 1:1 messages. Default true (safe: avoids 463). */
|
|
23
|
+
privacyTokenOn1to1: true,
|
|
24
|
+
/** AB prop 9666: gate tctoken on profile picture IQs. WA Web default: true. */
|
|
25
|
+
profilePicPrivacyToken: true,
|
|
26
|
+
/** AB prop 14303: issue tctokens to LID instead of PN. WA Web default: false. */
|
|
27
|
+
lidTrustedTokenIssueToLid: false
|
|
28
|
+
};
|
|
20
29
|
let syncState = SyncState.Connecting;
|
|
21
30
|
/** this mutex ensures that messages are processed in order */
|
|
22
31
|
const messageMutex = makeMutex();
|
|
@@ -28,14 +37,44 @@ export const makeChatsSocket = (config) => {
|
|
|
28
37
|
const notificationMutex = makeMutex();
|
|
29
38
|
// Timeout for AwaitingInitialSync state
|
|
30
39
|
let awaitingSyncTimeout;
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
// In-memory history sync completion tracking (resets on reconnection)
|
|
41
|
+
const historySyncStatus = {
|
|
42
|
+
initialBootstrapComplete: false,
|
|
43
|
+
recentSyncComplete: false
|
|
44
|
+
};
|
|
45
|
+
let historySyncPausedTimeout;
|
|
46
|
+
// Collections blocked on missing app state sync keys (mirrors WA Web's "Blocked" state).
|
|
47
|
+
// When a key arrives via APP_STATE_SYNC_KEY_SHARE, these are re-synced.
|
|
48
|
+
const blockedCollections = new Set();
|
|
49
|
+
const internalPlaceholderResendCache = config.placeholderResendCache
|
|
50
|
+
? undefined
|
|
51
|
+
: new NodeCache({
|
|
33
52
|
stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
34
53
|
useClones: false
|
|
35
54
|
});
|
|
55
|
+
const placeholderResendCache = config.placeholderResendCache || internalPlaceholderResendCache;
|
|
36
56
|
if (!config.placeholderResendCache) {
|
|
37
57
|
config.placeholderResendCache = placeholderResendCache;
|
|
38
58
|
}
|
|
59
|
+
let cleanedUp = false;
|
|
60
|
+
const cleanupInternalResources = async () => {
|
|
61
|
+
if (cleanedUp) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
cleanedUp = true;
|
|
65
|
+
if (awaitingSyncTimeout) {
|
|
66
|
+
clearTimeout(awaitingSyncTimeout);
|
|
67
|
+
awaitingSyncTimeout = undefined;
|
|
68
|
+
}
|
|
69
|
+
if (historySyncPausedTimeout) {
|
|
70
|
+
clearTimeout(historySyncPausedTimeout);
|
|
71
|
+
historySyncPausedTimeout = undefined;
|
|
72
|
+
}
|
|
73
|
+
if (internalPlaceholderResendCache) {
|
|
74
|
+
await Promise.resolve(internalPlaceholderResendCache.close());
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
bindCleanupOnConnectionClose(ev, cleanupInternalResources);
|
|
39
78
|
/** helper function to fetch the given app state sync key */
|
|
40
79
|
const getAppStateSyncKey = async (keyId) => {
|
|
41
80
|
const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId]);
|
|
@@ -258,6 +297,42 @@ export const makeChatsSocket = (config) => {
|
|
|
258
297
|
return getBinaryNodeChildren(listNode, 'item').map(n => n.attrs.jid);
|
|
259
298
|
};
|
|
260
299
|
const updateBlockStatus = async (jid, action) => {
|
|
300
|
+
const normalizedJid = jidNormalizedUser(jid);
|
|
301
|
+
let lid;
|
|
302
|
+
let pn_jid;
|
|
303
|
+
if (isLidUser(normalizedJid) || isHostedLidUser(normalizedJid)) {
|
|
304
|
+
lid = normalizedJid;
|
|
305
|
+
if (action === 'block') {
|
|
306
|
+
const pn = await signalRepository.lidMapping.getPNForLID(normalizedJid);
|
|
307
|
+
if (!pn) {
|
|
308
|
+
throw new Boom(`Unable to resolve PN JID for LID: ${jid}`, { statusCode: 400 });
|
|
309
|
+
}
|
|
310
|
+
pn_jid = jidNormalizedUser(pn);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
else if (isPnUser(normalizedJid) || isHostedPnUser(normalizedJid)) {
|
|
314
|
+
const mapped = await signalRepository.lidMapping.getLIDForPN(normalizedJid);
|
|
315
|
+
if (!mapped) {
|
|
316
|
+
throw new Boom(`Unable to resolve LID for PN JID: ${jid}`, { statusCode: 400 });
|
|
317
|
+
}
|
|
318
|
+
lid = mapped;
|
|
319
|
+
if (action === 'block') {
|
|
320
|
+
pn_jid = jidNormalizedUser(normalizedJid);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
throw new Boom(`Invalid jid: ${jid}`, { statusCode: 400 });
|
|
325
|
+
}
|
|
326
|
+
const itemAttrs = {
|
|
327
|
+
action,
|
|
328
|
+
jid: lid
|
|
329
|
+
};
|
|
330
|
+
if (action === 'block') {
|
|
331
|
+
if (!pn_jid) {
|
|
332
|
+
throw new Boom(`pn_jid required for block: ${jid}`, { statusCode: 400 });
|
|
333
|
+
}
|
|
334
|
+
itemAttrs.pn_jid = pn_jid;
|
|
335
|
+
}
|
|
261
336
|
await query({
|
|
262
337
|
tag: 'iq',
|
|
263
338
|
attrs: {
|
|
@@ -268,10 +343,7 @@ export const makeChatsSocket = (config) => {
|
|
|
268
343
|
content: [
|
|
269
344
|
{
|
|
270
345
|
tag: 'item',
|
|
271
|
-
attrs:
|
|
272
|
-
action,
|
|
273
|
-
jid
|
|
274
|
-
}
|
|
346
|
+
attrs: itemAttrs
|
|
275
347
|
}
|
|
276
348
|
]
|
|
277
349
|
});
|
|
@@ -370,6 +442,9 @@ export const makeChatsSocket = (config) => {
|
|
|
370
442
|
const collectionsToHandle = new Set(collections);
|
|
371
443
|
// in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
|
|
372
444
|
const attemptsMap = {};
|
|
445
|
+
// collections that failed and need a full snapshot on retry
|
|
446
|
+
// mirrors WA Web's ErrorFatal -> force snapshot behavior
|
|
447
|
+
const forceSnapshotCollections = new Set();
|
|
373
448
|
// keep executing till all collections are done
|
|
374
449
|
// sometimes a single patch request will not return all the patches (God knows why)
|
|
375
450
|
// so we fetch till they're all done (this is determined by the "has_more_patches" flag)
|
|
@@ -380,6 +455,7 @@ export const makeChatsSocket = (config) => {
|
|
|
380
455
|
const result = await authState.keys.get('app-state-sync-version', [name]);
|
|
381
456
|
let state = result[name];
|
|
382
457
|
if (state) {
|
|
458
|
+
state = ensureLTHashStateVersion(state);
|
|
383
459
|
if (typeof initialVersionMap[name] === 'undefined') {
|
|
384
460
|
initialVersionMap[name] = state.version;
|
|
385
461
|
}
|
|
@@ -388,14 +464,18 @@ export const makeChatsSocket = (config) => {
|
|
|
388
464
|
state = newLTHashState();
|
|
389
465
|
}
|
|
390
466
|
states[name] = state;
|
|
391
|
-
|
|
467
|
+
const shouldForceSnapshot = forceSnapshotCollections.has(name);
|
|
468
|
+
if (shouldForceSnapshot) {
|
|
469
|
+
forceSnapshotCollections.delete(name);
|
|
470
|
+
}
|
|
471
|
+
logger.info(`resyncing ${name} from v${state.version}${shouldForceSnapshot ? ' (forcing snapshot)' : ''}`);
|
|
392
472
|
nodes.push({
|
|
393
473
|
tag: 'collection',
|
|
394
474
|
attrs: {
|
|
395
475
|
name,
|
|
396
476
|
version: state.version.toString(),
|
|
397
|
-
// return snapshot if
|
|
398
|
-
return_snapshot: (!state.version).toString()
|
|
477
|
+
// return snapshot if syncing from scratch or forcing after a failed attempt
|
|
478
|
+
return_snapshot: (shouldForceSnapshot || !state.version).toString()
|
|
399
479
|
}
|
|
400
480
|
});
|
|
401
481
|
}
|
|
@@ -444,19 +524,37 @@ export const makeChatsSocket = (config) => {
|
|
|
444
524
|
}
|
|
445
525
|
}
|
|
446
526
|
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
527
|
attemptsMap[name] = (attemptsMap[name] || 0) + 1;
|
|
456
|
-
|
|
457
|
-
|
|
528
|
+
const logData = {
|
|
529
|
+
name,
|
|
530
|
+
attempt: attemptsMap[name],
|
|
531
|
+
version: states[name].version,
|
|
532
|
+
statusCode: error.output?.statusCode,
|
|
533
|
+
errorType: error.name,
|
|
534
|
+
error: error.stack
|
|
535
|
+
};
|
|
536
|
+
if (isMissingKeyError(error) && attemptsMap[name] >= MAX_SYNC_ATTEMPTS) {
|
|
537
|
+
// WA Web treats missing keys as "Blocked" — park the collection
|
|
538
|
+
// until the key arrives via APP_STATE_SYNC_KEY_SHARE.
|
|
539
|
+
logger.warn(logData, `${name} blocked on missing key from v${states[name].version}, parking after ${attemptsMap[name]} attempts`);
|
|
540
|
+
blockedCollections.add(name);
|
|
541
|
+
collectionsToHandle.delete(name);
|
|
542
|
+
}
|
|
543
|
+
else if (isMissingKeyError(error)) {
|
|
544
|
+
// Retry with a snapshot which may use a different key.
|
|
545
|
+
logger.info(logData, `${name} blocked on missing key from v${states[name].version}, retrying with snapshot`);
|
|
546
|
+
forceSnapshotCollections.add(name);
|
|
547
|
+
}
|
|
548
|
+
else if (isAppStateSyncIrrecoverable(error, attemptsMap[name])) {
|
|
549
|
+
logger.warn(logData, `failed to sync ${name} from v${states[name].version}, giving up`);
|
|
458
550
|
collectionsToHandle.delete(name);
|
|
459
551
|
}
|
|
552
|
+
else {
|
|
553
|
+
logger.info(logData, `failed to sync ${name} from v${states[name].version}, forcing snapshot retry`);
|
|
554
|
+
// force a full snapshot on retry to recover from
|
|
555
|
+
// corrupted local state (e.g. LTHash MAC mismatch)
|
|
556
|
+
forceSnapshotCollections.add(name);
|
|
557
|
+
}
|
|
460
558
|
}
|
|
461
559
|
}
|
|
462
560
|
}
|
|
@@ -473,7 +571,22 @@ export const makeChatsSocket = (config) => {
|
|
|
473
571
|
*/
|
|
474
572
|
const profilePictureUrl = async (jid, type = 'preview', timeoutMs) => {
|
|
475
573
|
const baseContent = [{ tag: 'picture', attrs: { type, query: 'url' } }];
|
|
476
|
-
|
|
574
|
+
// WA Web only includes tctoken for user JIDs (not groups/newsletters)
|
|
575
|
+
// and never for own profile pic (Chat model for self has no tcToken).
|
|
576
|
+
// Including tctoken for own JID causes the server to never respond.
|
|
577
|
+
const normalizedJid = jidNormalizedUser(jid);
|
|
578
|
+
const isUserJid = isPnUser(normalizedJid) || isLidUser(normalizedJid);
|
|
579
|
+
const me = authState.creds.me;
|
|
580
|
+
const isSelf = me && (normalizedJid === jidNormalizedUser(me.id) || (me.lid && normalizedJid === jidNormalizedUser(me.lid)));
|
|
581
|
+
let content = baseContent;
|
|
582
|
+
if (serverProps.profilePicPrivacyToken && isUserJid && !isSelf) {
|
|
583
|
+
content = await buildTcTokenFromJid({
|
|
584
|
+
authState,
|
|
585
|
+
jid: normalizedJid,
|
|
586
|
+
baseContent,
|
|
587
|
+
getLIDForPN
|
|
588
|
+
});
|
|
589
|
+
}
|
|
477
590
|
jid = jidNormalizedUser(jid);
|
|
478
591
|
const result = await query({
|
|
479
592
|
tag: 'iq',
|
|
@@ -483,7 +596,7 @@ export const makeChatsSocket = (config) => {
|
|
|
483
596
|
type: 'get',
|
|
484
597
|
xmlns: 'w:profile:picture'
|
|
485
598
|
},
|
|
486
|
-
content
|
|
599
|
+
content
|
|
487
600
|
}, timeoutMs);
|
|
488
601
|
const child = getBinaryNodeChild(result, 'picture');
|
|
489
602
|
return child?.attrs?.url;
|
|
@@ -549,7 +662,12 @@ export const makeChatsSocket = (config) => {
|
|
|
549
662
|
* @param tcToken token for subscription, use if present
|
|
550
663
|
*/
|
|
551
664
|
const presenceSubscribe = async (toJid) => {
|
|
552
|
-
|
|
665
|
+
// Only include tctoken for user JIDs — groups/newsletters don't use tctokens
|
|
666
|
+
const normalizedToJid = jidNormalizedUser(toJid);
|
|
667
|
+
const isUserJid = isPnUser(normalizedToJid) || isLidUser(normalizedToJid);
|
|
668
|
+
const tcTokenContent = isUserJid
|
|
669
|
+
? await buildTcTokenFromJid({ authState, jid: normalizedToJid, getLIDForPN })
|
|
670
|
+
: undefined;
|
|
553
671
|
return sendNode({
|
|
554
672
|
tag: 'presence',
|
|
555
673
|
attrs: {
|
|
@@ -604,7 +722,7 @@ export const makeChatsSocket = (config) => {
|
|
|
604
722
|
logger.debug({ patch: patchCreate }, 'applying app patch');
|
|
605
723
|
await resyncAppState([name], false);
|
|
606
724
|
const { [name]: currentSyncVersion } = await authState.keys.get('app-state-sync-version', [name]);
|
|
607
|
-
initial = currentSyncVersion
|
|
725
|
+
initial = currentSyncVersion ? ensureLTHashStateVersion(currentSyncVersion) : newLTHashState();
|
|
608
726
|
encodeResult = await encodeSyncdPatch(patchCreate, myAppStateKeyId, initial, getAppStateSyncKey);
|
|
609
727
|
const { patch, state } = encodeResult;
|
|
610
728
|
const node = {
|
|
@@ -650,22 +768,21 @@ export const makeChatsSocket = (config) => {
|
|
|
650
768
|
}
|
|
651
769
|
}
|
|
652
770
|
};
|
|
653
|
-
/**
|
|
771
|
+
/** fetch AB props */
|
|
654
772
|
const fetchProps = async () => {
|
|
655
|
-
//TODO: implement both protocol 1 and protocol 2 prop fetching, specially for abKey for WM
|
|
656
773
|
const resultNode = await query({
|
|
657
774
|
tag: 'iq',
|
|
658
775
|
attrs: {
|
|
659
776
|
to: S_WHATSAPP_NET,
|
|
660
|
-
xmlns: '
|
|
777
|
+
xmlns: 'abt',
|
|
661
778
|
type: 'get'
|
|
662
779
|
},
|
|
663
780
|
content: [
|
|
664
781
|
{
|
|
665
782
|
tag: 'props',
|
|
666
783
|
attrs: {
|
|
667
|
-
protocol: '
|
|
668
|
-
hash: authState
|
|
784
|
+
protocol: '1',
|
|
785
|
+
...(authState?.creds?.lastPropHash ? { hash: authState.creds.lastPropHash } : {})
|
|
669
786
|
}
|
|
670
787
|
}
|
|
671
788
|
]
|
|
@@ -680,7 +797,20 @@ export const makeChatsSocket = (config) => {
|
|
|
680
797
|
}
|
|
681
798
|
props = reduceBinaryNodeToDictionary(propsNode, 'prop');
|
|
682
799
|
}
|
|
683
|
-
|
|
800
|
+
// Extract protocol-relevant AB props (only the ones we need)
|
|
801
|
+
const privacyTokenProp = props['10518'] ?? props['privacy_token_sending_on_all_1_on_1_messages'];
|
|
802
|
+
if (privacyTokenProp !== undefined) {
|
|
803
|
+
serverProps.privacyTokenOn1to1 = privacyTokenProp === 'true' || privacyTokenProp === '1';
|
|
804
|
+
}
|
|
805
|
+
const profilePicProp = props['9666'] ?? props['profile_scraping_privacy_token_in_photo_iq'];
|
|
806
|
+
if (profilePicProp !== undefined) {
|
|
807
|
+
serverProps.profilePicPrivacyToken = profilePicProp === 'true' || profilePicProp === '1';
|
|
808
|
+
}
|
|
809
|
+
const lidIssueProp = props['14303'] ?? props['lid_trusted_token_issue_to_lid'];
|
|
810
|
+
if (lidIssueProp !== undefined) {
|
|
811
|
+
serverProps.lidTrustedTokenIssueToLid = lidIssueProp === 'true' || lidIssueProp === '1';
|
|
812
|
+
}
|
|
813
|
+
logger.debug({ serverProps }, 'fetched props');
|
|
684
814
|
return props;
|
|
685
815
|
};
|
|
686
816
|
/**
|
|
@@ -820,6 +950,47 @@ export const makeChatsSocket = (config) => {
|
|
|
820
950
|
? shouldSyncHistoryMessage(historyMsg) &&
|
|
821
951
|
PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)
|
|
822
952
|
: false;
|
|
953
|
+
if (historyMsg && shouldProcessHistoryMsg) {
|
|
954
|
+
const syncType = historyMsg.syncType;
|
|
955
|
+
// INITIAL_BOOTSTRAP — fire immediately, no progress check (same as WA Web K function)
|
|
956
|
+
if (syncType === proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP &&
|
|
957
|
+
!historySyncStatus.initialBootstrapComplete) {
|
|
958
|
+
historySyncStatus.initialBootstrapComplete = true;
|
|
959
|
+
ev.emit('messaging-history.status', {
|
|
960
|
+
syncType,
|
|
961
|
+
status: 'complete',
|
|
962
|
+
explicit: true
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
// RECENT with progress === 100 — explicit completion
|
|
966
|
+
if (syncType === proto.HistorySync.HistorySyncType.RECENT &&
|
|
967
|
+
historyMsg.progress === 100 &&
|
|
968
|
+
!historySyncStatus.recentSyncComplete) {
|
|
969
|
+
historySyncStatus.recentSyncComplete = true;
|
|
970
|
+
clearTimeout(historySyncPausedTimeout);
|
|
971
|
+
historySyncPausedTimeout = undefined;
|
|
972
|
+
ev.emit('messaging-history.status', {
|
|
973
|
+
syncType,
|
|
974
|
+
status: 'complete',
|
|
975
|
+
explicit: true
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
// Reset 120s paused timeout on any RECENT chunk (like WA Web's handleChunkProgress)
|
|
979
|
+
if (syncType === proto.HistorySync.HistorySyncType.RECENT && !historySyncStatus.recentSyncComplete) {
|
|
980
|
+
clearTimeout(historySyncPausedTimeout);
|
|
981
|
+
historySyncPausedTimeout = setTimeout(() => {
|
|
982
|
+
if (!historySyncStatus.recentSyncComplete) {
|
|
983
|
+
historySyncStatus.recentSyncComplete = true;
|
|
984
|
+
ev.emit('messaging-history.status', {
|
|
985
|
+
syncType: proto.HistorySync.HistorySyncType.RECENT,
|
|
986
|
+
status: 'paused',
|
|
987
|
+
explicit: false
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
historySyncPausedTimeout = undefined;
|
|
991
|
+
}, HISTORY_SYNC_PAUSED_TIMEOUT_MS);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
823
994
|
// State machine: decide on sync and flush
|
|
824
995
|
if (historyMsg && syncState === SyncState.AwaitingInitialSync) {
|
|
825
996
|
if (awaitingSyncTimeout) {
|
|
@@ -839,6 +1010,8 @@ export const makeChatsSocket = (config) => {
|
|
|
839
1010
|
}
|
|
840
1011
|
const doAppStateSync = async () => {
|
|
841
1012
|
if (syncState === SyncState.Syncing) {
|
|
1013
|
+
// All collections will be synced, so clear any blocked ones
|
|
1014
|
+
blockedCollections.clear();
|
|
842
1015
|
logger.info('Doing app state sync');
|
|
843
1016
|
await resyncAppState(ALL_WA_PATCH_NAMES, true);
|
|
844
1017
|
// Sync is complete, go online and flush everything
|
|
@@ -898,6 +1071,11 @@ export const makeChatsSocket = (config) => {
|
|
|
898
1071
|
}
|
|
899
1072
|
});
|
|
900
1073
|
ev.on('connection.update', ({ connection, receivedPendingNotifications }) => {
|
|
1074
|
+
if (connection === 'close') {
|
|
1075
|
+
blockedCollections.clear();
|
|
1076
|
+
clearTimeout(historySyncPausedTimeout);
|
|
1077
|
+
historySyncPausedTimeout = undefined;
|
|
1078
|
+
}
|
|
901
1079
|
if (connection === 'open') {
|
|
902
1080
|
if (fireInitQueries) {
|
|
903
1081
|
executeInitQueries().catch(error => onUnexpectedError(error, 'init queries'));
|
|
@@ -907,6 +1085,10 @@ export const makeChatsSocket = (config) => {
|
|
|
907
1085
|
if (!receivedPendingNotifications || syncState !== SyncState.Connecting) {
|
|
908
1086
|
return;
|
|
909
1087
|
}
|
|
1088
|
+
historySyncStatus.initialBootstrapComplete = false;
|
|
1089
|
+
historySyncStatus.recentSyncComplete = false;
|
|
1090
|
+
clearTimeout(historySyncPausedTimeout);
|
|
1091
|
+
historySyncPausedTimeout = undefined;
|
|
910
1092
|
syncState = SyncState.AwaitingInitialSync;
|
|
911
1093
|
logger.info('Connection is now AwaitingInitialSync, buffering events');
|
|
912
1094
|
ev.buffer();
|
|
@@ -919,19 +1101,49 @@ export const makeChatsSocket = (config) => {
|
|
|
919
1101
|
setTimeout(() => ev.flush(), 0);
|
|
920
1102
|
return;
|
|
921
1103
|
}
|
|
922
|
-
|
|
1104
|
+
// On reconnection (accountSyncCounter > 0), the server does not push
|
|
1105
|
+
// history sync notifications — the device already has its data.
|
|
1106
|
+
// Skip the 20s wait and go online immediately.
|
|
1107
|
+
if (authState.creds.accountSyncCounter > 0) {
|
|
1108
|
+
logger.info('Reconnection with existing sync data, skipping history sync wait. Transitioning to Online.');
|
|
1109
|
+
syncState = SyncState.Online;
|
|
1110
|
+
setTimeout(() => ev.flush(), 0);
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
logger.info('First connection, awaiting history sync notification with a 20s timeout.');
|
|
923
1114
|
if (awaitingSyncTimeout) {
|
|
924
1115
|
clearTimeout(awaitingSyncTimeout);
|
|
925
1116
|
}
|
|
926
1117
|
awaitingSyncTimeout = setTimeout(() => {
|
|
927
1118
|
if (syncState === SyncState.AwaitingInitialSync) {
|
|
928
|
-
// TODO: investigate
|
|
929
1119
|
logger.warn('Timeout in AwaitingInitialSync, forcing state to Online and flushing buffer');
|
|
930
1120
|
syncState = SyncState.Online;
|
|
931
1121
|
ev.flush();
|
|
1122
|
+
// Increment so subsequent reconnections skip the 20s wait.
|
|
1123
|
+
// Late-arriving history is still processed via processMessage
|
|
1124
|
+
// regardless of the state machine phase.
|
|
1125
|
+
const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
|
|
1126
|
+
ev.emit('creds.update', { accountSyncCounter });
|
|
932
1127
|
}
|
|
933
1128
|
}, 20000);
|
|
934
1129
|
});
|
|
1130
|
+
// When an app state sync key arrives (myAppStateKeyId is set) and there are
|
|
1131
|
+
// collections blocked on a missing key, trigger a re-sync for just those collections.
|
|
1132
|
+
// This mirrors WA Web's Blocked → retry-on-key-arrival behavior.
|
|
1133
|
+
ev.on('creds.update', ({ myAppStateKeyId }) => {
|
|
1134
|
+
if (!myAppStateKeyId || blockedCollections.size === 0) {
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
// If we're in the middle of a full sync, doAppStateSync handles all collections
|
|
1138
|
+
if (syncState === SyncState.Syncing) {
|
|
1139
|
+
blockedCollections.clear();
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
const collections = [...blockedCollections];
|
|
1143
|
+
blockedCollections.clear();
|
|
1144
|
+
logger.info({ collections }, 'app state sync key arrived, re-syncing blocked collections');
|
|
1145
|
+
resyncAppState(collections, false).catch(error => onUnexpectedError(error, 'blocked collections resync'));
|
|
1146
|
+
});
|
|
935
1147
|
ev.on('lid-mapping.update', async ({ lid, pn }) => {
|
|
936
1148
|
try {
|
|
937
1149
|
await signalRepository.lidMapping.storeLIDPNMappings([{ lid, pn }]);
|
|
@@ -942,6 +1154,11 @@ export const makeChatsSocket = (config) => {
|
|
|
942
1154
|
});
|
|
943
1155
|
return {
|
|
944
1156
|
...sock,
|
|
1157
|
+
serverProps,
|
|
1158
|
+
end: async (error) => {
|
|
1159
|
+
await cleanupInternalResources();
|
|
1160
|
+
await sock.end(error);
|
|
1161
|
+
},
|
|
945
1162
|
createCallLink,
|
|
946
1163
|
getBotListV2,
|
|
947
1164
|
messageMutex,
|