libzapitu-rf 1.0.0-alpha.2 → 1.0.0-alpha.20

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.
Files changed (50) hide show
  1. package/README.md +27 -1
  2. package/WAProto/index.d.ts +3 -0
  3. package/lib/Defaults/index.d.ts +4 -0
  4. package/lib/Defaults/index.js +5 -1
  5. package/lib/Socket/business.d.ts +27 -2
  6. package/lib/Socket/chats.d.ts +2 -0
  7. package/lib/Socket/chats.js +4 -38
  8. package/lib/Socket/groups.d.ts +2 -0
  9. package/lib/Socket/index.d.ts +27 -2
  10. package/lib/Socket/messages-recv.d.ts +28 -3
  11. package/lib/Socket/messages-recv.js +182 -8
  12. package/lib/Socket/messages-send.d.ts +26 -1
  13. package/lib/Socket/messages-send.js +247 -40
  14. package/lib/Socket/mex.d.ts +1 -1
  15. package/lib/Socket/newsletter.d.ts +4 -3
  16. package/lib/Socket/newsletter.js +3 -1
  17. package/lib/Socket/socket.d.ts +3 -0
  18. package/lib/Socket/socket.js +49 -0
  19. package/lib/Socket/usync.d.ts +2 -0
  20. package/lib/Types/Auth.d.ts +8 -0
  21. package/lib/Types/Events.d.ts +19 -0
  22. package/lib/Types/Message.d.ts +1 -0
  23. package/lib/Types/Newsletter.d.ts +6 -2
  24. package/lib/Types/Newsletter.js +4 -0
  25. package/lib/Types/State.d.ts +55 -0
  26. package/lib/Types/State.js +44 -0
  27. package/lib/Utils/auth-utils.js +1 -1
  28. package/lib/Utils/cache-utils.d.ts +5 -0
  29. package/lib/Utils/cache-utils.js +10 -0
  30. package/lib/Utils/crypto.js +3 -1
  31. package/lib/Utils/decode-wa-message.d.ts +11 -0
  32. package/lib/Utils/decode-wa-message.js +33 -10
  33. package/lib/Utils/event-buffer.js +3 -2
  34. package/lib/Utils/history.d.ts +3 -2
  35. package/lib/Utils/history.js +27 -4
  36. package/lib/Utils/logger.d.ts +2 -1
  37. package/lib/Utils/messages.js +13 -0
  38. package/lib/Utils/process-message.d.ts +2 -2
  39. package/lib/Utils/process-message.js +2 -2
  40. package/lib/Utils/tc-token-utils.d.ts +53 -0
  41. package/lib/Utils/tc-token-utils.js +123 -0
  42. package/lib/Utils/validate-connection.d.ts +2 -2
  43. package/lib/Utils/validate-connection.js +59 -27
  44. package/lib/worker/child.d.ts +1 -0
  45. package/lib/worker/child.js +262 -0
  46. package/lib/worker/index.d.ts +31 -0
  47. package/lib/worker/index.js +72 -0
  48. package/lib/worker/proxy.d.ts +24 -0
  49. package/lib/worker/proxy.js +510 -0
  50. package/package.json +24 -4
package/README.md CHANGED
@@ -1,9 +1,35 @@
1
+ <h1><img alt="Baileys logo" src="https://raw.githubusercontent.com/zapitu/libzapitu/refs/heads/rf/Media/logo.jpg" height="75"/></h1>
2
+
1
3
  # libzapitu-rf
2
4
 
3
5
  LibZapitu is a WebSockets-based TypeScript library for interacting with the WhatsApp Web API.
4
6
 
