@ryuu-reinzz/baileys 3.5.1 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +30 -25
  2. package/WAProto/fix-imports.js +22 -18
  3. package/WAProto/index.js +22 -18
  4. package/lib/Defaults/index.js +10 -9
  5. package/lib/Signal/libsignal.js +45 -17
  6. package/lib/Signal/lid-mapping.js +6 -0
  7. package/lib/Socket/chats.js +241 -39
  8. package/lib/Socket/groups.js +20 -0
  9. package/lib/Socket/messages-recv.js +736 -314
  10. package/lib/Socket/messages-send.js +279 -129
  11. package/lib/Socket/newsletter.js +2 -2
  12. package/lib/Socket/socket.js +56 -25
  13. package/lib/Types/{Newsletter.js → Mex.js} +9 -3
  14. package/lib/Types/State.js +43 -0
  15. package/lib/Types/index.js +1 -1
  16. package/lib/Utils/auth-utils.js +12 -0
  17. package/lib/Utils/chat-utils.js +80 -20
  18. package/lib/Utils/companion-reg-client-utils.js +35 -0
  19. package/lib/Utils/decode-wa-message.js +34 -0
  20. package/lib/Utils/event-buffer.js +49 -1
  21. package/lib/Utils/generics.js +12 -3
  22. package/lib/Utils/history.js +12 -9
  23. package/lib/Utils/identity-change-handler.js +1 -0
  24. package/lib/Utils/index.js +3 -1
  25. package/lib/Utils/link-preview.js +2 -2
  26. package/lib/Utils/message-retry-manager.js +40 -0
  27. package/lib/Utils/messages-media.js +21 -7
  28. package/lib/Utils/messages.js +28 -5
  29. package/lib/Utils/offline-node-processor.js +40 -0
  30. package/lib/Utils/process-message.js +103 -1
  31. package/lib/Utils/signal.js +42 -0
  32. package/lib/Utils/stanza-ack.js +38 -0
  33. package/lib/Utils/sync-action-utils.js +1 -0
  34. package/lib/Utils/tc-token-utils.js +149 -4
  35. package/lib/Utils/validate-connection.js +3 -0
  36. package/lib/WAUSync/Protocols/USyncContactProtocol.js +26 -3
  37. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  38. package/lib/WAUSync/Protocols/index.js +1 -0
  39. package/lib/WAUSync/USyncQuery.js +6 -2
  40. package/lib/WAUSync/USyncUser.js +8 -0
  41. package/package.json +39 -12
package/README.md CHANGED
@@ -56,18 +56,23 @@ To run the example script, download or clone the repo and then type the followin
56
56
 
57
57
  Use the stable version:
58
58
  ```
59
- yarn add @ryuu-reinzz/baileys
59
+ yarn add @whiskeysockets/baileys
60
+ ```
61
+
62
+ Use the edge version (no guarantee of stability, but latest fixes + features)
63
+ ```
64
+ yarn add github:WhiskeySockets/Baileys
60
65
  ```
61
66
 
62
67
  Then import your code using:
63
68
  ```ts
64
- import makeWASocket from '@ryuu-reinzz/baileys'
69
+ import makeWASocket from '@whiskeysockets/baileys'
65
70
  ```
66
71
 
67
72
  # Links
68
73
 
