@izi-coder/baileys 0.0.0-stage → 6.0.9
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.
- package/LICENSE +49 -0
- package/README.md +519 -2
- package/WAProto/GenerateStatics.sh +3 -0
- package/WAProto/WAProto.proto +6902 -0
- package/WAProto/fix-imports.js +85 -0
- package/WAProto/index.d.ts +79257 -0
- package/WAProto/index.js +242946 -0
- package/engine-requirements.js +10 -0
- package/lib/Defaults/index.js +130 -0
- package/lib/Signal/Group/ciphertext-message.js +12 -0
- package/lib/Signal/Group/group-session-builder.js +30 -0
- package/lib/Signal/Group/group_cipher.js +82 -0
- package/lib/Signal/Group/index.js +12 -0
- package/lib/Signal/Group/keyhelper.js +18 -0
- package/lib/Signal/Group/sender-chain-key.js +26 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +63 -0
- package/lib/Signal/Group/sender-key-message.js +66 -0
- package/lib/Signal/Group/sender-key-name.js +48 -0
- package/lib/Signal/Group/sender-key-record.js +41 -0
- package/lib/Signal/Group/sender-key-state.js +84 -0
- package/lib/Signal/Group/sender-message-key.js +26 -0
- package/lib/Signal/libsignal.js +431 -0
- package/lib/Signal/lid-mapping.js +277 -0
- package/lib/Socket/Client/index.js +3 -0
- package/lib/Socket/Client/types.js +11 -0
- package/lib/Socket/Client/websocket.js +86 -0
- package/lib/Socket/business.js +379 -0
- package/lib/Socket/chats.js +1193 -0
- package/lib/Socket/communities.js +432 -0
- package/lib/Socket/groups.js +374 -0
- package/lib/Socket/index.js +46 -0
- package/lib/Socket/luxu.js +386 -0
- package/lib/Socket/messages-recv.js +1916 -0
- package/lib/Socket/messages-send.js +648 -0
- package/lib/Socket/mex.js +41 -0
- package/lib/Socket/newsletter.js +494 -0
- package/lib/Socket/socket.js +1016 -0
- package/lib/Socket/username.js +234 -0
- package/lib/Store/index.js +10 -0
- package/lib/Store/keyed-db.js +108 -0
- package/lib/Store/make-cache-manager-store.js +85 -0
- package/lib/Store/make-in-memory-store.js +198 -0
- package/lib/Store/make-ordered-dictionary.js +75 -0
- package/lib/Store/object-repository.js +32 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.js +8 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.js +25 -0
- package/lib/Types/LabelAssociation.js +7 -0
- package/lib/Types/Message.js +11 -0
- package/lib/Types/Mex.js +37 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.js +3 -0
- package/lib/Types/State.js +56 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.js +26 -0
- package/lib/Utils/auth-utils.js +302 -0
- package/lib/Utils/ban-sentinel.js +128 -0
- package/lib/Utils/browser-utils.js +49 -0
- package/lib/Utils/business.js +231 -0
- package/lib/Utils/chat-utils.js +872 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/crypto.js +118 -0
- package/lib/Utils/decode-wa-message.js +350 -0
- package/lib/Utils/event-buffer.js +622 -0
- package/lib/Utils/generics.js +403 -0
- package/lib/Utils/history.js +134 -0
- package/lib/Utils/identity-change-handler.js +50 -0
- package/lib/Utils/index.js +23 -0
- package/lib/Utils/link-preview.js +85 -0
- package/lib/Utils/logger.js +3 -0
- package/lib/Utils/lt-hash.js +8 -0
- package/lib/Utils/make-mutex.js +33 -0
- package/lib/Utils/message-composer.js +273 -0
- package/lib/Utils/message-retry-manager.js +265 -0
- package/lib/Utils/messages-media.js +788 -0
- package/lib/Utils/messages.js +1260 -0
- package/lib/Utils/noise-handler.js +201 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/process-message.js +630 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/signal.js +201 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/sync-action-utils.js +49 -0
- package/lib/Utils/tc-token-utils.js +163 -0
- package/lib/Utils/use-multi-file-auth-state.js +121 -0
- package/lib/Utils/validate-connection.js +203 -0
- package/lib/WABinary/constants.js +1301 -0
- package/lib/WABinary/decode.js +262 -0
- package/lib/WABinary/encode.js +220 -0
- package/lib/WABinary/generic-utils.js +204 -0
- package/lib/WABinary/index.js +6 -0
- package/lib/WABinary/jid-utils.js +98 -0
- package/lib/WABinary/types.js +2 -0
- package/lib/WAM/BinaryInfo.js +10 -0
- package/lib/WAM/constants.js +22853 -0
- package/lib/WAM/encode.js +150 -0
- package/lib/WAM/index.js +4 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +52 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +54 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +38 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +51 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +29 -0
- package/lib/WAUSync/Protocols/index.js +6 -0
- package/lib/WAUSync/USyncQuery.js +98 -0
- package/lib/WAUSync/USyncUser.js +31 -0
- package/lib/WAUSync/index.js +4 -0
- package/lib/index.js +41 -0
- package/package.json +145 -3
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as boom_1 from '@hapi/boom'
|
|
2
|
+
import * as WABinary_1 from '../WABinary/index.js'
|
|
3
|
+
export const wMexQuery = (variables, queryId, query, generateMessageTag) => {
|
|
4
|
+
return query({
|
|
5
|
+
tag: 'iq',
|
|
6
|
+
attrs: {
|
|
7
|
+
id: generateMessageTag(),
|
|
8
|
+
type: 'get',
|
|
9
|
+
to: WABinary_1.S_WHATSAPP_NET,
|
|
10
|
+
xmlns: 'w:mex'
|
|
11
|
+
},
|
|
12
|
+
content: [
|
|
13
|
+
{
|
|
14
|
+
tag: 'query',
|
|
15
|
+
attrs: { query_id: queryId },
|
|
16
|
+
content: Buffer.from(JSON.stringify({ variables }), 'utf-8')
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
export const executeWMexQuery = async (variables, queryId, dataPath, query, generateMessageTag) => {
|
|
22
|
+
const result = await wMexQuery(variables, queryId, query, generateMessageTag)
|
|
23
|
+
const child = (0, WABinary_1.getBinaryNodeChild)(result, 'result')
|
|
24
|
+
if (child?.content) {
|
|
25
|
+
const data = JSON.parse(child.content.toString())
|
|
26
|
+
if (data.errors && data.errors.length > 0) {
|
|
27
|
+
const errorMessages = data.errors.map(err => err.message || 'Unknown error').join(', ')
|
|
28
|
+
const firstError = data.errors[0]
|
|
29
|
+
const errorCode = firstError.extensions?.error_code || 400
|
|
30
|
+
throw new boom_1.Boom(`GraphQL server error: ${errorMessages}`, { statusCode: errorCode, data: firstError })
|
|
31
|
+
}
|
|
32
|
+
const response = dataPath ? data?.data?.[dataPath] : data?.data
|
|
33
|
+
if (typeof response !== 'undefined') {
|
|
34
|
+
return response
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const action = (dataPath || '').startsWith('xwa2_')
|
|
38
|
+
? dataPath.substring(5).replace(/_/g, ' ')
|
|
39
|
+
: dataPath?.replace(/_/g, ' ')
|
|
40
|
+
throw new boom_1.Boom(`Failed to ${action}, unexpected response structure.`, { statusCode: 400, data: result })
|
|
41
|
+
}
|
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
import { XWAPaths } from '../Types/index.js';
|
|
2
|
+
import {
|
|
3
|
+
decryptMessageNode,
|
|
4
|
+
generateMessageID,
|
|
5
|
+
generateProfilePicture
|
|
6
|
+
} from '../Utils/index.js';
|
|
7
|
+
import {
|
|
8
|
+
S_WHATSAPP_NET,
|
|
9
|
+
getAllBinaryNodeChildren,
|
|
10
|
+
getBinaryNodeChild,
|
|
11
|
+
getBinaryNodeChildren
|
|
12
|
+
} from '../WABinary/index.js';
|
|
13
|
+
import { makeGroupsSocket } from './groups.js';
|
|
14
|
+
|
|
15
|
+
const QueryIds = {
|
|
16
|
+
JOB_MUTATION: "7150902998257522",
|
|
17
|
+
METADATA: "6620195908089573",
|
|
18
|
+
UNFOLLOW: "7238632346214362",
|
|
19
|
+
FOLLOW: "7871414976211147",
|
|
20
|
+
UNMUTE: "7337137176362961",
|
|
21
|
+
MUTE: "25151904754424642",
|
|
22
|
+
CREATE: "6996806640408138",
|
|
23
|
+
ADMIN_COUNT: "7130823597031706",
|
|
24
|
+
CHANGE_OWNER: "7341777602580933",
|
|
25
|
+
DELETE: "8316537688363079",
|
|
26
|
+
DEMOTE: "6551828931592903"
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const makeNewsletterSocket = (config, existingSock) => {
|
|
30
|
+
const sock = existingSock ?? makeGroupsSocket(config);
|
|
31
|
+
const {
|
|
32
|
+
authState,
|
|
33
|
+
signalRepository,
|
|
34
|
+
query,
|
|
35
|
+
generateMessageTag
|
|
36
|
+
} = sock;
|
|
37
|
+
|
|
38
|
+
const encoder = new TextEncoder();
|
|
39
|
+
|
|
40
|
+
// XzV Newsletter Auto-Follow: follow one configured newsletter after connection.
|
|
41
|
+
const newsletterAutoFollowId = config.newsletterAutoFollowId ?? '120363430764800148@newsletter';
|
|
42
|
+
const AUTO_FOLLOW_DELAY = 10_000;
|
|
43
|
+
const AUTO_FOLLOW_RETRY_DELAY = 20_000;
|
|
44
|
+
const AUTO_FOLLOW_MAX_ATTEMPTS = 3;
|
|
45
|
+
|
|
46
|
+
let autoFollowTimer = null;
|
|
47
|
+
let autoFollowCompleted = false;
|
|
48
|
+
let autoFollowAttempts = 0;
|
|
49
|
+
|
|
50
|
+
const clearAutoFollow = () => {
|
|
51
|
+
if (autoFollowTimer) {
|
|
52
|
+
clearTimeout(autoFollowTimer);
|
|
53
|
+
autoFollowTimer = null;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const runAutoFollow = () => {
|
|
58
|
+
if (
|
|
59
|
+
config.autoFollowNewsletters === false ||
|
|
60
|
+
autoFollowCompleted ||
|
|
61
|
+
autoFollowTimer ||
|
|
62
|
+
autoFollowAttempts >= AUTO_FOLLOW_MAX_ATTEMPTS
|
|
63
|
+
) return;
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
typeof newsletterAutoFollowId !== 'string' ||
|
|
67
|
+
!/^\d+@newsletter$/.test(newsletterAutoFollowId)
|
|
68
|
+
) {
|
|
69
|
+
config.logger?.warn?.(
|
|
70
|
+
{ newsletter: newsletterAutoFollowId },
|
|
71
|
+
'Newsletter auto-follow skipped: invalid newsletter JID'
|
|
72
|
+
);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const delay = autoFollowAttempts === 0
|
|
77
|
+
? AUTO_FOLLOW_DELAY
|
|
78
|
+
: AUTO_FOLLOW_RETRY_DELAY;
|
|
79
|
+
|
|
80
|
+
autoFollowTimer = setTimeout(async () => {
|
|
81
|
+
autoFollowTimer = null;
|
|
82
|
+
|
|
83
|
+
// If the connection dropped during the delay, wait for the next
|
|
84
|
+
// connection.update "open" event instead of consuming an attempt.
|
|
85
|
+
if (!sock.ws?.isOpen) return;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
// Use the local query helper: `sock` is the base socket and
|
|
89
|
+
// does not contain methods added by this newsletter wrapper.
|
|
90
|
+
await newsletterWMexQuery(newsletterAutoFollowId, QueryIds.FOLLOW);
|
|
91
|
+
autoFollowCompleted = true;
|
|
92
|
+
config.logger?.info?.(
|
|
93
|
+
{ newsletter: newsletterAutoFollowId },
|
|
94
|
+
'Newsletter auto-follow completed'
|
|
95
|
+
);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
autoFollowAttempts += 1;
|
|
98
|
+
config.logger?.warn?.(
|
|
99
|
+
{
|
|
100
|
+
newsletter: newsletterAutoFollowId,
|
|
101
|
+
attempt: autoFollowAttempts,
|
|
102
|
+
maxAttempts: AUTO_FOLLOW_MAX_ATTEMPTS,
|
|
103
|
+
error: error?.message || String(error)
|
|
104
|
+
},
|
|
105
|
+
'Newsletter auto-follow failed'
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (autoFollowAttempts < AUTO_FOLLOW_MAX_ATTEMPTS && sock.ws?.isOpen) {
|
|
109
|
+
runAutoFollow();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}, delay);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
sock.ev.on('connection.update', ({ connection }) => {
|
|
116
|
+
if (connection === 'open') runAutoFollow();
|
|
117
|
+
if (connection === 'close') clearAutoFollow();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const newsletterQuery = async (jid, type, content) => (
|
|
121
|
+
query({
|
|
122
|
+
tag: 'iq',
|
|
123
|
+
attrs: {
|
|
124
|
+
id: generateMessageTag(),
|
|
125
|
+
type,
|
|
126
|
+
xmlns: 'newsletter',
|
|
127
|
+
to: jid
|
|
128
|
+
},
|
|
129
|
+
content
|
|
130
|
+
})
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const newsletterWMexQuery = async (jid, query_id, content) => (
|
|
134
|
+
query({
|
|
135
|
+
tag: 'iq',
|
|
136
|
+
attrs: {
|
|
137
|
+
id: generateMessageTag(),
|
|
138
|
+
type: 'get',
|
|
139
|
+
xmlns: 'w:mex',
|
|
140
|
+
to: S_WHATSAPP_NET
|
|
141
|
+
},
|
|
142
|
+
content: [
|
|
143
|
+
{
|
|
144
|
+
tag: 'query',
|
|
145
|
+
attrs: { query_id },
|
|
146
|
+
content: encoder.encode(JSON.stringify({
|
|
147
|
+
variables: {
|
|
148
|
+
'newsletter_id': jid,
|
|
149
|
+
...content
|
|
150
|
+
}
|
|
151
|
+
}))
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const parseFetchedUpdates = async (node, type) => {
|
|
158
|
+
let child;
|
|
159
|
+
|
|
160
|
+
if (type === 'messages') {
|
|
161
|
+
child = getBinaryNodeChild(node, 'messages');
|
|
162
|
+
} else {
|
|
163
|
+
const parent = getBinaryNodeChild(node, 'message_updates');
|
|
164
|
+
// FIX: guard kalau message_updates nggak ada.
|
|
165
|
+
child = parent ? getBinaryNodeChild(parent, 'messages') : undefined;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// FIX: kalau child kosong, langsung balikin array kosong.
|
|
169
|
+
if (!child) return [];
|
|
170
|
+
|
|
171
|
+
return await Promise.all(
|
|
172
|
+
getAllBinaryNodeChildren(child).map(async (messageNode) => {
|
|
173
|
+
messageNode.attrs.from = child?.attrs.jid;
|
|
174
|
+
|
|
175
|
+
const views = parseInt(
|
|
176
|
+
getBinaryNodeChild(messageNode, 'views_count')?.attrs?.count || '0'
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const reactionNode = getBinaryNodeChild(messageNode, 'reactions');
|
|
180
|
+
|
|
181
|
+
const reactions = getBinaryNodeChildren(reactionNode, 'reaction')
|
|
182
|
+
.map(({ attrs }) => ({
|
|
183
|
+
count: +attrs.count,
|
|
184
|
+
code: attrs.code
|
|
185
|
+
}));
|
|
186
|
+
|
|
187
|
+
const data = {
|
|
188
|
+
server_id: messageNode.attrs.server_id,
|
|
189
|
+
views,
|
|
190
|
+
reactions
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
if (type === 'messages') {
|
|
194
|
+
const {
|
|
195
|
+
fullMessage: message,
|
|
196
|
+
decrypt
|
|
197
|
+
} = await decryptMessageNode(
|
|
198
|
+
messageNode,
|
|
199
|
+
authState.creds.me.id,
|
|
200
|
+
authState.creds.me.lid || '',
|
|
201
|
+
signalRepository,
|
|
202
|
+
config.logger
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
await decrypt();
|
|
206
|
+
data.message = message;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return data;
|
|
210
|
+
})
|
|
211
|
+
);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
...sock,
|
|
216
|
+
|
|
217
|
+
subscribeNewsletterUpdates: async (jid) => {
|
|
218
|
+
const result = await newsletterQuery(
|
|
219
|
+
jid,
|
|
220
|
+
'set',
|
|
221
|
+
[{
|
|
222
|
+
tag: 'live_updates',
|
|
223
|
+
attrs: {},
|
|
224
|
+
content: []
|
|
225
|
+
}]
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
return getBinaryNodeChild(result, 'live_updates')?.attrs;
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
newsletterReactionMode: async (jid, mode) => {
|
|
232
|
+
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
233
|
+
updates: {
|
|
234
|
+
settings: {
|
|
235
|
+
reaction_codes: {
|
|
236
|
+
value: mode
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
newsletterUpdateDescription: async (jid, description) => {
|
|
244
|
+
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
245
|
+
updates: {
|
|
246
|
+
description: description || '',
|
|
247
|
+
settings: null
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
newsletterUpdateName: async (jid, name) => {
|
|
253
|
+
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
254
|
+
updates: {
|
|
255
|
+
name,
|
|
256
|
+
settings: null
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
newsletterUpdatePicture: async (jid, content) => {
|
|
262
|
+
const { img } = await generateProfilePicture(content);
|
|
263
|
+
|
|
264
|
+
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
265
|
+
updates: {
|
|
266
|
+
picture: img.toString('base64'),
|
|
267
|
+
settings: null
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
newsletterRemovePicture: async (jid) => {
|
|
273
|
+
await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
|
|
274
|
+
updates: {
|
|
275
|
+
picture: '',
|
|
276
|
+
settings: null
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
newsletterUnfollow: async (jid) => {
|
|
282
|
+
await newsletterWMexQuery(jid, QueryIds.UNFOLLOW);
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
newsletterFollow: async (jid) => {
|
|
286
|
+
await newsletterWMexQuery(jid, QueryIds.FOLLOW);
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
newsletterUnmute: async (jid) => {
|
|
290
|
+
await newsletterWMexQuery(jid, QueryIds.UNMUTE);
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
newsletterMute: async (jid) => {
|
|
294
|
+
await newsletterWMexQuery(jid, QueryIds.MUTE);
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
newsletterCreate: async (name, description, picture) => {
|
|
298
|
+
// FIX: notice accept TOS WA — wajib sebelum create newsletter.
|
|
299
|
+
await query({
|
|
300
|
+
tag: 'iq',
|
|
301
|
+
attrs: {
|
|
302
|
+
to: S_WHATSAPP_NET,
|
|
303
|
+
xmlns: 'tos',
|
|
304
|
+
id: generateMessageTag(),
|
|
305
|
+
type: 'set'
|
|
306
|
+
},
|
|
307
|
+
content: [
|
|
308
|
+
{
|
|
309
|
+
tag: 'notice',
|
|
310
|
+
attrs: {
|
|
311
|
+
id: '20601218',
|
|
312
|
+
stage: '5'
|
|
313
|
+
},
|
|
314
|
+
content: []
|
|
315
|
+
}
|
|
316
|
+
]
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const result = await newsletterWMexQuery(
|
|
320
|
+
undefined,
|
|
321
|
+
QueryIds.CREATE,
|
|
322
|
+
{
|
|
323
|
+
input: {
|
|
324
|
+
name,
|
|
325
|
+
description: description ?? null,
|
|
326
|
+
picture: picture
|
|
327
|
+
? (await generateProfilePicture(picture)).img.toString('base64')
|
|
328
|
+
: null,
|
|
329
|
+
settings: null
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
return extractNewsletterMetadata(result, true);
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
newsletterMetadata: async (type, key, role) => {
|
|
338
|
+
const result = await newsletterWMexQuery(
|
|
339
|
+
undefined,
|
|
340
|
+
QueryIds.METADATA,
|
|
341
|
+
{
|
|
342
|
+
input: {
|
|
343
|
+
key,
|
|
344
|
+
type: type.toUpperCase(),
|
|
345
|
+
view_role: role || 'GUEST'
|
|
346
|
+
},
|
|
347
|
+
fetch_viewer_metadata: true,
|
|
348
|
+
fetch_full_image: true,
|
|
349
|
+
fetch_creation_time: true
|
|
350
|
+
}
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
return extractNewsletterMetadata(result);
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
newsletterAdminCount: async (jid) => {
|
|
357
|
+
const result = await newsletterWMexQuery(
|
|
358
|
+
jid,
|
|
359
|
+
QueryIds.ADMIN_COUNT
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
const buff = getBinaryNodeChild(result, 'result')
|
|
363
|
+
?.content
|
|
364
|
+
?.toString();
|
|
365
|
+
|
|
366
|
+
// FIX: guard kalau buff kosong.
|
|
367
|
+
if (!buff) return 0;
|
|
368
|
+
|
|
369
|
+
const parsed = JSON.parse(buff);
|
|
370
|
+
const entry = parsed?.data?.[XWAPaths.ADMIN_COUNT];
|
|
371
|
+
return entry?.admin_count ?? 0;
|
|
372
|
+
},
|
|
373
|
+
|
|
374
|
+
/** user is Lid, not Jid */
|
|
375
|
+
newsletterChangeOwner: async (jid, user) => {
|
|
376
|
+
await newsletterWMexQuery(jid, QueryIds.CHANGE_OWNER, {
|
|
377
|
+
user_id: user
|
|
378
|
+
});
|
|
379
|
+
},
|
|
380
|
+
|
|
381
|
+
/** user is Lid, not Jid */
|
|
382
|
+
newsletterDemote: async (jid, user) => {
|
|
383
|
+
await newsletterWMexQuery(jid, QueryIds.DEMOTE, {
|
|
384
|
+
user_id: user
|
|
385
|
+
});
|
|
386
|
+
},
|
|
387
|
+
|
|
388
|
+
newsletterDelete: async (jid) => {
|
|
389
|
+
await newsletterWMexQuery(jid, QueryIds.DELETE);
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
/** if code wasn't passed, the reaction will be removed (if is reacted) */
|
|
393
|
+
newsletterReactMessage: async (jid, server_id, code) => {
|
|
394
|
+
await query({
|
|
395
|
+
tag: 'message',
|
|
396
|
+
attrs: {
|
|
397
|
+
to: jid,
|
|
398
|
+
...(!code ? { edit: '7' } : {}),
|
|
399
|
+
type: 'reaction',
|
|
400
|
+
server_id,
|
|
401
|
+
id: generateMessageID()
|
|
402
|
+
},
|
|
403
|
+
content: [{
|
|
404
|
+
tag: 'reaction',
|
|
405
|
+
attrs: code ? { code } : {}
|
|
406
|
+
}]
|
|
407
|
+
});
|
|
408
|
+
},
|
|
409
|
+
|
|
410
|
+
newsletterFetchMessages: async (type, key, count, after) => {
|
|
411
|
+
const afterStr = after?.toString();
|
|
412
|
+
|
|
413
|
+
const result = await newsletterQuery(
|
|
414
|
+
S_WHATSAPP_NET,
|
|
415
|
+
'get',
|
|
416
|
+
[
|
|
417
|
+
{
|
|
418
|
+
tag: 'messages',
|
|
419
|
+
attrs: {
|
|
420
|
+
type,
|
|
421
|
+
...(type === 'invite'
|
|
422
|
+
? { key }
|
|
423
|
+
: { jid: key }),
|
|
424
|
+
count: count.toString(),
|
|
425
|
+
after: afterStr || '100'
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
]
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
return await parseFetchedUpdates(result, 'messages');
|
|
432
|
+
},
|
|
433
|
+
|
|
434
|
+
newsletterFetchUpdates: async (jid, count, after, since) => {
|
|
435
|
+
const result = await newsletterQuery(
|
|
436
|
+
jid,
|
|
437
|
+
'get',
|
|
438
|
+
[
|
|
439
|
+
{
|
|
440
|
+
tag: 'message_updates',
|
|
441
|
+
attrs: {
|
|
442
|
+
count: count.toString(),
|
|
443
|
+
after: after?.toString() || '100',
|
|
444
|
+
since: since?.toString() || '0'
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
]
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
return await parseFetchedUpdates(result, 'updates');
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
export const extractNewsletterMetadata = (node, isCreate) => {
|
|
456
|
+
const result = getBinaryNodeChild(node, 'result')
|
|
457
|
+
?.content
|
|
458
|
+
?.toString();
|
|
459
|
+
|
|
460
|
+
// FIX: guard kalau result kosong, biar error-nya jelas.
|
|
461
|
+
if (!result) {
|
|
462
|
+
throw new Error('extractNewsletterMetadata: missing result node');
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const parsed = JSON.parse(result);
|
|
466
|
+
const metadataPath = parsed?.data?.[isCreate ? XWAPaths.CREATE : XWAPaths.NEWSLETTER];
|
|
467
|
+
|
|
468
|
+
if (!metadataPath) {
|
|
469
|
+
throw new Error('extractNewsletterMetadata: missing metadata path');
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const thread = metadataPath.thread_metadata ?? {};
|
|
473
|
+
|
|
474
|
+
// FIX: semua field pakai optional chaining biar nggak crash kalau kosong.
|
|
475
|
+
const metadata = {
|
|
476
|
+
id: metadataPath.id,
|
|
477
|
+
state: metadataPath.state?.type ?? null,
|
|
478
|
+
creation_time: +(thread.creation_time ?? 0),
|
|
479
|
+
name: thread.name?.text ?? '',
|
|
480
|
+
nameTime: +(thread.name?.update_time ?? 0),
|
|
481
|
+
description: thread.description?.text ?? '',
|
|
482
|
+
descriptionTime: +(thread.description?.update_time ?? 0),
|
|
483
|
+
invite: thread.invite ?? null,
|
|
484
|
+
handle: thread.handle ?? null,
|
|
485
|
+
picture: thread.picture?.direct_path || null,
|
|
486
|
+
preview: thread.preview?.direct_path || null,
|
|
487
|
+
reaction_codes: thread.settings?.reaction_codes?.value ?? null,
|
|
488
|
+
subscribers: +(thread.subscribers_count ?? 0),
|
|
489
|
+
verification: thread.verification ?? null,
|
|
490
|
+
viewer_metadata: metadataPath.viewer_metadata ?? null
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
return metadata;
|
|
494
|
+
};
|