@nerxa/socketon 0.0.0-stage → 1.21.0

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 (289) hide show
  1. package/EXPERIMENTAL.md +350 -0
  2. package/LICENSE +24 -0
  3. package/README.md +6317 -2
  4. package/WAProto/index.d.ts +17301 -0
  5. package/WAProto/index.js +125088 -0
  6. package/engine-requirements.js +14 -0
  7. package/package.json +100 -4
  8. package/src/Defaults/index.d.ts +152 -0
  9. package/src/Defaults/index.js +164 -0
  10. package/src/MessageBuilder/bot-signature.d.ts +22 -0
  11. package/src/MessageBuilder/bot-signature.js +122 -0
  12. package/src/MessageBuilder/extras.d.ts +449 -0
  13. package/src/MessageBuilder/extras.js +1356 -0
  14. package/src/MessageBuilder/index.d.ts +210 -0
  15. package/src/MessageBuilder/index.js +3594 -0
  16. package/src/MessageBuilder/metaai.d.ts +438 -0
  17. package/src/MessageBuilder/metaai.js +890 -0
  18. package/src/Signal/Group/ciphertext-message.d.ts +9 -0
  19. package/src/Signal/Group/ciphertext-message.js +11 -0
  20. package/src/Signal/Group/group-session-builder.d.ts +7 -0
  21. package/src/Signal/Group/group-session-builder.js +27 -0
  22. package/src/Signal/Group/group_cipher.d.ts +11 -0
  23. package/src/Signal/Group/group_cipher.js +78 -0
  24. package/src/Signal/Group/index.d.ts +11 -0
  25. package/src/Signal/Group/index.js +11 -0
  26. package/src/Signal/Group/keyhelper.d.ts +6 -0
  27. package/src/Signal/Group/keyhelper.js +17 -0
  28. package/src/Signal/Group/sender-chain-key.d.ts +13 -0
  29. package/src/Signal/Group/sender-chain-key.js +25 -0
  30. package/src/Signal/Group/sender-key-distribution-message.d.ts +16 -0
  31. package/src/Signal/Group/sender-key-distribution-message.js +62 -0
  32. package/src/Signal/Group/sender-key-message.d.ts +18 -0
  33. package/src/Signal/Group/sender-key-message.js +65 -0
  34. package/src/Signal/Group/sender-key-name.d.ts +11 -0
  35. package/src/Signal/Group/sender-key-name.js +47 -0
  36. package/src/Signal/Group/sender-key-record.d.ts +12 -0
  37. package/src/Signal/Group/sender-key-record.js +40 -0
  38. package/src/Signal/Group/sender-key-state.d.ts +16 -0
  39. package/src/Signal/Group/sender-key-state.js +83 -0
  40. package/src/Signal/Group/sender-message-key.d.ts +11 -0
  41. package/src/Signal/Group/sender-message-key.js +25 -0
  42. package/src/Signal/libsignal.d.ts +54 -0
  43. package/src/Signal/libsignal.js +427 -0
  44. package/src/Signal/lid-mapping.d.ts +20 -0
  45. package/src/Signal/lid-mapping.js +274 -0
  46. package/src/Socket/Client/index.d.ts +2 -0
  47. package/src/Socket/Client/index.js +3 -0
  48. package/src/Socket/Client/tcp.js +177 -0
  49. package/src/Socket/Client/types.d.ts +5 -0
  50. package/src/Socket/Client/types.js +9 -0
  51. package/src/Socket/Client/websocket.d.ts +12 -0
  52. package/src/Socket/Client/websocket.js +53 -0
  53. package/src/Socket/business.d.ts +431 -0
  54. package/src/Socket/business.js +379 -0
  55. package/src/Socket/chats.d.ts +247 -0
  56. package/src/Socket/chats.js +1484 -0
  57. package/src/Socket/communities.d.ts +598 -0
  58. package/src/Socket/communities.js +421 -0
  59. package/src/Socket/email.js +145 -0
  60. package/src/Socket/groups.d.ts +298 -0
  61. package/src/Socket/groups.js +339 -0
  62. package/src/Socket/index.d.ts +581 -0
  63. package/src/Socket/index.js +37 -0
  64. package/src/Socket/messages-recv.d.ts +370 -0
  65. package/src/Socket/messages-recv.js +1864 -0
  66. package/src/Socket/messages-send.d.ts +390 -0
  67. package/src/Socket/messages-send.js +1574 -0
  68. package/src/Socket/mex.d.ts +1 -0
  69. package/src/Socket/mex.js +44 -0
  70. package/src/Socket/mobile-builders.js +72 -0
  71. package/src/Socket/mobile.js +424 -0
  72. package/src/Socket/newsletter.d.ts +468 -0
  73. package/src/Socket/newsletter.js +671 -0
  74. package/src/Socket/socket.d.ts +77 -0
  75. package/src/Socket/socket.js +1106 -0
  76. package/src/Store/index.d.ts +3 -0
  77. package/src/Store/index.js +3 -0
  78. package/src/Store/make-in-memory-store.d.ts +62 -0
  79. package/src/Store/make-in-memory-store.js +396 -0
  80. package/src/Store/make-ordered-dictionary.d.ts +12 -0
  81. package/src/Store/make-ordered-dictionary.js +78 -0
  82. package/src/Store/object-repository.d.ts +10 -0
  83. package/src/Store/object-repository.js +23 -0
  84. package/src/Types/Auth.d.ts +1 -0
  85. package/src/Types/Auth.js +1 -0
  86. package/src/Types/Bussines.d.ts +1 -0
  87. package/src/Types/Bussines.js +1 -0
  88. package/src/Types/Call.d.ts +1 -0
  89. package/src/Types/Call.js +1 -0
  90. package/src/Types/Chat.d.ts +2 -0
  91. package/src/Types/Chat.js +24 -0
  92. package/src/Types/Contact.d.ts +1 -0
  93. package/src/Types/Contact.js +1 -0
  94. package/src/Types/Events.d.ts +1 -0
  95. package/src/Types/Events.js +0 -0
  96. package/src/Types/GroupMetadata.d.ts +5 -0
  97. package/src/Types/GroupMetadata.js +6 -0
  98. package/src/Types/Label.d.ts +2 -0
  99. package/src/Types/Label.js +24 -0
  100. package/src/Types/LabelAssociation.d.ts +2 -0
  101. package/src/Types/LabelAssociation.js +6 -0
  102. package/src/Types/Message.d.ts +13 -0
  103. package/src/Types/Message.js +23 -0
  104. package/src/Types/Mex.d.ts +2 -0
  105. package/src/Types/Mex.js +95 -0
  106. package/src/Types/Product.d.ts +1 -0
  107. package/src/Types/Product.js +1 -0
  108. package/src/Types/Signal.d.ts +1 -0
  109. package/src/Types/Signal.js +0 -0
  110. package/src/Types/Socket.d.ts +1 -0
  111. package/src/Types/Socket.js +0 -0
  112. package/src/Types/State.d.ts +5 -0
  113. package/src/Types/State.js +54 -0
  114. package/src/Types/USync.d.ts +1 -0
  115. package/src/Types/USync.js +0 -0
  116. package/src/Types/index.d.ts +13 -0
  117. package/src/Types/index.js +25 -0
  118. package/src/Utils/auth-store.d.ts +29 -0
  119. package/src/Utils/auth-store.js +76 -0
  120. package/src/Utils/auth-utils.d.ts +58 -0
  121. package/src/Utils/auth-utils.js +273 -0
  122. package/src/Utils/browser-utils.d.ts +9 -0
  123. package/src/Utils/browser-utils.js +28 -0
  124. package/src/Utils/business.d.ts +49 -0
  125. package/src/Utils/business.js +226 -0
  126. package/src/Utils/chat-utils.d.ts +408 -0
  127. package/src/Utils/chat-utils.js +846 -0
  128. package/src/Utils/companion-reg-client-utils.d.ts +4 -0
  129. package/src/Utils/companion-reg-client-utils.js +39 -0
  130. package/src/Utils/crypto.d.ts +39 -0
  131. package/src/Utils/crypto.js +110 -0
  132. package/src/Utils/decode-wa-message.d.ts +99 -0
  133. package/src/Utils/decode-wa-message.js +373 -0
  134. package/src/Utils/event-buffer.d.ts +22 -0
  135. package/src/Utils/event-buffer.js +624 -0
  136. package/src/Utils/generics.d.ts +63 -0
  137. package/src/Utils/generics.js +375 -0
  138. package/src/Utils/group-metadata-cache.d.ts +4 -0
  139. package/src/Utils/group-metadata-cache.js +25 -0
  140. package/src/Utils/history.d.ts +75 -0
  141. package/src/Utils/history.js +131 -0
  142. package/src/Utils/html-app.d.ts +19 -0
  143. package/src/Utils/html-app.js +96 -0
  144. package/src/Utils/html-multiplayer.d.ts +10 -0
  145. package/src/Utils/html-multiplayer.js +94 -0
  146. package/src/Utils/identity-change-handler.d.ts +13 -0
  147. package/src/Utils/identity-change-handler.js +48 -0
  148. package/src/Utils/index.d.ts +44 -0
  149. package/src/Utils/index.js +44 -0
  150. package/src/Utils/link-preview-metadata.d.ts +47 -0
  151. package/src/Utils/link-preview-metadata.js +88 -0
  152. package/src/Utils/link-preview.d.ts +12 -0
  153. package/src/Utils/link-preview.js +79 -0
  154. package/src/Utils/logger.d.ts +2 -0
  155. package/src/Utils/logger.js +2 -0
  156. package/src/Utils/lt-hash.d.ts +6 -0
  157. package/src/Utils/lt-hash.js +3 -0
  158. package/src/Utils/make-mutex.d.ts +6 -0
  159. package/src/Utils/make-mutex.js +32 -0
  160. package/src/Utils/message-retry-manager.d.ts +79 -0
  161. package/src/Utils/message-retry-manager.js +255 -0
  162. package/src/Utils/messages-media.d.ts +136 -0
  163. package/src/Utils/messages-media.js +814 -0
  164. package/src/Utils/messages.d.ts +62 -0
  165. package/src/Utils/messages.js +2223 -0
  166. package/src/Utils/mobile-companion-crypto.js +191 -0
  167. package/src/Utils/modern-messages.d.ts +150 -0
  168. package/src/Utils/modern-messages.js +496 -0
  169. package/src/Utils/native-flow.d.ts +11 -0
  170. package/src/Utils/native-flow.js +115 -0
  171. package/src/Utils/newsletter-status.d.ts +158 -0
  172. package/src/Utils/newsletter-status.js +651 -0
  173. package/src/Utils/noise-handler.d.ts +20 -0
  174. package/src/Utils/noise-handler.js +200 -0
  175. package/src/Utils/offline-node-processor.d.ts +9 -0
  176. package/src/Utils/offline-node-processor.js +33 -0
  177. package/src/Utils/optional-media.d.ts +3 -0
  178. package/src/Utils/optional-media.js +45 -0
  179. package/src/Utils/payment-messages.d.ts +66 -0
  180. package/src/Utils/payment-messages.js +160 -0
  181. package/src/Utils/pre-key-manager.d.ts +25 -0
  182. package/src/Utils/pre-key-manager.js +95 -0
  183. package/src/Utils/process-message.d.ts +60 -0
  184. package/src/Utils/process-message.js +688 -0
  185. package/src/Utils/reporting-utils.d.ts +12 -0
  186. package/src/Utils/reporting-utils.js +256 -0
  187. package/src/Utils/scheduled-message.d.ts +51 -0
  188. package/src/Utils/scheduled-message.js +112 -0
  189. package/src/Utils/sender-key-memory.d.ts +19 -0
  190. package/src/Utils/sender-key-memory.js +51 -0
  191. package/src/Utils/signal.d.ts +82 -0
  192. package/src/Utils/signal.js +193 -0
  193. package/src/Utils/stanza-ack.d.ts +16 -0
  194. package/src/Utils/stanza-ack.js +30 -0
  195. package/src/Utils/status-stickers.d.ts +127 -0
  196. package/src/Utils/status-stickers.js +260 -0
  197. package/src/Utils/sync-action-utils.d.ts +2 -0
  198. package/src/Utils/sync-action-utils.js +44 -0
  199. package/src/Utils/tc-token-utils.d.ts +29 -0
  200. package/src/Utils/tc-token-utils.js +155 -0
  201. package/src/Utils/ttl-cache.d.ts +28 -0
  202. package/src/Utils/ttl-cache.js +120 -0
  203. package/src/Utils/use-mongo-auth-state.d.ts +21 -0
  204. package/src/Utils/use-mongo-auth-state.js +67 -0
  205. package/src/Utils/use-multi-file-auth-state.d.ts +11 -0
  206. package/src/Utils/use-multi-file-auth-state.js +106 -0
  207. package/src/Utils/use-mysql-auth-state.d.ts +19 -0
  208. package/src/Utils/use-mysql-auth-state.js +79 -0
  209. package/src/Utils/use-postgres-auth-state.d.ts +19 -0
  210. package/src/Utils/use-postgres-auth-state.js +79 -0
  211. package/src/Utils/use-redis-auth-state.d.ts +19 -0
  212. package/src/Utils/use-redis-auth-state.js +89 -0
  213. package/src/Utils/use-single-file-auth-state.d.ts +10 -0
  214. package/src/Utils/use-single-file-auth-state.js +108 -0
  215. package/src/Utils/use-sqlite-auth-state.d.ts +12 -0
  216. package/src/Utils/use-sqlite-auth-state.js +120 -0
  217. package/src/Utils/useNekoDBAuth.d.ts +19 -0
  218. package/src/Utils/useNekoDBAuth.js +111 -0
  219. package/src/Utils/username.d.ts +12 -0
  220. package/src/Utils/username.js +58 -0
  221. package/src/Utils/validate-connection.d.ts +43 -0
  222. package/src/Utils/validate-connection.js +277 -0
  223. package/src/Utils/voice-recognition.d.ts +53 -0
  224. package/src/Utils/voice-recognition.js +219 -0
  225. package/src/Voip/audio-feeder.d.ts +24 -0
  226. package/src/Voip/audio-feeder.js +268 -0
  227. package/src/Voip/index.d.ts +88 -0
  228. package/src/Voip/index.js +936 -0
  229. package/src/Voip/relay-transport.d.ts +5 -0
  230. package/src/Voip/relay-transport.js +824 -0
  231. package/src/Voip/signaling.d.ts +11 -0
  232. package/src/Voip/signaling.js +1099 -0
  233. package/src/Voip/types.d.ts +2 -0
  234. package/src/Voip/types.js +12 -0
  235. package/src/Voip/video-feeder.d.ts +24 -0
  236. package/src/Voip/video-feeder.js +268 -0
  237. package/src/Voip/wasm-engine.d.ts +26 -0
  238. package/src/Voip/wasm-engine.js +1307 -0
  239. package/src/Voip/worker-bootstrap.js +1023 -0
  240. package/src/WABinary/constants.d.ts +22 -0
  241. package/src/WABinary/constants.js +1300 -0
  242. package/src/WABinary/decode.d.ts +9 -0
  243. package/src/WABinary/decode.js +261 -0
  244. package/src/WABinary/encode.d.ts +2 -0
  245. package/src/WABinary/encode.js +219 -0
  246. package/src/WABinary/generic-utils.d.ts +76 -0
  247. package/src/WABinary/generic-utils.js +214 -0
  248. package/src/WABinary/index.d.ts +5 -0
  249. package/src/WABinary/index.js +5 -0
  250. package/src/WABinary/jid-utils.d.ts +30 -0
  251. package/src/WABinary/jid-utils.js +97 -0
  252. package/src/WABinary/types.d.ts +1 -0
  253. package/src/WABinary/types.js +0 -0
  254. package/src/WAM/BinaryInfo.d.ts +7 -0
  255. package/src/WAM/BinaryInfo.js +9 -0
  256. package/src/WAM/constants.d.ts +34926 -0
  257. package/src/WAM/constants.js +22852 -0
  258. package/src/WAM/encode.d.ts +1 -0
  259. package/src/WAM/encode.js +148 -0
  260. package/src/WAM/index.d.ts +3 -0
  261. package/src/WAM/index.js +3 -0
  262. package/src/WAUSync/Protocols/USyncContactProtocol.d.ts +36 -0
  263. package/src/WAUSync/Protocols/USyncContactProtocol.js +50 -0
  264. package/src/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
  265. package/src/WAUSync/Protocols/USyncDeviceProtocol.js +51 -0
  266. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
  267. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +26 -0
  268. package/src/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
  269. package/src/WAUSync/Protocols/USyncStatusProtocol.js +37 -0
  270. package/src/WAUSync/Protocols/USyncUsernameProtocol.d.ts +9 -0
  271. package/src/WAUSync/Protocols/USyncUsernameProtocol.js +23 -0
  272. package/src/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +38 -0
  273. package/src/WAUSync/Protocols/UsyncBotProfileProtocol.js +49 -0
  274. package/src/WAUSync/Protocols/UsyncLIDProtocol.d.ts +14 -0
  275. package/src/WAUSync/Protocols/UsyncLIDProtocol.js +28 -0
  276. package/src/WAUSync/Protocols/index.d.ts +5 -0
  277. package/src/WAUSync/Protocols/index.js +5 -0
  278. package/src/WAUSync/USyncQuery.d.ts +20 -0
  279. package/src/WAUSync/USyncQuery.js +93 -0
  280. package/src/WAUSync/USyncUser.d.ts +16 -0
  281. package/src/WAUSync/USyncUser.js +30 -0
  282. package/src/WAUSync/index.d.ts +3 -0
  283. package/src/WAUSync/index.js +3 -0
  284. package/src/assets/wasm/README.md +76 -0
  285. package/src/assets/wasm/loader.js +5 -0
  286. package/src/assets/wasm/whatsapp.wasm +0 -0
  287. package/src/assets/wasm/worker-modules.js +273 -0
  288. package/src/index.d.ts +43 -0
  289. package/src/index.js +48 -0
