@nerxa/socketon 0.0.0-stage → 1.21.1

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 +125 -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 +77 -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,496 @@
1
+ import { proto } from '../../WAProto/index.js'
2
+
3
+ const requireObject = (value, name) => {
4
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
5
+ throw new TypeError(`${name} must be an object`)
6
+ }
7
+ return value
8
+ }
9
+
10
+ const requireKey = (value, name = 'key') => {
11
+ requireObject(value, name)
12
+ if (!value.id) {
13
+ throw new TypeError(`${name}.id is required`)
14
+ }
15
+ return value
16
+ }
17
+
18
+ const enumValue = (enumObject, value, fallback) => {
19
+ if (typeof value === 'number') return value
20
+ if (typeof value === 'string') {
21
+ const key = value.trim().toUpperCase()
22
+ if (key in enumObject) return enumObject[key]
23
+ }
24
+ return fallback
25
+ }
26
+
27
+ export const STATUS_NOTIFICATION_TYPES = Object.freeze({
28
+ ...proto.Message.StatusNotificationMessage.StatusNotificationType,
29
+ STATUS_GROUP_STATUS_REPLY: 4
30
+ })
31
+
32
+ const toSeconds = value => value instanceof Date ? Math.floor(value.getTime() / 1000) : value
33
+ const toMilliseconds = value => value instanceof Date ? value.getTime() : value
34
+
35
+ const makeInnerCommentMessage = content => {
36
+ const data = requireObject(content, 'comment.content')
37
+ if (data.raw && typeof data.raw === 'object') return data.raw
38
+ if (typeof data.text === 'string') {
39
+ return {
40
+ extendedTextMessage: proto.Message.ExtendedTextMessage.create({
41
+ text: data.text,
42
+ contextInfo: data.contextInfo
43
+ })
44
+ }
45
+ }
46
+ const keys = Object.keys(data)
47
+ if (keys.some(key => key.endsWith('Message'))) return data
48
+ throw new TypeError('comment.content supports text, raw, or protobuf message fields')
49
+ }
50
+
51
+ export const makeQuestionMessage = input => {
52
+ const data = requireObject(input, 'question')
53
+ if (typeof data.text !== 'string' || !data.text.length) {
54
+ throw new TypeError('question.text is required')
55
+ }
56
+ return {
57
+ questionMessage: proto.Message.FutureProofMessage.create({
58
+ message: {
59
+ extendedTextMessage: proto.Message.ExtendedTextMessage.create({
60
+ text: data.text,
61
+ contextInfo: {
62
+ ...(data.contextInfo || {}),
63
+ isQuestion: true
64
+ }
65
+ })
66
+ }
67
+ })
68
+ }
69
+ }
70
+
71
+ export const makeQuestionResponseMessage = input => {
72
+ const data = requireObject(input, 'questionResponse')
73
+ requireKey(data.key, 'questionResponse.key')
74
+ return {
75
+ questionResponseMessage: proto.Message.QuestionResponseMessage.create({
76
+ key: data.key,
77
+ text: data.text ?? ''
78
+ })
79
+ }
80
+ }
81
+
82
+ export const makeQuestionReplyMessage = input => {
83
+ const data = requireObject(input, 'questionReply')
84
+ if (typeof data.text !== 'string' || !data.text.length) {
85
+ throw new TypeError('questionReply.text is required')
86
+ }
87
+ if (data.serverQuestionId === undefined || data.serverQuestionId === null) {
88
+ throw new TypeError('questionReply.serverQuestionId is required')
89
+ }
90
+ const quoted = {
91
+ serverQuestionId: Number(data.serverQuestionId)
92
+ }
93
+ if (data.quotedQuestion) quoted.quotedQuestion = data.quotedQuestion
94
+ if (data.quotedResponse) quoted.quotedResponse = data.quotedResponse
95
+ return {
96
+ questionReplyMessage: proto.Message.FutureProofMessage.create({
97
+ message: {
98
+ extendedTextMessage: proto.Message.ExtendedTextMessage.create({
99
+ text: data.text,
100
+ contextInfo: {
101
+ ...(data.contextInfo || {}),
102
+ questionReplyQuotedMessage: quoted
103
+ }
104
+ })
105
+ }
106
+ })
107
+ }
108
+ }
109
+
110
+ export const makeStatusQuestionAnswerMessage = input => {
111
+ const data = requireObject(input, 'statusQuestionAnswer')
112
+ requireKey(data.key, 'statusQuestionAnswer.key')
113
+ return {
114
+ statusQuestionAnswerMessage: proto.Message.StatusQuestionAnswerMessage.create({
115
+ key: data.key,
116
+ text: data.text ?? ''
117
+ })
118
+ }
119
+ }
120
+
121
+ export const makeStatusQuotedMessage = input => {
122
+ const data = requireObject(input, 'statusQuoted')
123
+ requireKey(data.originalStatusId, 'statusQuoted.originalStatusId')
124
+ const type = enumValue(
125
+ proto.Message.StatusQuotedMessage.StatusQuotedMessageType,
126
+ data.type,
127
+ proto.Message.StatusQuotedMessage.StatusQuotedMessageType.QUESTION_ANSWER
128
+ )
129
+ return {
130
+ statusQuotedMessage: proto.Message.StatusQuotedMessage.create({
131
+ type,
132
+ text: data.text,
133
+ thumbnail: data.thumbnail,
134
+ originalStatusId: data.originalStatusId
135
+ })
136
+ }
137
+ }
138
+
139
+ export const makeStatusStickerInteractionMessage = input => {
140
+ const data = requireObject(input, 'statusStickerInteraction')
141
+ requireKey(data.key, 'statusStickerInteraction.key')
142
+ if (!data.stickerKey) {
143
+ throw new TypeError('statusStickerInteraction.stickerKey is required')
144
+ }
145
+ const type = enumValue(
146
+ proto.Message.StatusStickerInteractionMessage.StatusStickerType,
147
+ data.type,
148
+ proto.Message.StatusStickerInteractionMessage.StatusStickerType.REACTION
149
+ )
150
+ return {
151
+ statusStickerInteractionMessage: proto.Message.StatusStickerInteractionMessage.create({
152
+ key: data.key,
153
+ stickerKey: data.stickerKey,
154
+ type
155
+ })
156
+ }
157
+ }
158
+
159
+ export const makeStatusNotificationMessage = input => {
160
+ const data = requireObject(input, 'statusNotification')
161
+ requireKey(data.responseMessageKey, 'statusNotification.responseMessageKey')
162
+ requireKey(data.originalMessageKey, 'statusNotification.originalMessageKey')
163
+ const type = enumValue(
164
+ STATUS_NOTIFICATION_TYPES,
165
+ data.type,
166
+ STATUS_NOTIFICATION_TYPES.UNKNOWN
167
+ )
168
+ return {
169
+ statusNotificationMessage: proto.Message.StatusNotificationMessage.create({
170
+ responseMessageKey: data.responseMessageKey,
171
+ originalMessageKey: data.originalMessageKey,
172
+ type
173
+ })
174
+ }
175
+ }
176
+
177
+ export const makeNewsletterAdminInviteMessage = input => {
178
+ const data = requireObject(input, 'newsletterAdminInvite')
179
+ if (!data.newsletterJid) {
180
+ throw new TypeError('newsletterAdminInvite.newsletterJid is required')
181
+ }
182
+ return {
183
+ newsletterAdminInviteMessage: proto.Message.NewsletterAdminInviteMessage.create({
184
+ newsletterJid: data.newsletterJid,
185
+ newsletterName: data.newsletterName,
186
+ jpegThumbnail: data.jpegThumbnail,
187
+ caption: data.caption,
188
+ inviteExpiration: data.inviteExpiration,
189
+ contextInfo: data.contextInfo
190
+ })
191
+ }
192
+ }
193
+
194
+ export const makeNewsletterFollowerInviteMessage = input => {
195
+ const data = requireObject(input, 'newsletterFollowerInvite')
196
+ if (!data.newsletterJid) {
197
+ throw new TypeError('newsletterFollowerInvite.newsletterJid is required')
198
+ }
199
+ return {
200
+ newsletterFollowerInviteMessageV2: proto.Message.NewsletterFollowerInviteMessage.create({
201
+ newsletterJid: data.newsletterJid,
202
+ newsletterName: data.newsletterName,
203
+ jpegThumbnail: data.jpegThumbnail,
204
+ caption: data.caption,
205
+ contextInfo: data.contextInfo
206
+ })
207
+ }
208
+ }
209
+
210
+ export const makePollAddOptionMessage = input => {
211
+ const data = requireObject(input, 'pollAddOption')
212
+ requireKey(data.pollCreationMessageKey, 'pollAddOption.pollCreationMessageKey')
213
+ const addOption = typeof data.option === 'string'
214
+ ? { optionName: data.option }
215
+ : data.addOption || data.option
216
+ if (!addOption?.optionName) {
217
+ throw new TypeError('pollAddOption.option is required')
218
+ }
219
+ return {
220
+ pollAddOptionMessage: proto.Message.PollAddOptionMessage.create({
221
+ pollCreationMessageKey: data.pollCreationMessageKey,
222
+ addOption,
223
+ metadata: data.metadata
224
+ })
225
+ }
226
+ }
227
+
228
+ export const makeCommentMessage = input => {
229
+ const data = requireObject(input, 'comment')
230
+ requireKey(data.targetMessageKey, 'comment.targetMessageKey')
231
+ const message = data.message || (data.content ? makeInnerCommentMessage(data.content) : null)
232
+ requireObject(message, 'comment.message')
233
+ return {
234
+ commentMessage: proto.Message.CommentMessage.create({
235
+ message,
236
+ targetMessageKey: data.targetMessageKey
237
+ })
238
+ }
239
+ }
240
+
241
+ export const makeEventInviteMessage = input => {
242
+ const data = requireObject(input, 'eventInvite')
243
+ if (!data.eventId) {
244
+ throw new TypeError('eventInvite.eventId is required')
245
+ }
246
+ return {
247
+ eventInviteMessage: proto.Message.EventInviteMessage.create({
248
+ contextInfo: data.contextInfo,
249
+ eventId: data.eventId,
250
+ eventTitle: data.eventTitle,
251
+ jpegThumbnail: data.jpegThumbnail,
252
+ startTime: toSeconds(data.startTime),
253
+ caption: data.caption,
254
+ isCanceled: data.isCanceled,
255
+ endTime: toSeconds(data.endTime),
256
+ callLink: data.callLink
257
+ })
258
+ }
259
+ }
260
+
261
+ export const makeScheduledCallCreationMessage = input => {
262
+ const data = requireObject(input, 'scheduledCall')
263
+ if (!data.scheduledTimestampMs) {
264
+ throw new TypeError('scheduledCall.scheduledTimestampMs is required')
265
+ }
266
+ const callType = enumValue(
267
+ proto.Message.ScheduledCallCreationMessage.CallType,
268
+ data.callType,
269
+ proto.Message.ScheduledCallCreationMessage.CallType.UNKNOWN
270
+ )
271
+ return {
272
+ scheduledCallCreationMessage: proto.Message.ScheduledCallCreationMessage.create({
273
+ scheduledTimestampMs: toMilliseconds(data.scheduledTimestampMs),
274
+ callType,
275
+ title: data.title
276
+ })
277
+ }
278
+ }
279
+
280
+ export const makeScheduledCallEditMessage = input => {
281
+ const data = requireObject(input, 'scheduledCallEdit')
282
+ requireKey(data.key, 'scheduledCallEdit.key')
283
+ const editType = enumValue(
284
+ proto.Message.ScheduledCallEditMessage.EditType,
285
+ data.editType,
286
+ proto.Message.ScheduledCallEditMessage.EditType.CANCEL
287
+ )
288
+ return {
289
+ scheduledCallEditMessage: proto.Message.ScheduledCallEditMessage.create({
290
+ key: data.key,
291
+ editType
292
+ })
293
+ }
294
+ }
295
+
296
+ export const makeGroupStatusReactionMessage = input => {
297
+ const data = requireObject(input, 'groupStatusReaction')
298
+ requireKey(data.key, 'groupStatusReaction.key')
299
+ return {
300
+ groupStatusMessageV2: proto.Message.FutureProofMessage.create({
301
+ message: {
302
+ reactionMessage: proto.Message.ReactionMessage.create({
303
+ key: data.key,
304
+ text: data.text ?? '',
305
+ groupingKey: data.groupingKey,
306
+ senderTimestampMs: data.senderTimestampMs || Date.now()
307
+ })
308
+ }
309
+ })
310
+ }
311
+ }
312
+
313
+ export const makeNewsletterStatusAttribution = input => {
314
+ const data = requireObject(input, 'newsletterStatus')
315
+ if (!data.newsletterJid) {
316
+ throw new TypeError('newsletterStatus.newsletterJid is required')
317
+ }
318
+ if (data.messageId === undefined || data.messageId === null) {
319
+ throw new TypeError('newsletterStatus.messageId is required')
320
+ }
321
+ return proto.StatusAttribution.create({
322
+ type: proto.StatusAttribution.Type.NEWSLETTER_STATUS,
323
+ actionUrl: data.actionUrl,
324
+ statusReshare: {
325
+ source: proto.StatusAttribution.StatusReshare.Source.CHANNEL_RESHARE,
326
+ metadata: {
327
+ duration: data.duration,
328
+ channelJid: data.newsletterJid,
329
+ channelMessageId: Number(data.messageId),
330
+ hasMultipleReshares: data.hasMultipleReshares ?? false
331
+ }
332
+ }
333
+ })
334
+ }
335
+
336
+ export const makeGroupStatusAttribution = input => {
337
+ const data = requireObject(input, 'groupStatusAttribution')
338
+ if (!data.authorJid) {
339
+ throw new TypeError('groupStatusAttribution.authorJid is required')
340
+ }
341
+ return proto.StatusAttribution.create({
342
+ type: proto.StatusAttribution.Type.GROUP_STATUS,
343
+ actionUrl: data.actionUrl,
344
+ groupStatus: {
345
+ authorJid: data.authorJid
346
+ }
347
+ })
348
+ }
349
+
350
+ export const STATUS_AUDIENCE_DEFAULT_LIST_NAME = 'Close friends'
351
+ export const STATUS_AUDIENCE_DEFAULT_EMOJI = '⭐'
352
+
353
+ export const makeStatusAudienceMetadata = input => {
354
+ const data = typeof input === 'string' ? { listName: input } : requireObject(input, 'statusAudience')
355
+ const audienceType = enumValue(
356
+ proto.ContextInfo.StatusAudienceMetadata.AudienceType,
357
+ data.audienceType,
358
+ proto.ContextInfo.StatusAudienceMetadata.AudienceType.CLOSE_FRIENDS
359
+ )
360
+ const listName = data.listName === undefined ? STATUS_AUDIENCE_DEFAULT_LIST_NAME : String(data.listName)
361
+ const listEmoji = data.listEmoji === undefined ? STATUS_AUDIENCE_DEFAULT_EMOJI : String(data.listEmoji)
362
+ return proto.ContextInfo.StatusAudienceMetadata.create({
363
+ audienceType,
364
+ listName,
365
+ listEmoji
366
+ })
367
+ }
368
+
369
+ export const makeMessageAssociation = input => {
370
+ const data = requireObject(input, 'messageAssociation')
371
+ const parentMessageKey = data.parentMessageKey ?? data.key
372
+ requireKey(parentMessageKey, 'messageAssociation.parentMessageKey')
373
+ const associationType = enumValue(
374
+ proto.MessageAssociation.AssociationType,
375
+ data.associationType ?? data.type,
376
+ proto.MessageAssociation.AssociationType.UNKNOWN
377
+ )
378
+ return proto.MessageAssociation.create({
379
+ associationType,
380
+ parentMessageKey,
381
+ messageIndex: data.messageIndex
382
+ })
383
+ }
384
+
385
+ export const makeStatusAddYoursAssociation = input => {
386
+ const data = input && typeof input === 'object' && !Array.isArray(input) && input.id
387
+ ? { key: input }
388
+ : requireObject(input, 'addYours')
389
+ const parentMessageKey = data.key ?? data.parentMessageKey
390
+ requireKey(parentMessageKey, 'addYours.key')
391
+ const associationType = enumValue(
392
+ proto.MessageAssociation.AssociationType,
393
+ data.type ?? data.associationType,
394
+ proto.MessageAssociation.AssociationType.STATUS_ADD_YOURS
395
+ )
396
+ return proto.MessageAssociation.create({
397
+ associationType,
398
+ parentMessageKey,
399
+ messageIndex: data.messageIndex
400
+ })
401
+ }
402
+
403
+ export const makeStatusMentionMessage = input => {
404
+ const data = requireObject(input, 'statusMention')
405
+ requireKey(data.key, 'statusMention.key')
406
+ const field = data.group ? 'groupStatusMentionMessage' : 'statusMentionMessage'
407
+ return {
408
+ [field]: proto.Message.FutureProofMessage.create({
409
+ message: {
410
+ protocolMessage: proto.Message.ProtocolMessage.create({
411
+ key: data.key,
412
+ type: proto.Message.ProtocolMessage.Type.STATUS_MENTION_MESSAGE
413
+ })
414
+ }
415
+ })
416
+ }
417
+ }
418
+
419
+ const modernBuilders = [
420
+ ['question', makeQuestionMessage],
421
+ ['questionReply', makeQuestionReplyMessage],
422
+ ['questionResponse', makeQuestionResponseMessage],
423
+ ['statusQuestionAnswer', makeStatusQuestionAnswerMessage],
424
+ ['statusQuoted', makeStatusQuotedMessage],
425
+ ['statusStickerInteraction', makeStatusStickerInteractionMessage],
426
+ ['statusNotification', makeStatusNotificationMessage],
427
+ ['newsletterAdminInvite', makeNewsletterAdminInviteMessage],
428
+ ['newsletterFollowerInvite', makeNewsletterFollowerInviteMessage],
429
+ ['pollAddOption', makePollAddOptionMessage],
430
+ ['comment', makeCommentMessage],
431
+ ['eventInvite', makeEventInviteMessage],
432
+ ['scheduledCall', makeScheduledCallCreationMessage],
433
+ ['scheduledCallEdit', makeScheduledCallEditMessage],
434
+ ['groupStatusReaction', makeGroupStatusReactionMessage],
435
+ ['statusMention', makeStatusMentionMessage]
436
+ ]
437
+
438
+ export const prepareModernMessageContent = content => {
439
+ if (!content || typeof content !== 'object' || Array.isArray(content)) return content
440
+ let output = { ...content }
441
+ const attributions = Array.isArray(output.contextInfo?.statusAttributions)
442
+ ? [...output.contextInfo.statusAttributions]
443
+ : []
444
+ if (output.newsletterStatus) {
445
+ attributions.push(makeNewsletterStatusAttribution(output.newsletterStatus))
446
+ delete output.newsletterStatus
447
+ }
448
+ if (output.groupStatusAttribution) {
449
+ attributions.push(makeGroupStatusAttribution(output.groupStatusAttribution))
450
+ delete output.groupStatusAttribution
451
+ }
452
+ if (Array.isArray(output.statusAttributions)) {
453
+ attributions.push(...output.statusAttributions)
454
+ delete output.statusAttributions
455
+ }
456
+ const carried = []
457
+ const audience = output.statusAudience
458
+ if (audience !== undefined && audience !== null) {
459
+ carried.push('statusAudience')
460
+ output.contextInfo = {
461
+ ...(output.contextInfo || {}),
462
+ statusAudienceMetadata: makeStatusAudienceMetadata(audience)
463
+ }
464
+ delete output.statusAudience
465
+ }
466
+ if (attributions.length) {
467
+ output.contextInfo = {
468
+ ...(output.contextInfo || {}),
469
+ statusAttributions: attributions
470
+ }
471
+ }
472
+ if (output.addYours !== undefined && output.addYours !== null) {
473
+ carried.push('addYours')
474
+ output.messageAssociation = makeStatusAddYoursAssociation(output.addYours)
475
+ delete output.addYours
476
+ }
477
+ else if (output.messageAssociation !== undefined && output.messageAssociation !== null) {
478
+ carried.push('messageAssociation')
479
+ output.messageAssociation = makeMessageAssociation(output.messageAssociation)
480
+ }
481
+ for (const [key, builder] of modernBuilders) {
482
+ if (output[key] !== undefined && output[key] !== null) {
483
+ if (carried.length) {
484
+ throw new TypeError(
485
+ `${carried.join(' and ')} cannot be combined with ${key}: ${key} builds its own message and keeps no room for them. `
486
+ + 'Build it with the low-level makers and generateWAMessageFromContent instead.'
487
+ )
488
+ }
489
+ return {
490
+ raw: true,
491
+ ...builder(output[key])
492
+ }
493
+ }
494
+ }
495
+ return output
496
+ }
@@ -0,0 +1,11 @@
1
+ export declare const NATIVE_FLOW_NAMES: readonly string[]
2
+ export declare const WEB_SUPPORTED_INTERACTIVE_FLOWS: readonly string[]
3
+ export declare const NATIVE_FLOW_BUTTON_LIMIT: Readonly<{ quickReply: number; other: number }>
4
+ export declare function getNativeFlowNameByButtonName(name: string): string | undefined
5
+ export declare function isWebSupportedButtonName(name: string): boolean
6
+ export declare function checkNativeFlowButtons(buttons: ({ name?: string } | string)[]): {
7
+ ok: boolean
8
+ limit: number
9
+ problems: string[]
10
+ unsupported: string[]
11
+ }
@@ -0,0 +1,115 @@
1
+ export const NATIVE_FLOW_NAMES = Object.freeze([
2
+ 'booking_confirmation',
3
+ 'order_details',
4
+ 'order_status',
5
+ 'payment_status',
6
+ 'payment_method',
7
+ 'payment_reminder',
8
+ 'message_with_link',
9
+ 'message_with_link_status',
10
+ 'quick_reply',
11
+ 'cta_call',
12
+ 'cta_url',
13
+ 'cta_catalog',
14
+ 'catalog_message',
15
+ 'payment_info',
16
+ 'cta_copy',
17
+ 'mixed',
18
+ 'galaxy_message',
19
+ 'cta_app',
20
+ 'call_permission_request',
21
+ 'payment_request',
22
+ 'api_signup',
23
+ 'inapp_signup',
24
+ 'form_message',
25
+ 'menu_options',
26
+ 'a2ui_reply_action',
27
+ 'address_message',
28
+ 'mpm'
29
+ ])
30
+
31
+ const BUTTON_NAME_TO_FLOW = Object.freeze({
32
+ review_and_pay: 'order_details',
33
+ payment_info: 'payment_info',
34
+ review_order: 'order_status',
35
+ order_status: 'order_status',
36
+ payment_status: 'payment_status',
37
+ payment_method: 'payment_method',
38
+ open_webview: 'message_with_link',
39
+ message_with_link_status: 'message_with_link_status',
40
+ cta_url: 'cta_url',
41
+ cta_call: 'cta_call',
42
+ quick_reply: 'quick_reply',
43
+ catalog_message: 'catalog_message',
44
+ cta_catalog: 'cta_catalog',
45
+ cta_copy: 'cta_copy',
46
+ galaxy_message: 'galaxy_message',
47
+ payment_reminder: 'payment_reminder',
48
+ booking_confirmation: 'booking_confirmation',
49
+ call_permission_request: 'call_permission_request',
50
+ payment_request: 'payment_request',
51
+ api_signup: 'api_signup',
52
+ inapp_signup: 'inapp_signup',
53
+ cta_app: 'cta_app',
54
+ form_message: 'form_message',
55
+ address_message: 'address_message',
56
+ mpm: 'mpm'
57
+ })
58
+
59
+ export const WEB_SUPPORTED_INTERACTIVE_FLOWS = Object.freeze([
60
+ 'quick_reply',
61
+ 'cta_call',
62
+ 'cta_url',
63
+ 'cta_catalog',
64
+ 'catalog_message',
65
+ 'cta_copy',
66
+ 'galaxy_message',
67
+ 'order_status',
68
+ 'payment_reminder',
69
+ 'booking_confirmation',
70
+ 'payment_request',
71
+ 'api_signup',
72
+ 'inapp_signup',
73
+ 'cta_app',
74
+ 'form_message'
75
+ ])
76
+
77
+ export const NATIVE_FLOW_BUTTON_LIMIT = Object.freeze({
78
+ quickReply: 10,
79
+ other: 3
80
+ })
81
+
82
+ export const getNativeFlowNameByButtonName = (name) => BUTTON_NAME_TO_FLOW[name]
83
+
84
+ export const isWebSupportedButtonName = (name) => {
85
+ const flow = getNativeFlowNameByButtonName(name)
86
+ return flow !== undefined && WEB_SUPPORTED_INTERACTIVE_FLOWS.includes(flow)
87
+ }
88
+
89
+ export const checkNativeFlowButtons = (buttons) => {
90
+ const list = (Array.isArray(buttons) ? buttons : []).map(button => (typeof button === 'string' ? { name: button } : button))
91
+ const problems = []
92
+
93
+ if (!list.length) {
94
+ return { ok: true, limit: NATIVE_FLOW_BUTTON_LIMIT.other, problems, unsupported: [] }
95
+ }
96
+
97
+ const firstIsQuickReply = list[0]?.name === 'quick_reply'
98
+ const limit = firstIsQuickReply ? NATIVE_FLOW_BUTTON_LIMIT.quickReply : NATIVE_FLOW_BUTTON_LIMIT.other
99
+
100
+ if (list.length > limit) {
101
+ problems.push(`WhatsApp Web renders at most ${limit} buttons when the first one is ${firstIsQuickReply ? 'quick_reply' : 'not quick_reply'}, got ${list.length}`)
102
+ }
103
+
104
+ const unsupported = [...new Set(list.map(button => button?.name).filter(name => !isWebSupportedButtonName(name)))]
105
+ for (const name of unsupported) {
106
+ problems.push(`"${name}" is not a native flow WhatsApp Web or iOS can render, only Android shows it`)
107
+ }
108
+
109
+ const mixesKinds = list.slice(1).some(button => (button?.name === 'quick_reply') !== firstIsQuickReply)
110
+ if (mixesKinds) {
111
+ problems.push('quick_reply buttons cannot be mixed with other button types in one message')
112
+ }
113
+
114
+ return { ok: problems.length === 0, limit, problems, unsupported }
115
+ }