69
74
  - [Discord](https://discord.gg/WeJM5FP9GG)
70
- - [Docs](https://guide.whiskeysockets.io/)
75
+ - [Docs](https://baileys.wiki/docs/intro/)
71
76
 
72
77
  # Index
73
78
 
@@ -182,15 +187,15 @@ WhatsApp provides a multi-device API that allows Baileys to be authenticated as
182
187
  > **[Here](#example-to-start) is a simple example of event handling**
183
188
 
184
189
  > [!TIP]
185
- > **You can see all supported socket configs [here](https://baileys.whiskeysockets.io/types/SocketConfig.html) (Recommended)**
190
+ > **You can see all supported socket configs in the [SocketConfig type alias](https://baileys.wiki/docs/api/type-aliases/SocketConfig/) (Recommended)**
186
191
 
187
192
  ### Starting socket with **QR-CODE**
188
193
 
189
194
  > [!TIP]
190
- > 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)**
195
+ > You can customize browser name if you connect with **QR-CODE**, with `Browser` constant, we have some browsers config, **see the [BrowsersMap type alias](https://baileys.wiki/docs/api/type-aliases/BrowsersMap/)**
191
196
 
192
197
  ```ts
193
- import makeWASocket from '@ryuu-reinzz/baileys'
198
+ import makeWASocket from '@whiskeysockets/baileys'
194
199
 
195
200
  const sock = makeWASocket({
196
201
  // can provide additional config here
@@ -210,7 +215,7 @@ If the connection is successful, you will see a QR code printed on your terminal
210
215
  The phone number can't have `+` or `()` or `-`, only numbers, you must provide country code
211
216
 
212
217
  ```ts
213
- import makeWASocket from '@ryuu-reinzz/baileys'
218
+ import makeWASocket from '@whiskeysockets/baileys'
214
219
 
215
220
  const sock = makeWASocket({
216
221
  // can provide additional config here
@@ -283,7 +288,7 @@ You obviously don't want to keep scanning the QR code every time you want to con
283
288
 
284
289
  So, you can load the credentials to log back in:
285
290
  ```ts
286
- import makeWASocket, { useMultiFileAuthState } from '@ryuu-reinzz/baileys'
291
+ import makeWASocket, { useMultiFileAuthState } from '@whiskeysockets/baileys'
287
292
 
288
293
  const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
289
294
 
@@ -307,7 +312,7 @@ sock.ev.on('creds.update', saveCreds)
307
312
  They're all nicely typed up, so you shouldn't have any issues with an Intellisense editor like VS Code.
308
313
 
309
314
  > [!IMPORTANT]
310
- > **The events are [these](https://baileys.whiskeysockets.io/types/BaileysEventMap.html)**, it's important you see all events
315
+ > **The events are in the [BaileysEventMap type alias](https://baileys.wiki/docs/api/type-aliases/BaileysEventMap/)**, it's important you see all events
311
316
 
312
317
  You can listen to these events like this:
313
318
  ```ts
@@ -326,7 +331,7 @@ sock.ev.on('messages.upsert', ({ messages }) => {
326
331
  > For reliable serialization of the authentication state, especially when storing as JSON, always use the BufferJSON utility.
327
332
 
328
333
  ```ts
329
- import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@ryuu-reinzz/baileys'
334
+ import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@whiskeysockets/baileys'
330
335
  import { Boom } from '@hapi/boom'
331
336
 
332
337
  async function connectToWhatsApp () {
@@ -408,7 +413,7 @@ sock.ev.on('messages.update', event => {
408
413
  It can be used as follows:
409
414
 
410
415
  ```ts
411
- import makeWASocket, { makeInMemoryStore } from '@ryuu-reinzz/baileys'
416
+ import makeWASocket, { makeInMemoryStore } from '@whiskeysockets/baileys'
412
417
  // the store maintains the data of the WA connection in memory
413
418
  // can be written out to a file & read from it
414
419
  const store = makeInMemoryStore({ })
@@ -457,8 +462,8 @@ The store also provides some simple functions such as `loadMessages` that utiliz
457
462
  ## Sending Messages
458
463
 
459
464
  - Send all types of messages with a single function
460
- - **[Here](https://baileys.whiskeysockets.io/types/AnyMessageContent.html) you can see all message contents supported, like text message**
461
- - **[Here](https://baileys.whiskeysockets.io/types/MiscMessageGenerationOptions.html) you can see all options supported, like quote message**
465
+ - **In the [AnyMessageContent type alias](https://baileys.wiki/docs/api/type-aliases/AnyMessageContent/) you can see all message contents supported, like text message**
466
+ - **In the [MiscMessageGenerationOptions type alias](https://baileys.wiki/docs/api/type-aliases/MiscMessageGenerationOptions/) you can see all options supported, like quote message**
462
467
 
463
468
  ```ts
464
469
  const jid: string
@@ -493,7 +498,7 @@ await sock.sendMessage(
493
498
  ```
494
499
 
495
500
  #### Forward Messages
496
- - You need to have message object, can be retrieved from [store](#implementing-a-data-store) or use a [message](https://baileys.whiskeysockets.io/types/WAMessage.html) object
501
+ - You need to have message object, can be retrieved from [store](#implementing-a-data-store) or use a [message](https://baileys.wiki/docs/api/type-aliases/WAMessage/) object
497
502
  ```ts
498
503
  const msg = getMessageFromStore() // implement this on your end
499
504
  await sock.sendMessage(jid, { forward: msg }) // WA forward the message!
@@ -532,7 +537,7 @@ await sock.sendMessage(
532
537
  ```
533
538
 
534
539
  #### Reaction Message
535
- - You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.whiskeysockets.io/types/WAMessageKey.html) object
540
+ - You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.wiki/docs/api/type-aliases/WAMessageKey/) object
536
541
  ```ts
537
542
  await sock.sendMessage(
538
543
  jid,
@@ -546,7 +551,7 @@ await sock.sendMessage(
546
551
  ```
547
552
 
548
553
  #### Pin Message
549
- - You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.whiskeysockets.io/types/WAMessageKey.html) object
554
+ - You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.wiki/docs/api/type-aliases/WAMessageKey/) object
550
555
 
551
556
  - Time can be:
552
557
 
@@ -594,7 +599,7 @@ await sock.sendMessage(
594
599
  await sock.sendMessage(
595
600
  jid,
596
601
  {
597
- text: 'Hi, this was sent using https://github.com/ryuu-reinzz/baileys'
602
+ text: 'Hi, this was sent using https://github.com/whiskeysockets/baileys'
598
603
  }
599
604
  )
600
605
  ```
@@ -604,7 +609,7 @@ await sock.sendMessage(
604
609
  Sending media (video, stickers, images) is easier & more efficient than ever.
605
610
 
606
611
  > [!NOTE]
607
- > In media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more [here](https://baileys.whiskeysockets.io/types/WAMediaUpload.html)
612
+ > In media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more in the [WAMediaUpload type alias](https://baileys.wiki/docs/api/type-aliases/WAMediaUpload/)
608
613
 
609
614
  - When specifying a media url, Baileys never loads the entire buffer into memory; it even encrypts the media as a readable stream.
610
615
 
@@ -724,7 +729,7 @@ await sock.sendMessage(jid, {
724
729
  If you want to save the media you received
725
730
  ```ts
726
731
  import { createWriteStream } from 'fs'
727
- import { downloadMediaMessage, getContentType } from '@ryuu-reinzz/baileys'
732
+ import { downloadMediaMessage, getContentType } from '@whiskeysockets/baileys'
728
733
 
729
734
  sock.ev.on('messages.upsert', async ({ [m] }) => {
730
735
  if (!m.message) return // if there is no text or media message
@@ -769,7 +774,7 @@ await sock.rejectCall(callId, callFrom)
769
774
  ## Send States in Chat
770
775
 
771
776
  ### Reading Messages
772
- - A set of message [keys](https://baileys.whiskeysockets.io/types/WAMessageKey.html) must be explicitly marked read now.
777
+ - A set of message [keys](https://baileys.wiki/docs/api/type-aliases/WAMessageKey/) must be explicitly marked read now.
773
778
  - You cannot mark an entire 'chat' read as it were with Baileys Web.
774
779
  This means you have to keep track of unread messages.
775
780
 
@@ -784,7 +789,7 @@ On a `WAMessage`, the `messageID` can be accessed using ```messageID = message.k
784
789
 
785
790
  ### Update Presence
786
791
 
787
- - ``` presence ``` can be one of [these](https://baileys.whiskeysockets.io/types/WAPresence.html)
792
+ - ``` presence ``` can be one of the values in the [WAPresence type alias](https://baileys.wiki/docs/api/type-aliases/WAPresence/)
788
793
  - The presence expires after about 10 seconds.
789
794
  - This lets the person/group with `jid` know whether you're online, offline, typing etc.
790
795
 
@@ -986,7 +991,7 @@ await sock.updateProfileName('My name')
986
991
  - To change your display picture or a group's
987
992
 
988
993
  > [!NOTE]
989
- > Like media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more [here](https://baileys.whiskeysockets.io/types/WAMediaUpload.html)
994
+ > Like media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more in the [WAMediaUpload type alias](https://baileys.wiki/docs/api/type-aliases/WAMediaUpload/)
990
995
 
991
996
  ```ts
992
997
  await sock.updateProfilePicture(jid, { url: './new-profile-picture.jpeg' })
@@ -1198,8 +1203,8 @@ await sock.sendMessage(
1198
1203
  }
1199
1204
  )
1200
1205
  ```
1201
- - Message body can be a `extendedTextMessage` or `imageMessage` or `videoMessage` or `voiceMessage`, see [here](https://baileys.whiskeysockets.io/types/AnyRegularMessageContent.html)
1202
- - You can add `backgroundColor` and other options in the message options, see [here](https://baileys.whiskeysockets.io/types/MiscMessageGenerationOptions.html)
1206
+ - Message body can be a `extendedTextMessage` or `imageMessage` or `videoMessage` or `voiceMessage`, see the [AnyRegularMessageContent type alias](https://baileys.wiki/docs/api/type-aliases/AnyRegularMessageContent/)
1207
+ - You can add `backgroundColor` and other options in the message options, see the [MiscMessageGenerationOptions type alias](https://baileys.wiki/docs/api/type-aliases/MiscMessageGenerationOptions/)
1203
1208
  - `broadcast: true` enables broadcast mode
1204
1209
  - `statusJidList`: a list of people that you can get which you need to provide, which are the people who will get this status message.
1205
1210
 
@@ -1283,7 +1288,7 @@ sock.ws.on('CB:edge_routing,id:abcd,routing_info', (node: BinaryNode) => { })
1283
1288
  ```
1284
1289
 
1285
1290
  # License
1286
- Copyright (c) 2025 RyuuReinzz
1291
+ Copyright (c) 2025 Rajeh Taher/WhiskeySockets
1287
1292
 
1288
1293
  Licensed under the MIT License:
1289
1294
  Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -18,14 +18,18 @@ try {
18
18
  '\tif (typeof value === "number") {\n' +
19
19
  '\t\treturn String(value);\n' +
20
20
  '\t}\n' +
21
- '\tif (!$util.Long) {\n' +
22
- '\t\treturn String(value);\n' +
21
+ '\t// Fast path: convert Long {low, high} directly via native BigInt\n' +
22
+ '\t// BigInt.toString() is a native C++ operation, much faster than Long\'s pure JS division loops\n' +
23
+ '\tif (value && typeof value.low === "number" && typeof value.high === "number") {\n' +
24
+ '\t\tconst lo = BigInt(value.low >>> 0);\n' +
25
+ '\t\tconst hi = BigInt(value.high >>> 0);\n' +
26
+ '\t\tconst combined = (hi << 32n) | lo;\n' +
27
+ '\t\tif (!unsigned && value.high < 0) {\n' +
28
+ '\t\t\treturn (combined - (1n << 64n)).toString();\n' +
29
+ '\t\t}\n' +
30
+ '\t\treturn combined.toString();\n' +
23
31
  '\t}\n' +
24
- '\tconst normalized = $util.Long.fromValue(value);\n' +
25
- '\tconst prepared = unsigned && normalized && typeof normalized.toUnsigned === "function"\n' +
26
- '\t\t? normalized.toUnsigned()\n' +
27
- '\t\t: normalized;\n' +
28
- '\treturn prepared.toString();\n' +
32
+ '\treturn String(value);\n' +
29
33
  '}\n\n'
30
34
  const longToNumberHelper =
31
35
  'function longToNumber(value, unsigned) {\n' +
@@ -33,19 +37,19 @@ try {
33
37
  '\t\treturn value;\n' +
34
38
  '\t}\n' +
35
39
  '\tif (typeof value === "string") {\n' +
36
- '\t\tconst numeric = Number(value);\n' +
37
- '\t\treturn numeric;\n' +
38
- '\t}\n' +
39
- '\tif (!$util.Long) {\n' +
40
40
  '\t\treturn Number(value);\n' +
41
41
  '\t}\n' +
42
- '\tconst normalized = $util.Long.fromValue(value);\n' +
43
- '\tconst prepared = unsigned && normalized && typeof normalized.toUnsigned === "function"\n' +
44
- '\t\t? normalized.toUnsigned()\n' +
45
- '\t\t: typeof normalized.toSigned === "function"\n' +
46
- '\t\t\t? normalized.toSigned()\n' +
47
- '\t\t\t: normalized;\n' +
48
- '\treturn prepared.toNumber();\n' +
42
+ '\t// Fast path: convert Long {low, high} directly via native BigInt\n' +
43
+ '\tif (value && typeof value.low === "number" && typeof value.high === "number") {\n' +
44
+ '\t\tconst lo = BigInt(value.low >>> 0);\n' +
45
+ '\t\tconst hi = BigInt(value.high >>> 0);\n' +
46
+ '\t\tconst combined = (hi << 32n) | lo;\n' +
47
+ '\t\tif (!unsigned && value.high < 0) {\n' +
48
+ '\t\t\treturn Number(combined - (1n << 64n));\n' +
49
+ '\t\t}\n' +
50
+ '\t\treturn Number(combined);\n' +
51
+ '\t}\n' +
52
+ '\treturn Number(value);\n' +
49
53
  '}\n\n'
50
54
 
51
55
  if (!content.includes('function longToString(')) {
package/WAProto/index.js CHANGED
@@ -12,14 +12,18 @@ function longToString(value, unsigned) {
12
12
  if (typeof value === "number") {
13
13
  return String(value);
14
14
  }
15
- if (!$util.Long) {
16
- return String(value);
15
+ // Fast path: convert Long {low, high} directly via native BigInt
16
+ // BigInt.toString() is a native C++ operation, much faster than Long's pure JS division loops
17
+ if (value && typeof value.low === "number" && typeof value.high === "number") {
18
+ const lo = BigInt(value.low >>> 0);
19
+ const hi = BigInt(value.high >>> 0);
20
+ const combined = (hi << 32n) | lo;
21
+ if (!unsigned && value.high < 0) {
22
+ return (combined - (1n << 64n)).toString();
23
+ }
24
+ return combined.toString();
17
25
  }
18
- const normalized = $util.Long.fromValue(value);
19
- const prepared = unsigned && normalized && typeof normalized.toUnsigned === "function"
20
- ? normalized.toUnsigned()
21
- : normalized;
22
- return prepared.toString();
26
+ return String(value);
23
27
  }
24
28
 
25
29
  function longToNumber(value, unsigned) {
@@ -27,19 +31,19 @@ function longToNumber(value, unsigned) {
27
31
  return value;
28
32
  }
29
33
  if (typeof value === "string") {
30
- const numeric = Number(value);
31
- return numeric;
32
- }
33
- if (!$util.Long) {
34
34
  return Number(value);
35
35
  }
36
- const normalized = $util.Long.fromValue(value);
37
- const prepared = unsigned && normalized && typeof normalized.toUnsigned === "function"
38
- ? normalized.toUnsigned()
39
- : typeof normalized.toSigned === "function"
40
- ? normalized.toSigned()
41
- : normalized;
42
- return prepared.toNumber();
36
+ // Fast path: convert Long {low, high} directly via native BigInt
37
+ if (value && typeof value.low === "number" && typeof value.high === "number") {
38
+ const lo = BigInt(value.low >>> 0);
39
+ const hi = BigInt(value.high >>> 0);
40
+ const combined = (hi << 32n) | lo;
41
+ if (!unsigned && value.high < 0) {
42
+ return Number(combined - (1n << 64n));
43
+ }
44
+ return Number(combined);
45
+ }
46
+ return Number(value);
43
47
  }
44
48
 
45
49
  export const proto = $root.proto = (() => {
@@ -2,7 +2,7 @@ import { proto } from '../../WAProto/index.js';
2
2
  import { makeLibSignalRepository } from '../Signal/libsignal.js';
3
3
  import { Browsers } from '../Utils/browser-utils.js';
4
4
  import logger from '../Utils/logger.js';
5
- const version = [2, 3000, 1033105955];
5
+ const version = [2, 3000, 1035194821];
6
6
  export const UNAUTHORIZED_CODES = [401, 403, 419];
7
7
  export const DEFAULT_ORIGIN = 'https://web.whatsapp.com';
8
8
  export const CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/';
@@ -39,9 +39,15 @@ export const PROCESSABLE_HISTORY_TYPES = [
39
39
  proto.HistorySync.HistorySyncType.NON_BLOCKING_DATA,
40
40
  proto.HistorySync.HistorySyncType.INITIAL_STATUS_V3
41
41
  ];
42
+ export const DEFAULT_CACHE_TTLS = {
43
+ SIGNAL_STORE: 5 * 60, // 5 minutes
44
+ MSG_RETRY: 60 * 60, // 1 hour
45
+ CALL_OFFER: 5 * 60, // 5 minutes
46
+ USER_DEVICES: 5 * 60 // 5 minutes
47
+ };
42
48
  export const DEFAULT_CONNECTION_CONFIG = {
43
49
  version: version,
44
- browser: Browsers.macOS('Chrome'),
50
+ browser: Browsers.macOS('Safari'),
45
51
  waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
46
52
  connectTimeoutMs: 20000,
47
53
  keepAliveIntervalMs: 30000,
@@ -109,16 +115,11 @@ export const MEDIA_HKDF_KEY_MAPPING = {
109
115
  'biz-cover-photo': 'Image'
110
116
  };
111
117
  export const MEDIA_KEYS = Object.keys(MEDIA_PATH_MAP);
118
+ /** 120s timeout for history sync stall detection, same as WA Web's handleChunkProgress / restartPausedTimer (g = 120) */
119
+ export const HISTORY_SYNC_PAUSED_TIMEOUT_MS = 120000;
112
120
  export const MIN_PREKEY_COUNT = 5;
113
121
  export const INITIAL_PREKEY_COUNT = 812;
114
122
  export const UPLOAD_TIMEOUT = 30000; // 30 seconds
115
- export const MIN_UPLOAD_INTERVAL = 5000; // 5 seconds minimum between uploads
116
- export const DEFAULT_CACHE_TTLS = {
117
- SIGNAL_STORE: 5 * 60, // 5 minutes
118
- MSG_RETRY: 60 * 60, // 1 hour
119
- CALL_OFFER: 5 * 60, // 5 minutes
120
- USER_DEVICES: 5 * 60 // 5 minutes
121
- };
122
123
  export const TimeMs = {
123
124
  Minute: 60 * 1000,
124
125
  Hour: 60 * 60 * 1000,
@@ -41,6 +41,16 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
41
41
  ttlAutopurge: true,
42
42
  updateAgeOnGet: true
43
43
  });
44
+ const ensureSenderKeyAndCreateSkdm = async (group, meId) => {
45
+ const senderName = jidToSignalSenderKeyName(group, meId);
46
+ const senderNameStr = senderName.toString();
47
+ const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr]);
48
+ if (!senderKey) {
49
+ await storage.storeSenderKey(senderName, new SenderKeyRecord());
50
+ }
51
+ const skdm = await new GroupSessionBuilder(storage).create(senderName);
52
+ return { senderName, skdm };
53
+ };
44
54
  const repository = {
45
55
  decryptGroupMessage({ group, authorJid, msg }) {
46
56
  const senderName = jidToSignalSenderKeyName(group, authorJid);
@@ -113,27 +123,43 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
113
123
  }, jid);
114
124
  },
115
125
  async encryptGroupMessage({ group, meId, data }) {
116
- const senderName = jidToSignalSenderKeyName(group, meId);
117
- const builder = new GroupSessionBuilder(storage);
118
- const senderNameStr = senderName.toString();
119
126
  return parsedKeys.transaction(async () => {
120
- const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr]);
121
- if (!senderKey) {
122
- await storage.storeSenderKey(senderName, new SenderKeyRecord());
123
- }
124
- const senderKeyDistributionMessage = await builder.create(senderName);
125
- const session = new GroupCipher(storage, senderName);
126
- const ciphertext = await session.encrypt(data);
127
- return {
128
- ciphertext,
129
- senderKeyDistributionMessage: senderKeyDistributionMessage.serialize()
130
- };
127
+ const { senderName, skdm } = await ensureSenderKeyAndCreateSkdm(group, meId);
128
+ const ciphertext = await new GroupCipher(storage, senderName).encrypt(data);
129
+ return { ciphertext, senderKeyDistributionMessage: skdm.serialize() };
131
130
  }, group);
132
131
  },
132
+ async getSenderKeyDistributionMessage({ group, meId }) {
133
+ return parsedKeys.transaction(async () => {
134
+ const { skdm } = await ensureSenderKeyAndCreateSkdm(group, meId);
135
+ return skdm.serialize();
136
+ }, group);
137
+ },
138
+ async hasSenderKey({ group, meId }) {
139
+ const senderName = jidToSignalSenderKeyName(group, meId).toString();
140
+ const { [senderName]: key } = await auth.keys.get('sender-key', [senderName]);
141
+ return !!key;
142
+ },
143
+ async getSessionInfo(jid) {
144
+ const addr = jidToSignalProtocolAddress(jid).toString();
145
+ const session = (await storage.loadSession(addr));
146
+ if (!session) {
147
+ return null;
148
+ }
149
+ const open = session.getOpenSession?.();
150
+ const baseKey = open?.indexInfo?.baseKey;
151
+ const registrationId = open?.registrationId;
152
+ if (!baseKey || typeof registrationId !== 'number') {
153
+ return null;
154
+ }
155
+ return { baseKey: new Uint8Array(baseKey), registrationId };
156
+ },
133
157
  async injectE2ESession({ jid, session }) {
134
158
  logger.trace({ jid }, 'injecting E2EE session');
135
159
  const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid));
136
160
  return parsedKeys.transaction(async () => {
161
+ // libsignal runtime accepts an absent prekey (initOutgoing checks `device.preKey && ...`)
162
+ // but the bundled .d.ts marks it required.
137
163
  await cipher.initOutgoing(session);
138
164
  }, jid);
139
165
  },
@@ -172,6 +198,10 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
172
198
  await auth.keys.set({ session: sessionUpdates });
173
199
  }, `delete-${jids.length}-sessions`);
174
200
  },
201
+ close() {
202
+ migratedSessionCache.clear();
203
+ lidMapping.close();
204
+ },
175
205
  async migrateSession(fromJid, toJid) {
176
206
  // TODO: use usync to handle this entire mess
177
207
  if (!fromJid || (!isLidUser(toJid) && !isHostedLidUser(toJid)))
@@ -342,9 +372,7 @@ function signalStorage({ creds, keys }, lidMapping) {
342
372
  saveIdentity: async (id, identityKey) => {
343
373
  const wireJid = await resolveLIDSignalAddress(id);
344
374
  const { [wireJid]: existingKey } = await keys.get('identity-key', [wireJid]);
345
- const keysMatch = existingKey &&
346
- existingKey.length === identityKey.length &&
347
- existingKey.every((byte, i) => byte === identityKey[i]);
375
+ const keysMatch = existingKey?.length === identityKey.length && existingKey.every((byte, i) => byte === identityKey[i]);
348
376
  if (existingKey && !keysMatch) {
349
377
  // Identity changed - clear session and update key
350
378
  await keys.set({
@@ -267,5 +267,11 @@ export class LIDMappingStore {
267
267
  }
268
268
  return Object.values(successfulPairs).length ? Object.values(successfulPairs) : null;
269
269
  }
270
+ /**
271
+ * Close the cache and release resources
272
+ */
273
+ close() {
274
+ this.mappingCache.clear();
275
+ }
270
276
  }
271
277
  //# sourceMappingURL=lid-mapping.js.map