@@ -0,0 +1,277 @@
1
+ import { Boom } from '@hapi/boom';
2
+ import { createHash, randomUUID } from 'crypto';
3
+ import { proto } from '../../WAProto/index.js';
4
+ import { KEY_BUNDLE_TYPE, WA_ADV_ACCOUNT_SIG_PREFIX, WA_ADV_DEVICE_SIG_PREFIX, WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX } from '../Defaults/index.js';
5
+ import { getBinaryNodeChild, jidDecode, S_WHATSAPP_NET } from '../WABinary/index.js';
6
+ import { Curve, hmacSign } from './crypto.js';
7
+ import { encodeBigEndian } from './generics.js';
8
+ import { createSignalIdentity } from './signal.js';
9
+ const getUserAgent = (config) => {
10
+ return {
11
+ appVersion: {
12
+ primary: config.version[0],
13
+ secondary: config.version[1],
14
+ tertiary: config.version[2]
15
+ },
16
+ platform: config.browser[1].toLocaleLowerCase().includes('android')
17
+ ? proto.ClientPayload.UserAgent.Platform.ANDROID
18
+ : proto.ClientPayload.UserAgent.Platform.WEB,
19
+ releaseChannel: proto.ClientPayload.UserAgent.ReleaseChannel.RELEASE,
20
+ osVersion: '0.1',
21
+ device: 'Desktop',
22
+ osBuildNumber: '0.1',
23
+ localeLanguageIso6391: 'en',
24
+ mnc: '000',
25
+ mcc: '000',
26
+ localeCountryIso31661Alpha2: config.countryCode
27
+ };
28
+ };
29
+ const PLATFORM_MAP = {
30
+ 'Mac OS': proto.ClientPayload.WebInfo.WebSubPlatform.DARWIN,
31
+ Windows: proto.ClientPayload.WebInfo.WebSubPlatform.WIN32
32
+ };
33
+ const getWebInfo = (config) => {
34
+ let webSubPlatform = proto.ClientPayload.WebInfo.WebSubPlatform.WEB_BROWSER;
35
+ if (config.syncFullHistory &&
36
+ PLATFORM_MAP[config.browser[0]] &&
37
+ config.browser[1] === 'Desktop') {
38
+ webSubPlatform = PLATFORM_MAP[config.browser[0]];
39
+ }
40
+ return { webSubPlatform };
41
+ };
42
+ const getClientPayload = (config) => {
43
+ const payload = {
44
+ connectType: proto.ClientPayload.ConnectType.WIFI_UNKNOWN,
45
+ connectReason: proto.ClientPayload.ConnectReason.USER_ACTIVATED,
46
+ userAgent: getUserAgent(config)
47
+ };
48
+ if (!config.browser[1].toLocaleLowerCase().includes('android')) {
49
+ payload.webInfo = getWebInfo(config);
50
+ }
51
+ if (config.pushName) {
52
+ payload.pushName = config.pushName;
53
+ }
54
+ return payload;
55
+ };
56
+ const buildMobileLoginPayload = (userJid, config, deviceInfo) => {
57
+ if (!deviceInfo) {
58
+ throw new Boom('mobile login requires deviceInfo', { statusCode: 400 });
59
+ }
60
+ const { user, device } = jidDecode(userJid);
61
+ const username = +user;
62
+ if (!Number.isSafeInteger(username) || username <= 0) {
63
+ throw new Boom('mobile login requires a valid numeric username', { statusCode: 400 });
64
+ }
65
+ const parseAppVersion = (version) => {
66
+ const parts = String(version || '').split('.');
67
+ const at = (i) => {
68
+ const n = Number(parts[i]);
69
+ return Number.isFinite(n) ? n : undefined;
70
+ };
71
+ return { primary: at(0) ?? 2, secondary: at(1) ?? 0, tertiary: at(2) ?? 0, quaternary: at(3) };
72
+ };
73
+ const version = parseAppVersion(deviceInfo.appVersion);
74
+ const isIos = deviceInfo.os === 'ios';
75
+ const platform = isIos
76
+ ? (deviceInfo.business ? proto.ClientPayload.UserAgent.Platform.SMB_IOS : proto.ClientPayload.UserAgent.Platform.IOS)
77
+ : (deviceInfo.business ? proto.ClientPayload.UserAgent.Platform.SMB_ANDROID : proto.ClientPayload.UserAgent.Platform.ANDROID);
78
+ const distributionChannelMap = {
79
+ website: proto.ClientPayload.UserAgent.DistributionChannel.WEBSITE,
80
+ testflight: proto.ClientPayload.UserAgent.DistributionChannel.TESTFLIGHT,
81
+ internal: proto.ClientPayload.UserAgent.DistributionChannel.INTERNAL,
82
+ appstore: proto.ClientPayload.UserAgent.DistributionChannel.APPSTORE
83
+ };
84
+ const userAgent = {
85
+ platform,
86
+ releaseChannel: proto.ClientPayload.UserAgent.ReleaseChannel.RELEASE,
87
+ appVersion: version,
88
+ osVersion: deviceInfo.osVersion,
89
+ manufacturer: deviceInfo.manufacturer,
90
+ device: deviceInfo.device,
91
+ osBuildNumber: deviceInfo.osBuildNumber,
92
+ phoneId: deviceInfo.phoneId || randomUUID(),
93
+ localeLanguageIso6391: deviceInfo.localeLanguageIso6391 || 'en',
94
+ localeCountryIso31661Alpha2: deviceInfo.localeCountryIso31661Alpha2 || 'US',
95
+ deviceType: proto.ClientPayload.UserAgent.DeviceType.PHONE,
96
+ deviceModelType: deviceInfo.deviceModelType
97
+ };
98
+ if (isIos) {
99
+ userAgent.distributionChannel = distributionChannelMap[deviceInfo.distributionChannel || 'appstore'] || distributionChannelMap.appstore;
100
+ } else {
101
+ userAgent.mcc = deviceInfo.mcc || '000';
102
+ userAgent.mnc = deviceInfo.mnc || '000';
103
+ userAgent.deviceBoard = deviceInfo.deviceBoard;
104
+ }
105
+ const payload = {
106
+ passive: config.mobileTransport?.passive === true || deviceInfo.passive === true,
107
+ pull: true,
108
+ product: proto.ClientPayload.Product.WHATSAPP,
109
+ connectType: proto.ClientPayload.ConnectType.CELLULAR_UNKNOWN,
110
+ connectReason: proto.ClientPayload.ConnectReason.USER_ACTIVATED,
111
+ userAgent,
112
+ username,
113
+ device: device || 0,
114
+ lidDbMigrated: false,
115
+ pushName: config.mobileTransport?.pushName || config.pushName
116
+ };
117
+ if (config.mobileTransport?.yearClass) payload.yearClass = config.mobileTransport.yearClass;
118
+ if (config.mobileTransport?.memClass) payload.memClass = config.mobileTransport.memClass;
119
+ return proto.ClientPayload.fromObject(payload);
120
+ };
121
+
122
+ export const generateLoginNode = (userJid, config, deviceInfo) => {
123
+ if (deviceInfo || config?.mobileDeviceInfo || config?.mobileTransport?.deviceInfo) {
124
+ const di = deviceInfo || config?.mobileDeviceInfo || config?.mobileTransport?.deviceInfo;
125
+ return buildMobileLoginPayload(userJid, { ...config, mobileTransport: config?.mobileTransport }, di);
126
+ }
127
+ const { user, device } = jidDecode(userJid);
128
+ const payload = {
129
+ ...getClientPayload(config),
130
+ passive: true,
131
+ pull: true,
132
+ username: +user,
133
+ device: device,
134
+
135
+ lidDbMigrated: false
136
+ };
137
+ return proto.ClientPayload.fromObject(payload);
138
+ };
139
+ const getPlatformType = (platform) => {
140
+ const platformType = platform.toUpperCase();
141
+ if (platformType === 'ANDROID') {
142
+ return proto.DeviceProps.PlatformType.ANDROID_PHONE;
143
+ }
144
+ return (proto.DeviceProps.PlatformType[platformType] ||
145
+ proto.DeviceProps.PlatformType.CHROME);
146
+ };
147
+ export const generateRegistrationNode = ({ registrationId, signedPreKey, signedIdentityKey }, config) => {
148
+
149
+ const appVersionBuf = createHash('md5')
150
+ .update(config.version.join('.'))
151
+ .digest();
152
+ const companion = {
153
+ os: config.browser[0],
154
+ platformType: getPlatformType(config.browser[1]),
155
+ requireFullSync: config.syncFullHistory,
156
+ historySyncConfig: {
157
+ storageQuotaMb: 10240,
158
+ inlineInitialPayloadInE2EeMsg: true,
159
+ recentSyncDaysLimit: undefined,
160
+ supportCallLogHistory: false,
161
+ supportBotUserAgentChatHistory: true,
162
+ supportCagReactionsAndPolls: true,
163
+ supportBizHostedMsg: true,
164
+ supportRecentSyncChunkMessageCountTuning: true,
165
+ supportHostedGroupMsg: true,
166
+ supportFbidBotChatHistory: true,
167
+ supportAddOnHistorySyncMigration: undefined,
168
+ supportMessageAssociation: true,
169
+ supportGroupHistory: false,
170
+ onDemandReady: undefined,
171
+ supportGuestChat: undefined
172
+ },
173
+ version: {
174
+ primary: 10,
175
+ secondary: 15,
176
+ tertiary: 7
177
+ }
178
+ };
179
+ const companionProto = proto.DeviceProps.encode(companion).finish();
180
+ const registerPayload = {
181
+ ...getClientPayload(config),
182
+ passive: false,
183
+ pull: false,
184
+ devicePairingData: {
185
+ buildHash: appVersionBuf,
186
+ deviceProps: companionProto,
187
+ eRegid: encodeBigEndian(registrationId),
188
+ eKeytype: KEY_BUNDLE_TYPE,
189
+ eIdent: signedIdentityKey.public,
190
+ eSkeyId: encodeBigEndian(signedPreKey.keyId, 3),
191
+ eSkeyVal: signedPreKey.keyPair.public,
192
+ eSkeySig: signedPreKey.signature
193
+ }
194
+ };
195
+ return proto.ClientPayload.fromObject(registerPayload);
196
+ };
197
+ export const configureSuccessfulPairing = (stanza, { advSecretKey, signedIdentityKey, signalIdentities }) => {
198
+ const msgId = stanza.attrs.id;
199
+ const pairSuccessNode = getBinaryNodeChild(stanza, 'pair-success');
200
+ const deviceIdentityNode = getBinaryNodeChild(pairSuccessNode, 'device-identity');
201
+ const platformNode = getBinaryNodeChild(pairSuccessNode, 'platform');
202
+ const deviceNode = getBinaryNodeChild(pairSuccessNode, 'device');
203
+ const businessNode = getBinaryNodeChild(pairSuccessNode, 'biz');
204
+ if (!deviceIdentityNode || !deviceNode) {
205
+ throw new Boom('Missing device-identity or device in pair success node', { data: stanza });
206
+ }
207
+ const bizName = businessNode?.attrs.name;
208
+ const jid = deviceNode.attrs.jid;
209
+ const lid = deviceNode.attrs.lid;
210
+ const { details, hmac, accountType } = proto.ADVSignedDeviceIdentityHMAC.decode(deviceIdentityNode.content);
211
+ let hmacPrefix = Buffer.from([]);
212
+ if (accountType !== undefined && accountType === proto.ADVEncryptionType.HOSTED) {
213
+ hmacPrefix = WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX;
214
+ }
215
+ const advSign = hmacSign(Buffer.concat([hmacPrefix, details]), Buffer.from(advSecretKey, 'base64'));
216
+ if (Buffer.compare(hmac, advSign) !== 0) {
217
+ throw new Boom('Invalid account signature');
218
+ }
219
+ const account = proto.ADVSignedDeviceIdentity.decode(details);
220
+ const { accountSignatureKey, accountSignature, details: deviceDetails } = account;
221
+ const deviceIdentity = proto.ADVDeviceIdentity.decode(deviceDetails);
222
+ const accountSignaturePrefix = deviceIdentity.deviceType === proto.ADVEncryptionType.HOSTED
223
+ ? WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX
224
+ : WA_ADV_ACCOUNT_SIG_PREFIX;
225
+ const accountMsg = Buffer.concat([accountSignaturePrefix, deviceDetails, signedIdentityKey.public]);
226
+ if (!Curve.verify(accountSignatureKey, accountMsg, accountSignature)) {
227
+ throw new Boom('Failed to verify account signature');
228
+ }
229
+ const deviceMsg = Buffer.concat([
230
+ WA_ADV_DEVICE_SIG_PREFIX,
231
+ deviceDetails,
232
+ signedIdentityKey.public,
233
+ accountSignatureKey
234
+ ]);
235
+ account.deviceSignature = Curve.sign(signedIdentityKey.private, deviceMsg);
236
+ const identity = createSignalIdentity(lid, accountSignatureKey);
237
+ const accountEnc = encodeSignedDeviceIdentity(account, false);
238
+ const reply = {
239
+ tag: 'iq',
240
+ attrs: {
241
+ to: S_WHATSAPP_NET,
242
+ type: 'result',
243
+ id: msgId
244
+ },
245
+ content: [
246
+ {
247
+ tag: 'pair-device-sign',
248
+ attrs: {},
249
+ content: [
250
+ {
251
+ tag: 'device-identity',
252
+ attrs: { 'key-index': deviceIdentity.keyIndex.toString() },
253
+ content: accountEnc
254
+ }
255
+ ]
256
+ }
257
+ ]
258
+ };
259
+ const authUpdate = {
260
+ account,
261
+ me: { id: jid, name: bizName, lid },
262
+ signalIdentities: [...(signalIdentities || []), identity],
263
+ platform: platformNode?.attrs.name
264
+ };
265
+ return {
266
+ creds: authUpdate,
267
+ reply
268
+ };
269
+ };
270
+ export const encodeSignedDeviceIdentity = (account, includeSignatureKey) => {
271
+ account = { ...account };
272
+
273
+ if (!includeSignatureKey || !account.accountSignatureKey?.length) {
274
+ account.accountSignatureKey = null;
275
+ }
276
+ return proto.ADVSignedDeviceIdentity.encode(account).finish();
277
+ };
@@ -0,0 +1,53 @@
1
+ export type VoiceRecognitionContext = {
2
+ message: any;
3
+ audioMessage: any;
4
+ chatJid: string;
5
+ senderJid: string;
6
+ isGroup: boolean;
7
+ };
8
+ export type VoiceTranscriptionInput = VoiceRecognitionContext & {
9
+ buffer: Buffer;
10
+ mimetype: string;
11
+ };
12
+ export type VoiceTranscriptionResult = string | {
13
+ text?: string;
14
+ transcript?: string;
15
+ language?: string;
16
+ confidence?: number;
17
+ [key: string]: any;
18
+ };
19
+ export type VoiceRecognitionOptions = {
20
+ enabled?: boolean;
21
+ transcribe: (input: VoiceTranscriptionInput) => VoiceTranscriptionResult | Promise<VoiceTranscriptionResult>;
22
+ wakePhrases?: string | string[];
23
+ getWakePhrases?: (context: VoiceRecognitionContext) => string | string[] | undefined | Promise<string | string[] | undefined>;
24
+ shouldProcess?: (context: VoiceRecognitionContext) => boolean | Promise<boolean>;
25
+ allowQuotedActivation?: boolean;
26
+ pttOnly?: boolean;
27
+ maxDuration?: number;
28
+ maxBytes?: number;
29
+ downloadOptions?: any;
30
+ };
31
+ export type VoiceRecognitionEvent = VoiceRecognitionContext & {
32
+ transcript: string;
33
+ commandText: string;
34
+ activation: 'quoted' | 'wake-phrase' | null;
35
+ wakePhrase: string | null;
36
+ language?: string;
37
+ confidence?: number;
38
+ [key: string]: any;
39
+ };
40
+ export function normalizeVoiceText(value: any): string;
41
+ export function matchVoiceWakePhrase(transcript: any, phrases?: string | string[]): {
42
+ phrase: string;
43
+ normalizedPhrase: string;
44
+ normalizedTranscript: string;
45
+ } | null;
46
+ export function removeVoiceWakePhrase(transcript: any, wakePhrase: any): string;
47
+ export function bindVoiceRecognition(sock: any, config?: {
48
+ voiceRecognition?: VoiceRecognitionOptions;
49
+ getMessage?: (key: any) => Promise<any>;
50
+ logger?: any;
51
+ }, dependencies?: {
52
+ downloadContentFromMessage?: (...args: any[]) => Promise<any>;
53
+ }): () => void;
@@ -0,0 +1,219 @@
1
+ import { downloadContentFromMessage } from './messages-media.js';
2
+ import { normalizeMessageContent } from './messages.js';
3
+ import { areJidsSameUser, isJidGroup, jidNormalizedUser } from '../WABinary/index.js';
4
+
5
+ const DEFAULT_MAX_DURATION = 60;
6
+ const DEFAULT_MAX_BYTES = 16 * 1024 * 1024;
7
+
8
+ const streamToBuffer = async (stream, maxBytes) => {
9
+ const chunks = [];
10
+ let total = 0;
11
+ for await (const chunk of stream) {
12
+ const buffer = Buffer.from(chunk);
13
+ total += buffer.length;
14
+ if (maxBytes && total > maxBytes) {
15
+ throw new Error('voice message exceeds maxBytes');
16
+ }
17
+ chunks.push(buffer);
18
+ }
19
+ return Buffer.concat(chunks);
20
+ };
21
+
22
+ export const normalizeVoiceText = value => String(value ?? '')
23
+ .normalize('NFKD')
24
+ .replace(/\p{M}/gu, '')
25
+ .toLowerCase()
26
+ .replace(/[^\p{L}\p{N}]+/gu, ' ')
27
+ .replace(/\s+/g, ' ')
28
+ .trim();
29
+
30
+ export const matchVoiceWakePhrase = (transcript, phrases = []) => {
31
+ const normalizedTranscript = normalizeVoiceText(transcript);
32
+ if (!normalizedTranscript) {
33
+ return null;
34
+ }
35
+ const candidates = [...new Map((Array.isArray(phrases) ? phrases : [phrases])
36
+ .map(phrase => ({ raw: String(phrase ?? '').trim(), normalized: normalizeVoiceText(phrase) }))
37
+ .filter(phrase => phrase.normalized)
38
+ .map(phrase => [phrase.normalized, phrase])).values()]
39
+ .sort((a, b) => b.normalized.length - a.normalized.length);
40
+ for (const phrase of candidates) {
41
+ const index = ` ${normalizedTranscript} `.indexOf(` ${phrase.normalized} `);
42
+ if (index >= 0) {
43
+ return {
44
+ phrase: phrase.raw,
45
+ normalizedPhrase: phrase.normalized,
46
+ normalizedTranscript
47
+ };
48
+ }
49
+ }
50
+ return null;
51
+ };
52
+
53
+ export const removeVoiceWakePhrase = (transcript, wakePhrase) => {
54
+ const normalizedTranscript = normalizeVoiceText(transcript);
55
+ const normalizedPhrase = normalizeVoiceText(wakePhrase);
56
+ if (!normalizedPhrase) {
57
+ return normalizedTranscript;
58
+ }
59
+ const words = normalizedTranscript.split(' ');
60
+ const phraseWords = normalizedPhrase.split(' ');
61
+ for (let index = 0; index <= words.length - phraseWords.length; index += 1) {
62
+ if (phraseWords.every((word, offset) => words[index + offset] === word)) {
63
+ words.splice(index, phraseWords.length);
64
+ break;
65
+ }
66
+ }
67
+ return words.join(' ').trim();
68
+ };
69
+
70
+ const getVoiceSenderJid = message => jidNormalizedUser(message?.key?.participantAlt ||
71
+ message?.key?.participant ||
72
+ message?.key?.remoteJidAlt ||
73
+ message?.key?.remoteJid);
74
+
75
+ const isQuotedToSelf = async ({ message, audioMessage, meId, meLid, getMessage }) => {
76
+ const contextInfo = audioMessage?.contextInfo;
77
+ if (!contextInfo?.quotedMessage && !contextInfo?.stanzaId) {
78
+ return false;
79
+ }
80
+ const quotedAuthor = contextInfo.participantAlt || contextInfo.participant;
81
+ if (quotedAuthor && (areJidsSameUser(quotedAuthor, meId) || areJidsSameUser(quotedAuthor, meLid))) {
82
+ return true;
83
+ }
84
+ if (!contextInfo.stanzaId || typeof getMessage !== 'function') {
85
+ return false;
86
+ }
87
+ const target = await getMessage({
88
+ remoteJid: message.key.remoteJid,
89
+ remoteJidAlt: message.key.remoteJidAlt,
90
+ participant: quotedAuthor,
91
+ id: contextInfo.stanzaId
92
+ });
93
+ return target?.key?.fromMe === true;
94
+ };
95
+
96
+ const normalizeTranscriptionResult = value => {
97
+ if (typeof value === 'string') {
98
+ return { text: value };
99
+ }
100
+ if (value && typeof value === 'object') {
101
+ return {
102
+ ...value,
103
+ text: String(value.text ?? value.transcript ?? '')
104
+ };
105
+ }
106
+ return { text: '' };
107
+ };
108
+
109
+ const getWakePhrases = async (voiceRecognition, context) => {
110
+ const staticPhrases = Array.isArray(voiceRecognition.wakePhrases)
111
+ ? voiceRecognition.wakePhrases
112
+ : voiceRecognition.wakePhrases
113
+ ? [voiceRecognition.wakePhrases]
114
+ : [];
115
+ const dynamicPhrases = typeof voiceRecognition.getWakePhrases === 'function'
116
+ ? await voiceRecognition.getWakePhrases(context)
117
+ : [];
118
+ return [...new Set([
119
+ ...staticPhrases,
120
+ ...(Array.isArray(dynamicPhrases) ? dynamicPhrases : dynamicPhrases ? [dynamicPhrases] : [])
121
+ ].map(value => String(value ?? '').trim()).filter(Boolean))];
122
+ };
123
+
124
+ export const bindVoiceRecognition = (sock, config = {}, dependencies = {}) => {
125
+ const voiceRecognition = config.voiceRecognition;
126
+ if (!voiceRecognition?.enabled || typeof voiceRecognition.transcribe !== 'function') {
127
+ return () => undefined;
128
+ }
129
+ const downloadContent = dependencies.downloadContentFromMessage || downloadContentFromMessage;
130
+ const getMessage = config.getMessage;
131
+ const logger = config.logger;
132
+ const handler = async ({ messages, type }) => {
133
+ if (type !== 'notify') {
134
+ return;
135
+ }
136
+ for (const message of messages || []) {
137
+ try {
138
+ if (
139
+ !message?.message ||
140
+ (message.key?.fromMe && !voiceRecognition.allowFromMe)
141
+ ) {
142
+ continue
143
+ }
144
+ const content = normalizeMessageContent(message.message);
145
+ const audioMessage = content?.audioMessage;
146
+ if (!audioMessage) {
147
+ continue;
148
+ }
149
+ if ((voiceRecognition.pttOnly ?? true) && !audioMessage.ptt) {
150
+ continue;
151
+ }
152
+ const maxDuration = Number.isFinite(voiceRecognition.maxDuration)
153
+ ? Math.max(0, Number(voiceRecognition.maxDuration))
154
+ : DEFAULT_MAX_DURATION;
155
+ if (maxDuration && Number(audioMessage.seconds || 0) > maxDuration) {
156
+ continue;
157
+ }
158
+ const chatJid = jidNormalizedUser(message.key.remoteJid);
159
+ const senderJid = getVoiceSenderJid(message);
160
+ const context = {
161
+ message,
162
+ audioMessage,
163
+ chatJid,
164
+ senderJid,
165
+ isGroup: isJidGroup(chatJid)
166
+ };
167
+ if (typeof voiceRecognition.shouldProcess === 'function' && !(await voiceRecognition.shouldProcess(context))) {
168
+ continue;
169
+ }
170
+ const maxBytes = Number.isFinite(voiceRecognition.maxBytes)
171
+ ? Math.max(0, Number(voiceRecognition.maxBytes))
172
+ : DEFAULT_MAX_BYTES;
173
+ const declaredBytes = Number(audioMessage.fileLength?.toString?.() || audioMessage.fileLength || 0);
174
+ if (maxBytes && declaredBytes > maxBytes) {
175
+ continue;
176
+ }
177
+ const stream = await downloadContent(audioMessage, 'audio', voiceRecognition.downloadOptions || {});
178
+ const buffer = await streamToBuffer(stream, maxBytes);
179
+ const transcription = normalizeTranscriptionResult(await voiceRecognition.transcribe({
180
+ ...context,
181
+ buffer,
182
+ mimetype: audioMessage.mimetype || 'audio/ogg; codecs=opus'
183
+ }));
184
+ const transcript = transcription.text.trim();
185
+ if (!transcript) {
186
+ continue;
187
+ }
188
+ const meId = sock.authState?.creds?.me?.id;
189
+ const meLid = sock.authState?.creds?.me?.lid;
190
+ const quoted = (voiceRecognition.allowQuotedActivation ?? true)
191
+ ? await isQuotedToSelf({ message, audioMessage, meId, meLid, getMessage })
192
+ : false;
193
+ const phrases = quoted ? [] : await getWakePhrases(voiceRecognition, context);
194
+ const wake = quoted ? null : matchVoiceWakePhrase(transcript, phrases);
195
+ const activation = quoted ? 'quoted' : wake ? 'wake-phrase' : null;
196
+ const commandText = wake
197
+ ? removeVoiceWakePhrase(transcript, wake.normalizedPhrase)
198
+ : normalizeVoiceText(transcript);
199
+ const event = {
200
+ ...context,
201
+ ...transcription,
202
+ transcript,
203
+ commandText,
204
+ activation,
205
+ wakePhrase: wake?.phrase || null
206
+ };
207
+ sock.ev.emit('voice.transcription', event);
208
+ if (activation) {
209
+ sock.ev.emit('voice.command', event);
210
+ }
211
+ }
212
+ catch (error) {
213
+ logger?.warn({ err: error, key: message?.key }, 'voice recognition failed');
214
+ }
215
+ }
216
+ };
217
+ sock.ev.on('messages.upsert', handler);
218
+ return () => sock.ev.off('messages.upsert', handler);
219
+ };
@@ -0,0 +1,24 @@
1
+ export declare class AudioFeeder {
2
+ constructor(sampleRate: number, channels: number, framesPerChunk: number, onChunk: (chunk: Float32Array) => void, source?: string, hooks?: {
3
+ onTrackStart?: (track: string) => void;
4
+ onTrackEnd?: (track: string) => void;
5
+ onIdle?: () => void;
6
+ ffmpegPath?: string;
7
+ });
8
+ readonly queuedChunks: number;
9
+ droppedChunks: number;
10
+ underflowChunks: number;
11
+ rebuffers: number;
12
+ bytesProduced: number;
13
+ chunksEmitted: number;
14
+ readonly playlistLength: number;
15
+ readonly currentTrack: string | null;
16
+ readonly idle: boolean;
17
+ tracksPlayed: number;
18
+ enqueue(source: string | string[]): number;
19
+ clearPlaylist(): void;
20
+ skip(): boolean;
21
+ start(playlist?: string[]): void;
22
+ stop(): void;
23
+ }
24
+ export default AudioFeeder;