5
7
  It is forked from [Baileys](https://github.com/WhiskeySockets/Baileys) before the changes to ESM and implements better compatibility to the new privacy of phone numbers from Whatsapp.
6
8
 
9
+ # To work with libzapitu it is needed:
10
+
11
+ * It is suggested to restart the connections reading again their qrcode
12
+ * Do not use `makeCacheableSignalKeystore` on MakeWASocket
13
+ * Be sure that `getMessage` is implemented and working well
14
+
15
+ # To use libzapitu
16
+
17
+ ## To use libzapitu
18
+
19
+ ```
20
+ npm install libzapitu-rf
21
+ ```
22
+
23
+ ## To install libzapitu-rf in place of baileys
24
+
25
+ To avoid renaming imports from baileys on your existing code you can use npm aliasing function.
26
+
27
+ Example: if your code uses "baileys" on imports:
28
+
29
+ ```
30
+ npm install baileys@npm:libzapitu-rf
31
+ ```
32
+
7
33
  # Sponsor the author
8
34
 
9
35
  Work on this fork is mostly from [Renato Freitas](https://github.com/renatoiub)
@@ -180,7 +206,7 @@ WhatsApp provides a multi-device API that allows Baileys to be authenticated as
180
206
  > You can customize browser name if you connect with **QR-CODE**, with `Browser` constant, we have some browsers config, **see [here](https://baileys.whiskeysockets.io/types/BrowsersMap.html)**
181
207
 
182
208
  ```ts
183
- import makeWASocket from '@whiskeysockets/baileys'
209
+ import makeWASocket from 'libzapitu-rf'
184
210
 
185
211
  const sock = makeWASocket({
186
212
  // can provide additional config here
@@ -52837,6 +52837,9 @@ export namespace proto {
52837
52837
 
52838
52838
  /** WebMessageInfo botTargetId */
52839
52839
  botTargetId?: (string|null);
52840
+
52841
+ /** view once message */
52842
+ viewOnce?: (boolean|null);
52840
52843
  }
52841
52844
 
52842
52845
  /** Represents a WebMessageInfo. */
@@ -5,6 +5,10 @@ export declare const DEFAULT_ORIGIN = "https://web.whatsapp.com";
5
5
  export declare const DEF_CALLBACK_PREFIX = "CB:";
6
6
  export declare const DEF_TAG_PREFIX = "TAG:";
7
7
  export declare const PHONE_CONNECTION_CB = "CB:Pong";
8
+ export declare const WA_ADV_ACCOUNT_SIG_PREFIX: Buffer<ArrayBuffer>;
9
+ export declare const WA_ADV_DEVICE_SIG_PREFIX: Buffer<ArrayBuffer>;
10
+ export declare const WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX: Buffer<ArrayBuffer>;
11
+ export declare const WA_ADV_HOSTED_DEVICE_SIG_PREFIX: Buffer<ArrayBuffer>;
8
12
  export declare const WA_DEFAULT_EPHEMERAL: number;
9
13
  export declare const NOISE_MODE = "Noise_XX_25519_AESGCM_SHA256\0\0\0\0";
10
14
  export declare const DICT_VERSION = 3;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DEFAULT_CACHE_TTLS = exports.INITIAL_PREKEY_COUNT = exports.MIN_PREKEY_COUNT = exports.MEDIA_KEYS = exports.MEDIA_HKDF_KEY_MAPPING = exports.MEDIA_PATH_MAP = exports.DEFAULT_CONNECTION_CONFIG = exports.PROCESSABLE_HISTORY_TYPES = exports.WA_CERT_DETAILS = exports.URL_REGEX = exports.NOISE_WA_HEADER = exports.KEY_BUNDLE_TYPE = exports.DICT_VERSION = exports.NOISE_MODE = exports.WA_DEFAULT_EPHEMERAL = exports.PHONE_CONNECTION_CB = exports.DEF_TAG_PREFIX = exports.DEF_CALLBACK_PREFIX = exports.DEFAULT_ORIGIN = exports.UNAUTHORIZED_CODES = void 0;
6
+ exports.DEFAULT_CACHE_TTLS = exports.INITIAL_PREKEY_COUNT = exports.MIN_PREKEY_COUNT = exports.MEDIA_KEYS = exports.MEDIA_HKDF_KEY_MAPPING = exports.MEDIA_PATH_MAP = exports.DEFAULT_CONNECTION_CONFIG = exports.PROCESSABLE_HISTORY_TYPES = exports.WA_CERT_DETAILS = exports.URL_REGEX = exports.NOISE_WA_HEADER = exports.KEY_BUNDLE_TYPE = exports.DICT_VERSION = exports.NOISE_MODE = exports.WA_DEFAULT_EPHEMERAL = exports.WA_ADV_HOSTED_DEVICE_SIG_PREFIX = exports.WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX = exports.WA_ADV_DEVICE_SIG_PREFIX = exports.WA_ADV_ACCOUNT_SIG_PREFIX = exports.PHONE_CONNECTION_CB = exports.DEF_TAG_PREFIX = exports.DEF_CALLBACK_PREFIX = exports.DEFAULT_ORIGIN = exports.UNAUTHORIZED_CODES = void 0;
7
7
  const WAProto_1 = require("../../WAProto");
8
8
  const libsignal_1 = require("../Signal/libsignal");
9
9
  const Utils_1 = require("../Utils");
@@ -14,6 +14,10 @@ exports.DEFAULT_ORIGIN = 'https://web.whatsapp.com';
14
14
  exports.DEF_CALLBACK_PREFIX = 'CB:';
15
15
  exports.DEF_TAG_PREFIX = 'TAG:';
16
16
  exports.PHONE_CONNECTION_CB = 'CB:Pong';
17
+ exports.WA_ADV_ACCOUNT_SIG_PREFIX = Buffer.from([6, 0]);
18
+ exports.WA_ADV_DEVICE_SIG_PREFIX = Buffer.from([6, 1]);
19
+ exports.WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX = Buffer.from([6, 5]);
20
+ exports.WA_ADV_HOSTED_DEVICE_SIG_PREFIX = Buffer.from([6, 6]);
17
21
  exports.WA_DEFAULT_EPHEMERAL = 7 * 24 * 60 * 60;
18
22
  exports.NOISE_MODE = 'Noise_XX_25519_AESGCM_SHA256\0\0\0\0';
19
23
  exports.DICT_VERSION = 3;
@@ -18,9 +18,11 @@ export declare const makeBusinessSocket: (config: SocketConfig) => {
18
18
  sendMessageAck: ({ tag, attrs, content }: BinaryNode, errorCode?: number) => Promise<void>;
19
19
  sendRetryRequest: (node: BinaryNode, forceIncludeKeys?: boolean) => Promise<void>;
20
20
  rejectCall: (callId: string, callFrom: string) => Promise<void>;
21
- fetchMessageHistory: (count: number, oldestMsgKey: import("../Types").WAMessageKey, oldestMsgTimestamp: number | import("long").default) => Promise<string>;
21
+ fetchMessageHistory: (count: number, oldestMsgKey: import("../Types").WAMessageKey, oldestMsgTimestamp: number | Long) => Promise<string>;
22
+ fetchNewChatMessageCap: () => Promise<import("../Types").NewChatMessageCapInfo>;
23
+ fetchAccountReachoutTimelock: () => Promise<import("../Types").ReachoutTimelockState>;
22
24
  requestPlaceholderResend: (messageKey: import("../Types").WAMessageKey) => Promise<string | undefined>;
23
- getPrivacyTokens: (jids: string[]) => Promise<any>;
25
+ getPrivacyTokens: (jids: string[], timestamp?: number) => Promise<any>;
24
26
  assertSessions: (jids: string[], force: boolean, lids?: string) => Promise<boolean>;
25
27
  relayMessage: (jid: string, message: import("../Types").WAProto.IMessage, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, isretry }: import("../Types").MessageRelayOptions) => Promise<string>;
26
28
  sendReceipt: (jid: string, participant: string | undefined, messageIds: string[], type: import("../Types").MessageReceiptType) => Promise<void>;
@@ -39,6 +41,29 @@ export declare const makeBusinessSocket: (config: SocketConfig) => {
39
41
  getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<import("../WABinary").JidWithDevice[]>;
40
42
  updateMediaMessage: (message: import("../Types").WAProto.IWebMessageInfo) => Promise<import("../Types").WAProto.IWebMessageInfo>;
41
43
  sendMessage: (jid: string, content: import("../Types").AnyMessageContent, options?: import("../Types").MiscMessageGenerationOptions) => Promise<import("../Types").WAProto.WebMessageInfo | undefined>;
44
+ newsletterCreate: (name: string, description?: string) => Promise<import("../Types").NewsletterMetadata>;
45
+ newsletterUpdate: (jid: string, updates: import("../Types").NewsletterUpdate) => Promise<unknown>;
46
+ newsletterSubscribers: (jid: string) => Promise<{
47
+ subscribers: number;
48
+ }>;
49
+ newsletterMetadata: (type: "invite" | "jid", key: string) => Promise<import("../Types").NewsletterMetadata | null>;
50
+ newsletterFollow: (jid: string) => Promise<unknown>;
51
+ newsletterUnfollow: (jid: string) => Promise<unknown>;
52
+ newsletterMute: (jid: string) => Promise<unknown>;
53
+ newsletterUnmute: (jid: string) => Promise<unknown>;
54
+ newsletterUpdateName: (jid: string, name: string) => Promise<unknown>;
55
+ newsletterUpdateDescription: (jid: string, description: string) => Promise<unknown>;
56
+ newsletterUpdatePicture: (jid: string, content: import("../Types").WAMediaUpload) => Promise<unknown>;
57
+ newsletterRemovePicture: (jid: string) => Promise<unknown>;
58
+ newsletterReactMessage: (jid: string, serverId: string, reaction?: string) => Promise<void>;
59
+ newsletterFetchMessages: (jid: string, count: number, since: number, after: number) => Promise<any>;
60
+ subscribeNewsletterUpdates: (jid: string) => Promise<{
61
+ duration: string;
62
+ } | null>;
63
+ newsletterAdminCount: (jid: string) => Promise<number>;
64
+ newsletterChangeOwner: (jid: string, newOwnerJid: string) => Promise<void>;
65
+ newsletterDemote: (jid: string, userJid: string) => Promise<void>;
66
+ newsletterDelete: (jid: string) => Promise<void>;
42
67
  groupMetadata: (jid: string) => Promise<import("../Types").GroupMetadata>;
43
68
  groupCreate: (subject: string, participants: string[]) => Promise<import("../Types").GroupMetadata>;
44
69
  groupLeave: (id: string) => Promise<void>;
@@ -85,6 +85,8 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
85
85
  uploadPreKeys: (count?: number) => Promise<void>;
86
86
  uploadPreKeysToServerIfRequired: () => Promise<void>;
87
87
  requestPairingCode: (phoneNumber: string, customPairingCode?: string) => Promise<string>;
88
+ fetchAccountReachoutTimelock: () => Promise<import("../Types").ReachoutTimelockState>;
89
+ fetchNewChatMessageCap: () => Promise<import("../Types").NewChatMessageCapInfo>;
88
90
  waitForConnectionUpdate: (check: (u: Partial<import("../Types").ConnectionState>) => Promise<boolean | undefined>, timeoutMs?: number) => Promise<void>;
89
91
  sendWAMBuffer: (wamBuffer: Buffer) => Promise<any>;
90
92
  };
@@ -537,38 +537,6 @@ const makeChatsSocket = (config) => {
537
537
  ]
538
538
  : undefined
539
539
  });
540
- const handlePresenceUpdate = ({ tag, attrs, content }) => {
541
- var _a;
542
- let presence;
543
- const jid = attrs.from;
544
- const participant = attrs.participant || attrs.from;
545
- if (shouldIgnoreJid(jid) && jid !== '@s.whatsapp.net') {
546
- return;
547
- }
548
- if (tag === 'presence') {
549
- presence = {
550
- lastKnownPresence: attrs.type === 'unavailable' ? 'unavailable' : 'available',
551
- lastSeen: attrs.last && attrs.last !== 'deny' ? +attrs.last : undefined
552
- };
553
- }
554
- else if (Array.isArray(content)) {
555
- const [firstChild] = content;
556
- let type = firstChild.tag;
557
- if (type === 'paused') {
558
- type = 'available';
559
- }
560
- if (((_a = firstChild.attrs) === null || _a === void 0 ? void 0 : _a.media) === 'audio') {
561
- type = 'recording';
562
- }
563
- presence = { lastKnownPresence: type };
564
- }
565
- else {
566
- logger.error({ tag, attrs, content }, 'recv invalid presence node');
567
- }
568
- if (presence) {
569
- ev.emit('presence.update', { id: jid, presences: { [participant]: presence } });
570
- }
571
- };
572
540
  const appPatch = async (patchCreate) => {
573
541
  const name = patchCreate.type;
574
542
  const myAppStateKeyId = authState.creds.myAppStateKeyId;
@@ -635,15 +603,15 @@ const makeChatsSocket = (config) => {
635
603
  tag: 'iq',
636
604
  attrs: {
637
605
  to: WABinary_1.S_WHATSAPP_NET,
638
- xmlns: 'w',
606
+ xmlns: 'abt',
639
607
  type: 'get'
640
608
  },
641
609
  content: [
642
610
  {
643
611
  tag: 'props',
644
612
  attrs: {
645
- protocol: '2',
646
- hash: ((_a = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _a === void 0 ? void 0 : _a.lastPropHash) || ''
613
+ protocol: '1',
614
+ ...(((_a = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _a === void 0 ? void 0 : _a.lastPropHash) ? { hash: authState.creds.lastPropHash } : {})
647
615
  }
648
616
  }
649
617
  ]
@@ -793,7 +761,7 @@ const makeChatsSocket = (config) => {
793
761
  keyStore: authState.keys,
794
762
  logger,
795
763
  options: config.options
796
- })
764
+ }, authState)
797
765
  ]);
798
766
  if (((_c = (_b = msg.message) === null || _b === void 0 ? void 0 : _b.protocolMessage) === null || _c === void 0 ? void 0 : _c.appStateSyncKeyShare) && pendingAppStateSync) {
799
767
  await doAppStateSync();
@@ -812,8 +780,6 @@ const makeChatsSocket = (config) => {
812
780
  }
813
781
  }
814
782
  });
815
- ws.on('CB:presence', handlePresenceUpdate);
816
- ws.on('CB:chatstate', handlePresenceUpdate);
817
783
  ws.on('CB:ib,,dirty', async (node) => {
818
784
  const { attrs } = (0, WABinary_1.getBinaryNodeChild)(node, 'dirty');
819
785
  const type = attrs.type;
@@ -125,6 +125,8 @@ export declare const makeGroupsSocket: (config: SocketConfig) => {
125
125
  uploadPreKeys: (count?: number) => Promise<void>;
126
126
  uploadPreKeysToServerIfRequired: () => Promise<void>;
127
127
  requestPairingCode: (phoneNumber: string, customPairingCode?: string) => Promise<string>;
128
+ fetchAccountReachoutTimelock: () => Promise<import("../Types").ReachoutTimelockState>;
129
+ fetchNewChatMessageCap: () => Promise<import("../Types").NewChatMessageCapInfo>;
128
130
  waitForConnectionUpdate: (check: (u: Partial<import("../Types").ConnectionState>) => Promise<boolean | undefined>, timeoutMs?: number) => Promise<void>;
129
131
  sendWAMBuffer: (wamBuffer: Buffer) => Promise<any>;
130
132
  };
@@ -17,9 +17,11 @@ declare const makeWASocket: (config: UserFacingSocketConfig) => {
17
17
  sendMessageAck: ({ tag, attrs, content }: import("..").BinaryNode, errorCode?: number) => Promise<void>;
18
18
  sendRetryRequest: (node: import("..").BinaryNode, forceIncludeKeys?: boolean) => Promise<void>;
19
19
  rejectCall: (callId: string, callFrom: string) => Promise<void>;
20
- fetchMessageHistory: (count: number, oldestMsgKey: import("../Types").WAMessageKey, oldestMsgTimestamp: number | import("long").default) => Promise<string>;
20
+ fetchMessageHistory: (count: number, oldestMsgKey: import("../Types").WAMessageKey, oldestMsgTimestamp: number | Long) => Promise<string>;
21
+ fetchNewChatMessageCap: () => Promise<import("../Types").NewChatMessageCapInfo>;
22
+ fetchAccountReachoutTimelock: () => Promise<import("../Types").ReachoutTimelockState>;
21
23
  requestPlaceholderResend: (messageKey: import("../Types").WAMessageKey) => Promise<string | undefined>;
22
- getPrivacyTokens: (jids: string[]) => Promise<any>;
24
+ getPrivacyTokens: (jids: string[], timestamp?: number) => Promise<any>;
23
25
  assertSessions: (jids: string[], force: boolean, lids?: string) => Promise<boolean>;
24
26
  relayMessage: (jid: string, message: import("../Types").WAProto.IMessage, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, isretry }: import("../Types").MessageRelayOptions) => Promise<string>;
25
27
  sendReceipt: (jid: string, participant: string | undefined, messageIds: string[], type: import("../Types").MessageReceiptType) => Promise<void>;
@@ -38,6 +40,29 @@ declare const makeWASocket: (config: UserFacingSocketConfig) => {
38
40
  getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<import("..").JidWithDevice[]>;
39
41
  updateMediaMessage: (message: import("../Types").WAProto.IWebMessageInfo) => Promise<import("../Types").WAProto.IWebMessageInfo>;
40
42
  sendMessage: (jid: string, content: import("../Types").AnyMessageContent, options?: import("../Types").MiscMessageGenerationOptions) => Promise<import("../Types").WAProto.WebMessageInfo | undefined>;
43
+ newsletterCreate: (name: string, description?: string) => Promise<import("../Types").NewsletterMetadata>;
44
+ newsletterUpdate: (jid: string, updates: import("../Types").NewsletterUpdate) => Promise<unknown>;
45
+ newsletterSubscribers: (jid: string) => Promise<{
46
+ subscribers: number;
47
+ }>;
48
+ newsletterMetadata: (type: "invite" | "jid", key: string) => Promise<import("../Types").NewsletterMetadata | null>;
49
+ newsletterFollow: (jid: string) => Promise<unknown>;
50
+ newsletterUnfollow: (jid: string) => Promise<unknown>;
51
+ newsletterMute: (jid: string) => Promise<unknown>;
52
+ newsletterUnmute: (jid: string) => Promise<unknown>;
53
+ newsletterUpdateName: (jid: string, name: string) => Promise<unknown>;
54
+ newsletterUpdateDescription: (jid: string, description: string) => Promise<unknown>;
55
+ newsletterUpdatePicture: (jid: string, content: import("../Types").WAMediaUpload) => Promise<unknown>;
56
+ newsletterRemovePicture: (jid: string) => Promise<unknown>;
57
+ newsletterReactMessage: (jid: string, serverId: string, reaction?: string) => Promise<void>;
58
+ newsletterFetchMessages: (jid: string, count: number, since: number, after: number) => Promise<any>;
59
+ subscribeNewsletterUpdates: (jid: string) => Promise<{
60
+ duration: string;
61
+ } | null>;
62
+ newsletterAdminCount: (jid: string) => Promise<number>;
63
+ newsletterChangeOwner: (jid: string, newOwnerJid: string) => Promise<void>;
64
+ newsletterDemote: (jid: string, userJid: string) => Promise<void>;
65
+ newsletterDelete: (jid: string) => Promise<void>;
41
66
  groupMetadata: (jid: string) => Promise<import("../Types").GroupMetadata>;
42
67
  groupCreate: (subject: string, participants: string[]) => Promise<import("../Types").GroupMetadata>;
43
68
  groupLeave: (id: string) => Promise<void>;
@@ -1,15 +1,17 @@
1
1
  import { Boom } from '@hapi/boom';
2
2
  import Long = require('long');
3
3
  import { proto } from '../../WAProto';
4
- import { MessageReceiptType, MessageRelayOptions, SocketConfig, WAMessageKey } from '../Types';
4
+ import { MessageReceiptType, MessageRelayOptions, SocketConfig, WAMessageKey, WAPresence } from '../Types';
5
5
  import { BinaryNode } from '../WABinary';
6
6
  export declare const makeMessagesRecvSocket: (config: SocketConfig) => {
7
7
  sendMessageAck: ({ tag, attrs, content }: BinaryNode, errorCode?: number) => Promise<void>;
8
8
  sendRetryRequest: (node: BinaryNode, forceIncludeKeys?: boolean) => Promise<void>;
9
9
  rejectCall: (callId: string, callFrom: string) => Promise<void>;
10
10
  fetchMessageHistory: (count: number, oldestMsgKey: WAMessageKey, oldestMsgTimestamp: number | Long) => Promise<string>;
11
+ fetchNewChatMessageCap: () => Promise<import("../Types").NewChatMessageCapInfo>;
12
+ fetchAccountReachoutTimelock: () => Promise<import("../Types").ReachoutTimelockState>;
11
13
  requestPlaceholderResend: (messageKey: WAMessageKey) => Promise<string | undefined>;
12
- getPrivacyTokens: (jids: string[]) => Promise<any>;
14
+ getPrivacyTokens: (jids: string[], timestamp?: number) => Promise<any>;
13
15
  assertSessions: (jids: string[], force: boolean, lids?: string) => Promise<boolean>;
14
16
  relayMessage: (jid: string, message: proto.IMessage, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, isretry }: MessageRelayOptions) => Promise<string>;
15
17
  sendReceipt: (jid: string, participant: string | undefined, messageIds: string[], type: MessageReceiptType) => Promise<void>;
@@ -28,6 +30,29 @@ export declare const makeMessagesRecvSocket: (config: SocketConfig) => {
28
30
  getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<import("../WABinary").JidWithDevice[]>;
29
31
  updateMediaMessage: (message: proto.IWebMessageInfo) => Promise<proto.IWebMessageInfo>;
30
32
  sendMessage: (jid: string, content: import("../Types").AnyMessageContent, options?: import("../Types").MiscMessageGenerationOptions) => Promise<proto.WebMessageInfo | undefined>;
33
+ newsletterCreate: (name: string, description?: string) => Promise<import("../Types").NewsletterMetadata>;
34
+ newsletterUpdate: (jid: string, updates: import("../Types").NewsletterUpdate) => Promise<unknown>;
35
+ newsletterSubscribers: (jid: string) => Promise<{
36
+ subscribers: number;
37
+ }>;
38
+ newsletterMetadata: (type: "invite" | "jid", key: string) => Promise<import("../Types").NewsletterMetadata | null>;
39
+ newsletterFollow: (jid: string) => Promise<unknown>;
40
+ newsletterUnfollow: (jid: string) => Promise<unknown>;
41
+ newsletterMute: (jid: string) => Promise<unknown>;
42
+ newsletterUnmute: (jid: string) => Promise<unknown>;
43
+ newsletterUpdateName: (jid: string, name: string) => Promise<unknown>;
44
+ newsletterUpdateDescription: (jid: string, description: string) => Promise<unknown>;
45
+ newsletterUpdatePicture: (jid: string, content: import("../Types").WAMediaUpload) => Promise<unknown>;
46
+ newsletterRemovePicture: (jid: string) => Promise<unknown>;
47
+ newsletterReactMessage: (jid: string, serverId: string, reaction?: string) => Promise<void>;
48
+ newsletterFetchMessages: (jid: string, count: number, since: number, after: number) => Promise<any>;
49
+ subscribeNewsletterUpdates: (jid: string) => Promise<{
50
+ duration: string;
51
+ } | null>;
52
+ newsletterAdminCount: (jid: string) => Promise<number>;
53
+ newsletterChangeOwner: (jid: string, newOwnerJid: string) => Promise<void>;
54
+ newsletterDemote: (jid: string, userJid: string) => Promise<void>;
55
+ newsletterDelete: (jid: string) => Promise<void>;
31
56
  groupMetadata: (jid: string) => Promise<import("../Types").GroupMetadata>;
32
57
  groupCreate: (subject: string, participants: string[]) => Promise<import("../Types").GroupMetadata>;
33
58
  groupLeave: (id: string) => Promise<void>;
@@ -66,7 +91,7 @@ export declare const makeMessagesRecvSocket: (config: SocketConfig) => {
66
91
  };
67
92
  upsertMessage: (msg: import("../Types").WAMessage, type: import("../Types").MessageUpsertType) => Promise<void>;
68
93
  appPatch: (patchCreate: import("../Types").WAPatchCreate) => Promise<void>;
69
- sendPresenceUpdate: (type: import("../Types").WAPresence, toJid?: string) => Promise<void>;
94
+ sendPresenceUpdate: (type: WAPresence, toJid?: string) => Promise<void>;
70
95
  presenceSubscribe: (toJid: string, tcToken?: Buffer) => Promise<void>;
71
96
  profilePictureUrl: (jid: string, type?: "preview" | "image", timeoutMs?: number) => Promise<string | undefined>;
72
97
  onWhatsApp: (...jids: string[]) => Promise<{
@@ -18,7 +18,7 @@ const messages_send_1 = require("./messages-send");
18
18
  const makeMessagesRecvSocket = (config) => {
19
19
  const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config;
20
20
  const sock = (0, messages_send_1.makeMessagesSocket)(config);
21
- const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage } = sock;
21
+ const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, fetchAccountReachoutTimelock, fetchNewChatMessageCap } = sock;
22
22
  /** this mutex ensures that each retryRequest will wait for the previous one to finish */
23
23
  const retryMutex = (0, make_mutex_1.makeMutex)();
24
24
  const msgRetryCache = config.msgRetryCounterCache ||
@@ -87,7 +87,7 @@ const makeMessagesRecvSocket = (config) => {
87
87
  await query(stanza);
88
88
  };
89
89
  const sendRetryRequest = async (node, forceIncludeKeys = false) => {
90
- const { fullMessage } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '');
90
+ const { fullMessage, author } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '');
91
91
  const { key: msgKey } = fullMessage;
92
92
  const msgId = msgKey.id;
93
93
  const key = `${msgId}:${msgKey === null || msgKey === void 0 ? void 0 : msgKey.participant}`;
@@ -138,7 +138,8 @@ const makeMessagesRecvSocket = (config) => {
138
138
  if (node.attrs.participant) {
139
139
  receipt.attrs.participant = node.attrs.participant;
140
140
  }
141
- if (retryCount > 1 || forceIncludeKeys) {
141
+ if (retryCount <= 2 && forceIncludeKeys) {
142
+ await assertSessions([(0, WABinary_1.jidNormalizedUser)(author)], true);
142
143
  const { update, preKeys } = await (0, Utils_1.getNextPreKeys)(authState, 1);
143
144
  const [keyId] = Object.keys(preKeys);
144
145
  const key = preKeys[+keyId];
@@ -293,6 +294,7 @@ const makeMessagesRecvSocket = (config) => {
293
294
  const from = (0, WABinary_1.jidNormalizedUser)(node.attrs.from);
294
295
  switch (nodeType) {
295
296
  case 'privacy_token':
297
+ await handlePrivacyTokenNotification(node);
296
298
  const tokenList = (0, WABinary_1.getBinaryNodeChildren)(child, 'token');
297
299
  for (const { attrs, content } of tokenList) {
298
300
  const jid = attrs.jid;
@@ -442,6 +444,32 @@ const makeMessagesRecvSocket = (config) => {
442
444
  });
443
445
  authState.creds.registered = true;
444
446
  ev.emit('creds.update', authState.creds);
447
+ break;
448
+ case 'passkey_prologue_request': {
449
+ const optsNode = (0, WABinary_1.getBinaryNodeChild)(node, 'passkey_request_options');
450
+ let publicKey;
451
+ const content = optsNode === null || optsNode === void 0 ? void 0 : optsNode.content;
452
+ if (content instanceof Buffer || content instanceof Uint8Array) {
453
+ publicKey = content;
454
+ }
455
+ else if (typeof content === 'string') {
456
+ try {
457
+ publicKey = JSON.parse(content);
458
+ }
459
+ catch (_d) {
460
+ publicKey = Buffer.from(content, 'utf-8');
461
+ }
462
+ }
463
+ ev.emit('pair.passkey.request', { publicKey, raw: node });
464
+ logger.info('passkey_prologue_request — use WhatsApp Web + extensão');
465
+ break;
466
+ }
467
+ case 'crsc_continuation': {
468
+ const primaryNode = (0, WABinary_1.getBinaryNodeChild)(node, 'primary_ephemeral_identity');
469
+ ev.emit('pair.passkey.confirmation', { raw: node });
470
+ logger.info({ hasPrimary: !!primaryNode }, 'passkey continuation (crsc_continuation)');
471
+ break;
472
+ }
445
473
  }
446
474
  if (Object.keys(result).length) {
447
475
  return result;
@@ -514,7 +542,7 @@ const makeMessagesRecvSocket = (config) => {
514
542
  fromMe,
515
543
  participant: attrs.participant
516
544
  };
517
- if (shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
545
+ if (remoteJid && shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
518
546
  logger.debug({ remoteJid }, 'ignoring receipt from jid');
519
547
  await sendMessageAck(node);
520
548
  return;
@@ -614,12 +642,21 @@ const makeMessagesRecvSocket = (config) => {
614
642
  }
615
643
  };
616
644
  const handleMessage = async (node) => {
617
- var _a, _b, _c;
645
+ var _a, _b, _c, _d, _e;
618
646
  if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== '@s.whatsapp.net') {
619
647
  logger.debug({ key: node.attrs.key }, 'ignored message');
620
648
  await sendMessageAck(node);
621
649
  return;
622
650
  }
651
+ const checkisValid = (0, WABinary_1.getBinaryNodeChild)(node, 'unavailable');
652
+ if (checkisValid && checkisValid.attrs.type === 'view_once') {
653
+ logger.debug({ key: node.attrs.key }, 'ignored msmsg viewOnce message');
654
+ const { fullMessage } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '');
655
+ fullMessage.viewOnce = true;
656
+ await upsertMessage(fullMessage, 'append');
657
+ await sendMessageAck(node);
658
+ return;
659
+ }
623
660
  const encNode = (0, WABinary_1.getBinaryNodeChild)(node, 'enc');
624
661
  // TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
625
662
  if (encNode && encNode.attrs.type === 'msmsg') {
@@ -655,6 +692,12 @@ const makeMessagesRecvSocket = (config) => {
655
692
  node.attrs.sender_pn) {
656
693
  ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
657
694
  }
695
+ if (msg.messageStubType === WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT) {
696
+ if (((_d = msg === null || msg === void 0 ? void 0 : msg.messageStubParameters) === null || _d === void 0 ? void 0 : _d[0]) === Utils_1.MISSING_KEYS_ERROR_TEXT ||
697
+ ((_e = msg.messageStubParameters) === null || _e === void 0 ? void 0 : _e[0]) === Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT) {
698
+ return sendMessageAck(node);
699
+ }
700
+ }
658
701
  try {
659
702
  await Promise.all([
660
703
  processingMutex.mutex(async () => {
@@ -671,7 +714,7 @@ const makeMessagesRecvSocket = (config) => {
671
714
  return;
672
715
  }
673
716
  const encNode = (0, WABinary_1.getBinaryNodeChild)(node, 'enc');
674
- await sendRetryRequest(node, !encNode);
717
+ await sendRetryRequest(node, true);
675
718
  if (retryRequestDelayMs) {
676
719
  await (0, Utils_1.delay)(retryRequestDelayMs);
677
720
  }
@@ -715,6 +758,7 @@ const makeMessagesRecvSocket = (config) => {
715
758
  ]);
716
759
  }
717
760
  catch (error) {
761
+ sendMessageAck(node);
718
762
  logger.error({ error, node }, 'error in handling message');
719
763
  }
720
764
  };
@@ -812,6 +856,40 @@ const makeMessagesRecvSocket = (config) => {
812
856
  ev.emit('call', [call]);
813
857
  await sendMessageAck(node);
814
858
  };
859
+ /** tracks message IDs that have already been retried for error 463 — prevents retry loops */
860
+ const tcTokenRetriedMsgIds = new Set();
861
+ /** tracks JIDs for which we have stored tctokens — used for periodic pruning */
862
+ const tcTokenKnownJids = new Set();
863
+ const retryMissingTcToken = async (key, msgId, jid) => {
864
+ if (!msgId || !jid || tcTokenRetriedMsgIds.has(msgId)) {
865
+ if (msgId && tcTokenRetriedMsgIds.has(msgId)) {
866
+ logger.warn({ msgId, from: jid }, 'error 463: already retried, giving up');
867
+ }
868
+ return false;
869
+ }
870
+ // Each entry auto-expires via setTimeout(60s), so the set
871
+ // is naturally bounded under normal conditions.
872
+ tcTokenRetriedMsgIds.add(msgId);
873
+ setTimeout(() => tcTokenRetriedMsgIds.delete(msgId), 60000);
874
+ const msg = await getMessage(key);
875
+ if (!msg) {
876
+ logger.warn({ msgId, from: jid }, 'error 463: no message found for retry');
877
+ return false;
878
+ }
879
+ try {
880
+ await (0, Utils_1.delay)(1500);
881
+ await relayMessage(jid, msg, {
882
+ messageId: msgId,
883
+ useUserDevicesCache: true
884
+ });
885
+ logger.info({ msgId, from: jid }, 'error 463 retry succeeded');
886
+ return true;
887
+ }
888
+ catch (retryErr) {
889
+ logger.warn({ msgId, err: retryErr === null || retryErr === void 0 ? void 0 : retryErr.message }, 'error 463 retry failed');
890
+ return false;
891
+ }
892
+ };
815
893
  const handleBadAck = async ({ attrs }) => {
816
894
  const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id };
817
895
  // WARNING: REFRAIN FROM ENABLING THIS FOR NOW. IT WILL CAUSE A LOOP
@@ -830,7 +908,41 @@ const makeMessagesRecvSocket = (config) => {
830
908
  // error in acknowledgement,
831
909
  // device could not display the message
832
910
  if (attrs.error) {
833
- logger.warn({ attrs }, 'received error in ack');
911
+ if (attrs.error === Utils_1.SERVER_ERROR_CODES.MissingTcToken) {
912
+ const reachoutTimeLock = await fetchAccountReachoutTimelock().catch(err => {
913
+ logger.warn({ err: err === null || err === void 0 ? void 0 : err.message }, 'failed to fetch reachout timelock after error 463');
914
+ return undefined;
915
+ });
916
+ await fetchNewChatMessageCap().catch(err => {
917
+ logger.debug({ err: err === null || err === void 0 ? void 0 : err.message }, 'failed to fetch new chat message cap after error 463');
918
+ });
919
+ if (reachoutTimeLock === null || reachoutTimeLock === void 0 ? void 0 : reachoutTimeLock.isActive) {
920
+ ev.emit('messages.update', [
921
+ {
922
+ key,
923
+ update: {
924
+ status: Types_1.WAMessageStatus.ERROR,
925
+ messageStubParameters: [attrs.error, Utils_1.ACCOUNT_RESTRICTED_TEXT]
926
+ }
927
+ }
928
+ ]);
929
+ return;
930
+ }
931
+ // Single retry: the original getPrivacyTokens IQ triggered token issuance.
932
+ // After a brief delay the server should have pushed a privacy_token
933
+ // notification, making the re-send succeed.
934
+ const msgId = attrs.id;
935
+ const jid = (0, WABinary_1.jidNormalizedUser)(attrs.from);
936
+ if (await retryMissingTcToken(key, msgId, jid)) {
937
+ return;
938
+ }
939
+ }
940
+ else if (attrs.error === Utils_1.SERVER_ERROR_CODES.SmaxInvalid) {
941
+ logger.warn({ msgId: attrs.id, from: attrs.from }, 'smax-invalid (479): stanza rejected by server — likely stale device session or malformed addressing');
942
+ }
943
+ else {
944
+ logger.warn({ attrs }, 'received error in ack');
945
+ }
834
946
  ev.emit('messages.update', [
835
947
  {
836
948
  key,
@@ -879,7 +991,10 @@ const makeMessagesRecvSocket = (config) => {
879
991
  }
880
992
  isProcessing = false;
881
993
  };
882
- promise().catch(error => onUnexpectedError(error, 'processing offline nodes'));
994
+ promise().catch(error => {
995
+ onUnexpectedError(error, 'processing offline nodes');
996
+ sendMessageAck(node);
997
+ });
883
998
  };
884
999
  return { enqueue };
885
1000
  };
@@ -1027,6 +1142,61 @@ const makeMessagesRecvSocket = (config) => {
1027
1142
  break;
1028
1143
  }
1029
1144
  }
1145
+ const handlePrivacyTokenNotification = async (node) => {
1146
+ const tokensNode = (0, WABinary_1.getBinaryNodeChild)(node, 'tokens');
1147
+ const from = (0, WABinary_1.jidNormalizedUser)(node.attrs.from);
1148
+ const issueTimestamp = (0, Utils_1.unixTimestampSeconds)();
1149
+ if (!tokensNode)
1150
+ return;
1151
+ const tokenNodes = (0, WABinary_1.getBinaryNodeChildren)(tokensNode, 'token');
1152
+ for (const tokenNode of tokenNodes) {
1153
+ const { attrs, content } = tokenNode;
1154
+ const type = attrs.type;
1155
+ const timestamp = attrs.t;
1156
+ if (type === 'trusted_contact' && content instanceof Buffer) {
1157
+ logger.debug({
1158
+ from,
1159
+ timestamp,
1160
+ tcToken: content
1161
+ }, 'received trusted contact token');
1162
+ await authState.keys.set({
1163
+ 'contacts-tc-token': { [from]: { token: content, timestamp, senderTimestamp: issueTimestamp } }
1164
+ });
1165
+ }
1166
+ }
1167
+ };
1168
+ const handlePresenceUpdate = ({ tag, attrs, content }) => {
1169
+ var _a;
1170
+ let presence;
1171
+ const jid = attrs.from;
1172
+ const participant = attrs.participant || attrs.from;
1173
+ if (shouldIgnoreJid(jid)) {
1174
+ return;
1175
+ }
1176
+ if (tag === 'presence') {
1177
+ presence = {
1178
+ lastKnownPresence: attrs.type === 'unavailable' ? 'unavailable' : 'available',
1179
+ lastSeen: attrs.last && attrs.last !== 'deny' ? +attrs.last : undefined
1180
+ };
1181
+ }
1182
+ else if (Array.isArray(content)) {
1183
+ const [firstChild] = content;
1184
+ let type = firstChild.tag;
1185
+ if (type === 'paused') {
1186
+ type = 'available';
1187
+ }
1188
+ if (((_a = firstChild.attrs) === null || _a === void 0 ? void 0 : _a.media) === 'audio') {
1189
+ type = 'recording';
1190
+ }
1191
+ presence = { lastKnownPresence: type };
1192
+ }
1193
+ else {
1194
+ logger.error({ tag, attrs, content }, 'recv invalid presence node');
1195
+ }
1196
+ if (presence) {
1197
+ ev.emit('presence.update', { id: jid, presences: { [participant]: presence } });
1198
+ }
1199
+ };
1030
1200
  // recv a message
1031
1201
  ws.on('CB:message', (node) => {
1032
1202
  processNode('message', node, 'processing message', handleMessage);
@@ -1043,6 +1213,8 @@ const makeMessagesRecvSocket = (config) => {
1043
1213
  ws.on('CB:ack,class:message', (node) => {
1044
1214
  handleBadAck(node).catch(error => onUnexpectedError(error, 'handling bad ack'));
1045
1215
  });
1216
+ ws.on('CB:presence', handlePresenceUpdate);
1217
+ ws.on('CB:chatstate', handlePresenceUpdate);
1046
1218
  ev.on('call', ([call]) => {
1047
1219
  // missed call + group call notification message generation
1048
1220
  if (call.status === 'timeout' || (call.status === 'offer' && call.isGroup)) {
@@ -1083,6 +1255,8 @@ const makeMessagesRecvSocket = (config) => {
1083
1255
  sendRetryRequest,
1084
1256
  rejectCall,
1085
1257
  fetchMessageHistory,
1258
+ fetchNewChatMessageCap,
1259
+ fetchAccountReachoutTimelock,
1086
1260
  requestPlaceholderResend
1087
1261
  };
1088
1262
  };