@awangxcode/qiro-baileys 7.0.0-rc23 → 7.0.0-rc25.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 (61) hide show
  1. package/README.md +6 -0
  2. package/WAProto/WAProto.proto +47 -0
  3. package/WAProto/index.d.ts +115 -2
  4. package/WAProto/index.js +299 -0
  5. package/lib/Defaults/index.d.ts.map +1 -1
  6. package/lib/Defaults/index.js +2 -0
  7. package/lib/Defaults/index.js.map +1 -1
  8. package/lib/Extensions/advanced.d.ts +247 -0
  9. package/lib/Extensions/advanced.d.ts.map +1 -0
  10. package/lib/Extensions/advanced.js +821 -0
  11. package/lib/Extensions/advanced.js.map +1 -0
  12. package/lib/Extensions/experimental.d.ts +378 -0
  13. package/lib/Extensions/experimental.d.ts.map +1 -0
  14. package/lib/Extensions/experimental.js +628 -0
  15. package/lib/Extensions/experimental.js.map +1 -0
  16. package/lib/MessageBuilder/index.d.ts +4 -0
  17. package/lib/MessageBuilder/index.d.ts.map +1 -1
  18. package/lib/MessageBuilder/index.js +4 -1
  19. package/lib/MessageBuilder/index.js.map +1 -1
  20. package/lib/Socket/business.d.ts +5 -3
  21. package/lib/Socket/business.d.ts.map +1 -1
  22. package/lib/Socket/chats.d.ts +4 -2
  23. package/lib/Socket/chats.d.ts.map +1 -1
  24. package/lib/Socket/chats.js.map +1 -1
  25. package/lib/Socket/communities.d.ts +5 -3
  26. package/lib/Socket/communities.d.ts.map +1 -1
  27. package/lib/Socket/groups.d.ts +4 -2
  28. package/lib/Socket/groups.d.ts.map +1 -1
  29. package/lib/Socket/index.d.ts +6 -4
  30. package/lib/Socket/index.d.ts.map +1 -1
  31. package/lib/Socket/index.js +9 -1
  32. package/lib/Socket/index.js.map +1 -1
  33. package/lib/Socket/messages-recv.d.ts +5 -3
  34. package/lib/Socket/messages-recv.d.ts.map +1 -1
  35. package/lib/Socket/messages-send.d.ts +5 -3
  36. package/lib/Socket/messages-send.d.ts.map +1 -1
  37. package/lib/Socket/messages-send.js +65 -5
  38. package/lib/Socket/messages-send.js.map +1 -1
  39. package/lib/Socket/newsletter.d.ts +4 -2
  40. package/lib/Socket/newsletter.d.ts.map +1 -1
  41. package/lib/Types/Message.d.ts +11 -0
  42. package/lib/Types/Message.d.ts.map +1 -1
  43. package/lib/Types/Socket.d.ts +4 -0
  44. package/lib/Types/Socket.d.ts.map +1 -1
  45. package/lib/Utils/messages-media.d.ts +4 -2
  46. package/lib/Utils/messages-media.d.ts.map +1 -1
  47. package/lib/Utils/messages-media.js +14 -11
  48. package/lib/Utils/messages-media.js.map +1 -1
  49. package/lib/Utils/messages.d.ts.map +1 -1
  50. package/lib/Utils/messages.js +20 -3
  51. package/lib/Utils/messages.js.map +1 -1
  52. package/lib/WABinary/generic-utils.d.ts +16 -0
  53. package/lib/WABinary/generic-utils.d.ts.map +1 -1
  54. package/lib/WABinary/generic-utils.js +111 -0
  55. package/lib/WABinary/generic-utils.js.map +1 -1
  56. package/lib/index.d.ts +2 -0
  57. package/lib/index.d.ts.map +1 -1
  58. package/lib/index.js +2 -0
  59. package/lib/index.js.map +1 -1
  60. package/package.json +6 -1
  61. package/THIRD_PARTY_NOTICES.md +0 -15
@@ -0,0 +1,628 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes, randomUUID } from 'crypto';
2
+ import { proto } from '../../WAProto/index.js';
3
+ import { generateWAMessageFromContent, prepareWAMessageMedia } from '../Utils/messages.js';
4
+ import { sha256 } from '../Utils/crypto.js';
5
+ import { generateMessageIDV2 } from '../Utils/generics.js';
6
+ import { normalizeUserJid } from './advanced.js';
7
+ const resolveUserJid = (sock) => sock.user?.id || sock.authState?.creds?.me?.id;
8
+ const messageId = (sock) => sock?.generateMessageTag?.() || generateMessageIDV2();
9
+ const safeHttpUrl = (value) => {
10
+ let url;
11
+ try {
12
+ url = new URL(value);
13
+ }
14
+ catch {
15
+ throw new TypeError('A valid absolute URL is required');
16
+ }
17
+ if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password)
18
+ throw new TypeError('Only credential-free http/https URLs are supported');
19
+ return url.toString();
20
+ };
21
+ export const WEBUI_PRIMITIVE_TYPENAME = 'GenAIaeacdsnwHtmlPrimitive';
22
+ export const DEFAULT_WEBUI_BOT_JID = '867051314767696@bot';
23
+ export const WEBUI_MAX_PAYLOAD_BYTES = 64 * 1024;
24
+ /** Builds an internal WhatsApp WebUI payload. Rendering depends on WhatsApp client-side gates and can stop working without notice. */
25
+ export const buildWebuiMessage = ({ html, title = 'WebUI', botJid = DEFAULT_WEBUI_BOT_JID, forwardOrigin = proto.ContextInfo.ForwardOrigin.META_AI, responseId = randomUUID() }) => {
26
+ if (typeof html !== 'string' || html.length === 0)
27
+ throw new TypeError('html must be a non-empty string');
28
+ if (Buffer.byteLength(html, 'utf8') > WEBUI_MAX_PAYLOAD_BYTES)
29
+ throw new RangeError(`HTML payload exceeds ${WEBUI_MAX_PAYLOAD_BYTES} bytes`);
30
+ const data = {
31
+ response_id: responseId,
32
+ sections: [{ view_model: { primitive: { __typename: WEBUI_PRIMITIVE_TYPENAME, payload: html, trusted_sources: [] }, __typename: 'GenAISingleLayoutViewModel' } }]
33
+ };
34
+ return {
35
+ messageContextInfo: { deviceListMetadata: {}, deviceListMetadataVersion: 2, botMetadata: { botResponseId: responseId } },
36
+ botForwardedMessage: {
37
+ message: {
38
+ richResponseMessage: {
39
+ messageType: 1,
40
+ submessages: [{ messageType: 2, messageText: title }],
41
+ unifiedResponse: { data: Buffer.from(JSON.stringify(data), 'utf8').toString('base64') },
42
+ contextInfo: { forwardingScore: 1, isForwarded: true, forwardedAiBotMessageInfo: { botJid }, forwardOrigin }
43
+ }
44
+ }
45
+ }
46
+ };
47
+ };
48
+ export const sendInlineWebUI = async (sock, jid, html, title = 'WebUI', options = {}) => {
49
+ if (!sock || typeof sock.relayMessage !== 'function')
50
+ throw new TypeError('sock.relayMessage() is required');
51
+ const { messageId: customId, ...buildOptions } = options;
52
+ const message = buildWebuiMessage({ html, title, ...buildOptions });
53
+ const id = customId || messageId(sock);
54
+ await sock.relayMessage(normalizeUserJid(jid), message, { messageId: id });
55
+ return { messageId: id, message };
56
+ };
57
+ const DEFAULT_A2UI_CATALOG = 'https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json';
58
+ /** Declarative A2UI builder. The WhatsApp Bloks widget wire format is experimental. */
59
+ export class A2UI {
60
+ constructor(options = {}) {
61
+ this.components = new Map();
62
+ this.counter = 0;
63
+ this.rootChildren = [];
64
+ this.version = options.version || 'v0.9';
65
+ this.catalogId = options.catalogId || DEFAULT_A2UI_CATALOG;
66
+ }
67
+ nextId(prefix) { return `${prefix.toLowerCase()}_${(this.counter++).toString(36)}`; }
68
+ register(id, component, extra = {}) {
69
+ const finalId = id || this.nextId(component);
70
+ if (this.components.has(finalId))
71
+ throw new Error(`A2UI component id already exists: ${finalId}`);
72
+ this.components.set(finalId, { id: finalId, component, ...extra });
73
+ return finalId;
74
+ }
75
+ text(text, options = {}) { return this.register(options.id, 'Text', { text, variant: options.variant || 'body' }); }
76
+ image(url, options = {}) { return this.register(options.id, 'Image', { url: safeHttpUrl(url), ...(options.variant ? { variant: options.variant } : {}), fit: options.fit || 'cover' }); }
77
+ video(url, options = {}) { return this.register(options.id, 'Video', { url: safeHttpUrl(url) }); }
78
+ checkbox(label, options = {}) { return this.register(options.id, 'CheckBox', { label, value: options.value ?? false }); }
79
+ textField(label, options = {}) { return this.register(options.id, 'TextField', { label, variant: options.variant || 'text' }); }
80
+ button(childId, options = {}) {
81
+ if (!childId)
82
+ throw new TypeError('button() requires a child component id');
83
+ return this.register(options.id, 'Button', { child: childId, variant: options.variant || 'primary', ...(options.action ? { action: options.action } : {}) });
84
+ }
85
+ card(childId, options = {}) { return this.register(options.id, 'Card', { child: childId }); }
86
+ column(children, options = {}) {
87
+ if (!Array.isArray(children) || children.length === 0)
88
+ throw new TypeError('column() requires child ids');
89
+ return this.register(options.id, 'Column', { children, ...(options.justify ? { justify: options.justify } : {}), ...(options.align ? { align: options.align } : {}) });
90
+ }
91
+ row(children, options = {}) {
92
+ if (!Array.isArray(children) || children.length === 0)
93
+ throw new TypeError('row() requires child ids');
94
+ return this.register(options.id, 'Row', { children });
95
+ }
96
+ divider(options = {}) { return this.register(options.id, 'Divider', {}); }
97
+ choicePicker(label, optionsList, options = {}) {
98
+ if (!Array.isArray(optionsList) || !optionsList.length)
99
+ throw new TypeError('choicePicker() requires at least one option');
100
+ return this.register(options.id, 'ChoicePicker', { label, variant: options.variant || 'mutuallyExclusive', ...(options.value !== undefined ? { value: options.value } : {}), options: optionsList, displayStyle: options.displayStyle || 'checkbox', filterable: options.filterable ?? false });
101
+ }
102
+ root(children) {
103
+ if (!Array.isArray(children) || !children.length)
104
+ throw new TypeError('root() requires at least one top-level child id');
105
+ this.rootChildren = [...children];
106
+ return this;
107
+ }
108
+ listCard(options) {
109
+ if (!options?.title || !Array.isArray(options.items) || options.items.length === 0)
110
+ throw new TypeError('listCard() requires title and items');
111
+ const uuid = options.uuid || randomUUID();
112
+ this.listCardPayload = {
113
+ uuid,
114
+ type: 'im_a2ui',
115
+ fallback: options.fallbackText || '',
116
+ data: JSON.stringify({ type: 'list_card', title: options.title, fallback_text: options.fallbackText || '', items: options.items.map(item => ({ asset_id: item.assetId || randomUUID().replace(/-/g, '').slice(0, 17), asset_type: item.assetType || 'PRODUCT_ITEM', title: item.title, trailing_label: item.price || item.trailingLabel || '', trailing_emphasis: item.emphasis || 'strong' })) })
117
+ };
118
+ return this;
119
+ }
120
+ build(options = {}) {
121
+ if (this.listCardPayload)
122
+ return { ...this.listCardPayload };
123
+ if (!this.rootChildren.length)
124
+ throw new Error('Call root([...ids]) before build()');
125
+ const uuid = options.uuid || randomUUID();
126
+ const components = [{ id: 'root', component: 'Column', children: this.rootChildren }, ...this.components.values()];
127
+ const data = options.wrapped === false ? { components } : { version: this.version, createSurface: { surfaceId: options.surfaceId || `starcore-widget=${uuid}`, catalogId: this.catalogId, components } };
128
+ return { uuid, data: JSON.stringify(data), type: options.type || 'im_a2ui' };
129
+ }
130
+ }
131
+ export const sendA2UIWidget = async (sock, jid, options) => {
132
+ if (!sock || typeof sock.relayMessage !== 'function')
133
+ throw new TypeError('sock.relayMessage() is required');
134
+ if (!(options?.a2ui instanceof A2UI))
135
+ throw new TypeError('options.a2ui must be an A2UI instance');
136
+ const { a2ui, bodyText = '', footer = '', buttons = [], contextInfo = {}, expiration, quoted, type = 'im_a2ui', wrapped = true, singleScreen = false } = options;
137
+ const nativeFlowMessage = buttons.length ? { buttons: buttons.map(button => ({ name: button.name || 'cta_url', buttonParamsJson: typeof button.params === 'string' ? button.params : JSON.stringify(button.params ?? {}) })), messageParamsJson: '{}', messageVersion: 1 } : { messageParamsJson: '' };
138
+ const interactiveMessage = {
139
+ ...(singleScreen ? {} : { header: { hasMediaAttachment: false }, body: { text: bodyText }, footer: { text: footer } }),
140
+ nativeFlowMessage,
141
+ bloksWidget: a2ui.build({ type, wrapped }),
142
+ ...(expiration || Object.keys(contextInfo).length ? { contextInfo: { ...(expiration ? { expiration } : {}), ...contextInfo } } : {})
143
+ };
144
+ const message = generateWAMessageFromContent(normalizeUserJid(jid), { messageContextInfo: { messageSecret: randomBytes(32) }, interactiveMessage }, { userJid: resolveUserJid(sock), quoted });
145
+ await sock.relayMessage(message.key.remoteJid, message.message, {
146
+ messageId: message.key.id,
147
+ additionalNodes: [{ tag: 'biz', attrs: { actual_actors: '2', host_storage: '2', privacy_mode_ts: String(Math.floor(Date.now() / 1000)) }, content: [
148
+ { tag: 'interactive', attrs: { type: 'native_flow', v: '1' }, content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }] },
149
+ { tag: 'quality_control', attrs: { decision_id: randomUUID().replace(/-/g, ''), source_type: 'third_party' }, content: [{ tag: 'decision_source', attrs: { value: 'df' } }] }
150
+ ] }]
151
+ });
152
+ return message;
153
+ };
154
+ const WEBUI_TTL_MS = 24 * 60 * 60 * 1000;
155
+ const toolCallId = () => randomBytes(8).toString('hex');
156
+ const richSection = (viewModel) => ({ __typename: 'GenAIUnifiedResponseSection', view_model: viewModel });
157
+ const richSingle = (primitive) => richSection({ __typename: 'GenAISingleLayoutViewModel', primitive });
158
+ const inlineRichImage = (image, options = {}) => ({
159
+ __typename: 'GenAIMarkdownTextUXPrimitive', text: '{{header}}.{{/header}}', inline_entities: [{
160
+ __typename: 'GenAITextInlineEntity', key: 'header', metadata: {
161
+ __typename: 'GenAILatexItem', latex_expression: '.', font_height: 24, padding: options.padding ?? 4,
162
+ latex_image: { __typename: 'GenAIMediaItem', mime_type: image.mime_type || 'image/png', url: image.url, url_fallback: image.url, width: image.width || options.width || 500, height: image.height || options.height || 500, expiration_timestamp_ms: Date.now() + WEBUI_TTL_MS }
163
+ }
164
+ }]
165
+ });
166
+ const normalizeRichButton = (button, fallbackToast) => ({
167
+ label: String(typeof button === 'string' ? button : button?.label ?? button?.text ?? ''), state: 'PENDING', kind: 'OTHER', tool_call_id: toolCallId(),
168
+ toast: { label: (typeof button === 'object' && button?.toast !== undefined ? button.toast : fallbackToast) || '', __typename: 'GenAI3PExtWidgetToast' },
169
+ __typename: 'GenAI3PExtWidgetCTA'
170
+ });
171
+ const richWidget = (title, buttons, toast) => ({
172
+ __typename: 'GenAI3PExtWidgetPrimitive', header: { __typename: 'GenAI3PExtWidgetStandardHeader', title: title || '' },
173
+ body: { __typename: 'GenAI3PExtCalendarEventList', ctas: buttons.map(button => normalizeRichButton(button, toast)), sections: [] }
174
+ });
175
+ /** Builds a GenAI rich-menu wire payload. Button CTAs may be decorative and not bot reply-buttons. */
176
+ export const buildRichMenuMessage = (content = {}) => {
177
+ const { header, body, footer } = content;
178
+ const sections = [];
179
+ let messageContextInfo;
180
+ if (header) {
181
+ const { disclaimer = false, disclaimerText = ' ', image, title = '' } = header;
182
+ if (disclaimer)
183
+ messageContextInfo = { botMetadata: { messageDisclaimerText: disclaimerText } };
184
+ if (title)
185
+ sections.push(richSingle({ __typename: 'FOATextPrimitive', text: `# ${title}` }));
186
+ if (image?.url) {
187
+ const url = safeHttpUrl(image.url);
188
+ sections.push(richSingle(image.inline ? inlineRichImage({ ...image, url }, { width: 500, height: 500, padding: 4 }) : {
189
+ __typename: 'GenAIImagePrimitive', preview_image: { __typename: 'GenAIMediaItem', mime_type: image.mime_type || 'image/png', url },
190
+ full_image: { __typename: 'GenAIMediaItem', mime_type: image.mime_type || 'image/png', url }
191
+ }));
192
+ }
193
+ }
194
+ if (body) {
195
+ const { cards, buttons, title = '', toast = '', carousel = false, row = false } = body;
196
+ if ((carousel || row) && Array.isArray(cards) && cards.length)
197
+ sections.push(richSection({ __typename: carousel ? 'GenAIHScrollLayoutViewModel' : 'GenAIActionRowLayoutViewModel', primitives: cards.map((card) => richWidget(card?.title, card?.buttons || [], card?.toast || '')) }));
198
+ else if (Array.isArray(buttons) && buttons.length)
199
+ sections.push(richSingle(richWidget(title, buttons, toast)));
200
+ }
201
+ if (footer) {
202
+ const primitives = [];
203
+ if (footer.url)
204
+ primitives.push({ __typename: 'GenAIFooterActionPrimitive', cta_text: footer.text || 'Open', cta_type: 'OPEN_URL', cta_url: safeHttpUrl(footer.url) });
205
+ if (footer.image?.url)
206
+ primitives.push(inlineRichImage({ ...footer.image, url: safeHttpUrl(footer.image.url) }, { width: 100, height: 100, padding: -5 }));
207
+ if (primitives.length)
208
+ sections.push({ view_model: { __typename: 'GenAIActionRowLayoutViewModel', primitives } });
209
+ }
210
+ if (!sections.length)
211
+ throw new TypeError('richMenu requires at least one non-empty header, body, or footer section');
212
+ return {
213
+ ...(messageContextInfo ? { messageContextInfo } : {}),
214
+ botForwardedMessage: { message: { richResponseMessage: { messageType: 1, unifiedResponse: { data: Buffer.from(JSON.stringify({ sections })).toString('base64') }, contextInfo: { isForwarded: true, forwardOrigin: proto.ContextInfo.ForwardOrigin.META_AI, ...(content.contextInfo || {}) } } } }
215
+ };
216
+ };
217
+ export const sendRichMenu = async (sock, jid, content, options = {}) => {
218
+ if (!sock || typeof sock.relayMessage !== 'function')
219
+ throw new TypeError('sock.relayMessage() is required');
220
+ const message = buildRichMenuMessage(content);
221
+ const id = options.messageId || messageId(sock);
222
+ await sock.relayMessage(normalizeUserJid(jid), message, { messageId: id });
223
+ return { messageId: id, message };
224
+ };
225
+ export const hashImagePollOption = (optionName, fileSha256) => {
226
+ const nameHash = sha256(Buffer.from(String(optionName), 'utf8')).toString('hex');
227
+ const mediaHashBase64 = fileSha256 ? Buffer.from(fileSha256).toString('base64') : '';
228
+ return sha256(Buffer.from(nameHash + mediaHashBase64, 'utf8')).toString('hex');
229
+ };
230
+ export const sendImagePoll = async (sock, jid, options) => {
231
+ if (!sock?.relayMessage || !sock.waUploadToServer)
232
+ throw new TypeError('sendImagePoll requires a connected socket with waUploadToServer()');
233
+ if (!options?.name?.trim())
234
+ throw new TypeError('image poll name is required');
235
+ if (!Array.isArray(options.options) || options.options.length < 2 || options.options.length > 12)
236
+ throw new RangeError('image poll requires 2–12 options');
237
+ const names = options.options.map(option => String(option?.name || '').trim());
238
+ if (names.some(name => !name) || new Set(names).size !== names.length)
239
+ throw new TypeError('every image poll option needs a unique non-empty name');
240
+ const selectableCount = options.selectableCount ?? 1;
241
+ if (!Number.isInteger(selectableCount) || selectableCount < 1 || selectableCount > options.options.length)
242
+ throw new RangeError('selectableCount must be between 1 and the number of options');
243
+ const uploaded = [];
244
+ const pollOptions = [];
245
+ for (let index = 0; index < options.options.length; index++) {
246
+ const option = options.options[index];
247
+ const name = names[index];
248
+ if (!option || !name)
249
+ throw new TypeError(`image poll option ${index + 1} is invalid`);
250
+ const media = await prepareWAMessageMedia({ image: option.image }, { upload: sock.waUploadToServer, logger: sock.logger });
251
+ uploaded.push(media);
252
+ pollOptions.push({ optionName: name, optionHash: hashImagePollOption(name, media.imageMessage?.fileSha256) });
253
+ }
254
+ const secret = options.messageSecret ? Buffer.from(options.messageSecret) : randomBytes(32);
255
+ if (secret.length !== 32)
256
+ throw new RangeError('messageSecret must be exactly 32 bytes');
257
+ const poll = generateWAMessageFromContent(normalizeUserJid(jid), {
258
+ pollCreationMessageV3: { name: options.name, selectableOptionsCount: selectableCount, options: pollOptions, pollContentType: 2 },
259
+ messageContextInfo: { messageSecret: secret }
260
+ }, { userJid: resolveUserJid(sock), quoted: options.quoted });
261
+ await sock.relayMessage(poll.key.remoteJid, poll.message, { messageId: poll.key.id, additionalNodes: [{ tag: 'meta', attrs: { polltype: 'creation' } }] });
262
+ for (const media of uploaded) {
263
+ const optionContent = proto.Message.create({
264
+ pollCreationOptionImageMessage: { message: media },
265
+ messageContextInfo: { messageAssociation: { associationType: proto.MessageAssociation.AssociationType.MEDIA_POLL, parentMessageKey: poll.key } }
266
+ });
267
+ const optionMessage = generateWAMessageFromContent(normalizeUserJid(jid), optionContent, { userJid: resolveUserJid(sock) });
268
+ await sock.relayMessage(optionMessage.key.remoteJid, optionMessage.message, { messageId: optionMessage.key.id });
269
+ }
270
+ return poll;
271
+ };
272
+ export const SCHEDULED_MSG_WINDOW = Object.freeze({ minDelaySeconds: 600, maxChatDelaySeconds: 14 * 24 * 60 * 60, maxChannelDelaySeconds: 30 * 24 * 60 * 60, maxPerChat: 30, revealKeyRetentionSeconds: 30 * 24 * 60 * 60 });
273
+ export const isScheduledTimeValid = (timestampSeconds, options = {}) => {
274
+ if (!Number.isFinite(timestampSeconds))
275
+ return false;
276
+ const now = options.nowSeconds ?? Math.floor(Date.now() / 1000);
277
+ const delta = Math.floor(timestampSeconds) - now;
278
+ return delta >= SCHEDULED_MSG_WINDOW.minDelaySeconds && delta <= (options.channel ? SCHEDULED_MSG_WINDOW.maxChannelDelaySeconds : SCHEDULED_MSG_WINDOW.maxChatDelaySeconds);
279
+ };
280
+ /** Encrypts a protobuf message for WhatsApp's conditional-reveal scheduled-message protocol. Server/account support is not guaranteed. */
281
+ export const encodeScheduledMessage = (content, options = {}) => {
282
+ const revealKey = options.revealKey ? Buffer.from(options.revealKey) : randomBytes(32);
283
+ const encIv = options.encIv ? Buffer.from(options.encIv) : randomBytes(12);
284
+ if (revealKey.length !== 32 || encIv.length !== 12)
285
+ throw new RangeError('scheduled-message key must be 32 bytes and IV must be 12 bytes');
286
+ const revealKeyId = options.revealKeyId || randomUUID().replace(/-/g, '').slice(0, 16);
287
+ const plaintext = Buffer.from(proto.Message.encode(proto.Message.create(content)).finish());
288
+ const cipher = createCipheriv('aes-256-gcm', revealKey, encIv);
289
+ const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final(), cipher.getAuthTag()]);
290
+ return { revealKey, revealKeyId, encIv, encPayload: encrypted, message: { conditionalRevealMessage: { encPayload: encrypted, encIv, conditionalRevealMessageType: 1, revealKeyId } } };
291
+ };
292
+ export const decodeScheduledMessage = (message, revealKeyInput) => {
293
+ const revealKey = Buffer.from(revealKeyInput);
294
+ if (revealKey.length !== 32)
295
+ throw new RangeError('revealKey must be 32 bytes');
296
+ const wrapper = message?.conditionalRevealMessage || message?.message?.conditionalRevealMessage || message;
297
+ if (!wrapper?.encPayload || !wrapper?.encIv)
298
+ throw new TypeError('conditionalRevealMessage with encPayload and encIv is required');
299
+ const encrypted = Buffer.from(wrapper.encPayload);
300
+ if (encrypted.length < 16)
301
+ throw new Error('scheduled-message payload is too short');
302
+ const encIv = Buffer.from(wrapper.encIv);
303
+ const decipher = createDecipheriv('aes-256-gcm', revealKey, encIv);
304
+ decipher.setAuthTag(encrypted.subarray(encrypted.length - 16));
305
+ const plaintext = Buffer.concat([decipher.update(encrypted.subarray(0, encrypted.length - 16)), decipher.final()]);
306
+ return proto.Message.decode(plaintext);
307
+ };
308
+ export const buildScheduledMsgMetaNode = ({ scheduledTimestampS, revealKeyId, revealKey }) => {
309
+ if (!Number.isInteger(scheduledTimestampS) || !revealKeyId)
310
+ throw new TypeError('scheduledTimestampS and revealKeyId are required');
311
+ const key = Buffer.from(revealKey);
312
+ if (key.length !== 32)
313
+ throw new RangeError('revealKey must be 32 bytes');
314
+ return { tag: 'meta', attrs: { type: 'scheduled_message', st: String(scheduledTimestampS) }, content: [{ tag: 'key', attrs: { rkid: revealKeyId }, content: key }] };
315
+ };
316
+ export const sendScheduledMessage = async (sock, jid, content, scheduledTimestampS, options = {}) => {
317
+ if (!isScheduledTimeValid(scheduledTimestampS, { channel: options.channel }))
318
+ throw new RangeError('Scheduled time must be at least 10 minutes in the future and within the client-derived window');
319
+ const scheduled = encodeScheduledMessage(content, options);
320
+ const id = messageId(sock);
321
+ await sock.relayMessage(normalizeUserJid(jid), scheduled.message, { messageId: id, additionalNodes: [buildScheduledMsgMetaNode({ scheduledTimestampS, revealKeyId: scheduled.revealKeyId, revealKey: scheduled.revealKey })] });
322
+ return { ...scheduled, messageId: id, scheduledTimestampS };
323
+ };
324
+ /** Builds message payload for an experimental poll option append (requires a poll created with canAddOption on supported clients). */
325
+ export const makePollAddOptionMessage = (pollCreationMessageKey, option) => {
326
+ if (!pollCreationMessageKey?.id || !option?.trim())
327
+ throw new TypeError('poll key and option text are required');
328
+ return {
329
+ pollAddOptionMessage: { pollCreationMessageKey, addOption: { optionName: option.trim() } },
330
+ messageContextInfo: { messageAssociation: { associationType: proto.MessageAssociation.AssociationType.POLL_ADD_OPTION, parentMessageKey: pollCreationMessageKey } }
331
+ };
332
+ };
333
+ export const sendPollAddOption = async (sock, jid, pollCreationMessageKey, option) => {
334
+ const generated = generateWAMessageFromContent(normalizeUserJid(jid), makePollAddOptionMessage(pollCreationMessageKey, option), { userJid: resolveUserJid(sock) });
335
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
336
+ return generated;
337
+ };
338
+ export const makeNewsletterAdminInviteMessage = (options) => {
339
+ if (!options?.newsletterJid?.endsWith('@newsletter'))
340
+ throw new TypeError('newsletterJid must end in @newsletter');
341
+ if (!options.newsletterName?.trim())
342
+ throw new TypeError('newsletterName is required');
343
+ if (options.inviteExpiration !== undefined && (!Number.isFinite(options.inviteExpiration) || options.inviteExpiration <= 0))
344
+ throw new RangeError('inviteExpiration must be a positive Unix timestamp');
345
+ return { newsletterAdminInviteMessage: { ...options, newsletterName: options.newsletterName.trim() } };
346
+ };
347
+ export const makeNewsletterFollowerInviteMessage = (options) => {
348
+ if (!options?.newsletterJid?.endsWith('@newsletter'))
349
+ throw new TypeError('newsletterJid must end in @newsletter');
350
+ if (!options.newsletterName?.trim())
351
+ throw new TypeError('newsletterName is required');
352
+ return { newsletterFollowerInviteMessageV2: { newsletterJid: options.newsletterJid, newsletterName: options.newsletterName.trim(), caption: options.caption, jpegThumbnail: options.jpegThumbnail, contextInfo: options.contextInfo } };
353
+ };
354
+ export const sendNewsletterAdminInvite = async (sock, recipientJid, options) => {
355
+ const jid = normalizeUserJid(recipientJid);
356
+ const generated = generateWAMessageFromContent(jid, makeNewsletterAdminInviteMessage(options), { userJid: resolveUserJid(sock) });
357
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
358
+ return generated;
359
+ };
360
+ export const sendNewsletterFollowerInvite = async (sock, recipientJid, options) => {
361
+ const jid = normalizeUserJid(recipientJid);
362
+ const generated = generateWAMessageFromContent(jid, makeNewsletterFollowerInviteMessage(options), { userJid: resolveUserJid(sock) });
363
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
364
+ return generated;
365
+ };
366
+ export const makeScheduledCallCreationMessage = (options) => {
367
+ if (!Number.isFinite(options?.scheduledTimestampMs) || options.scheduledTimestampMs <= Date.now())
368
+ throw new RangeError('scheduledTimestampMs must be a future Unix timestamp in milliseconds');
369
+ if (![1, 2].includes(options.callType))
370
+ throw new RangeError('callType must be 1 (voice) or 2 (video)');
371
+ return { scheduledCallCreationMessage: { scheduledTimestampMs: Math.trunc(options.scheduledTimestampMs), callType: options.callType, title: options.title?.trim() } };
372
+ };
373
+ export const makeScheduledCallEditMessage = (key, editType = 1) => {
374
+ if (!key?.id)
375
+ throw new TypeError('scheduled call message key is required');
376
+ if (![1].includes(editType))
377
+ throw new RangeError('editType must be 1 (cancel)');
378
+ return { scheduledCallEditMessage: { key, editType } };
379
+ };
380
+ export const sendScheduledCallCreation = async (sock, jid, options) => {
381
+ const normalized = normalizeUserJid(jid);
382
+ const generated = generateWAMessageFromContent(normalized, makeScheduledCallCreationMessage(options), { userJid: resolveUserJid(sock) });
383
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
384
+ return generated;
385
+ };
386
+ export const sendScheduledCallEdit = async (sock, jid, key, editType = 1) => {
387
+ const normalized = normalizeUserJid(jid);
388
+ const generated = generateWAMessageFromContent(normalized, makeScheduledCallEditMessage(key, editType), { userJid: resolveUserJid(sock) });
389
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
390
+ return generated;
391
+ };
392
+ export const makeStatusAudienceMetadata = (options = {}) => ({
393
+ audienceType: options.audienceType ?? proto.ContextInfo.StatusAudienceMetadata.AudienceType.CLOSE_FRIENDS,
394
+ ...(options.listName ? { listName: options.listName } : {}),
395
+ ...(options.listEmoji ? { listEmoji: options.listEmoji } : {})
396
+ });
397
+ export const makeNewsletterStatusAttribution = (newsletterJid, channelMessageId, duration) => {
398
+ if (!newsletterJid?.endsWith('@newsletter'))
399
+ throw new TypeError('newsletterJid must end in @newsletter');
400
+ if (!Number.isInteger(channelMessageId) || channelMessageId < 0)
401
+ throw new RangeError('channelMessageId must be a non-negative integer');
402
+ return { type: proto.StatusAttribution.Type.RESHARE, statusReshare: { source: proto.StatusAttribution.StatusReshare.Source.CHANNEL_RESHARE, metadata: { channelJid: newsletterJid, channelMessageId, ...(duration !== undefined ? { duration } : {}) } } };
403
+ };
404
+ export const makeGroupStatusAttribution = (authorJid) => {
405
+ const jid = normalizeUserJid(authorJid);
406
+ return { type: proto.StatusAttribution.Type.GROUP_STATUS, groupStatus: { authorJid: jid } };
407
+ };
408
+ export const LOCATION_BROADCAST_JID = 'location@broadcast';
409
+ export const isJidLocationBroadcast = (jid) => jid === LOCATION_BROADCAST_JID;
410
+ export const makeQuestionMessage = (question) => {
411
+ if (!question?.trim())
412
+ throw new TypeError('question text is required');
413
+ return { questionMessage: { message: { extendedTextMessage: { text: question.trim(), contextInfo: { isQuestion: true } } } } };
414
+ };
415
+ export const makeQuestionResponseMessage = (questionKey, text) => {
416
+ if (!questionKey?.id || !text?.trim())
417
+ throw new TypeError('question key and response text are required');
418
+ return { questionResponseMessage: { key: questionKey, text: text.trim() } };
419
+ };
420
+ export const makeStatusLinkPreviewMetadata = (style) => {
421
+ if (!Number.isInteger(style) || style < 0)
422
+ throw new RangeError('status link preview style must be a non-negative integer');
423
+ return { statusLinkPreviewMetadata: { style } };
424
+ };
425
+ export const sendStatusLinkPreview = async (sock, text, style, recipients, options = {}) => {
426
+ if (!text?.trim())
427
+ throw new TypeError('status text is required');
428
+ if (!Array.isArray(recipients) || recipients.length === 0)
429
+ throw new TypeError('explicit status recipients are required');
430
+ const generated = generateWAMessageFromContent('status@broadcast', {
431
+ extendedTextMessage: { text: text.trim() },
432
+ ...makeStatusLinkPreviewMetadata(style),
433
+ messageContextInfo: { messageSecret: randomBytes(32) }
434
+ }, { userJid: resolveUserJid(sock) });
435
+ await sock.relayMessage('status@broadcast', generated.message, { messageId: options.messageId || generated.key.id, statusJidList: recipients.map(normalizeUserJid) });
436
+ return generated;
437
+ };
438
+ export const sendQuestionMessage = async (sock, jid, question, options = {}) => {
439
+ const normalized = normalizeUserJid(jid);
440
+ const generated = generateWAMessageFromContent(normalized, makeQuestionMessage(question), { userJid: resolveUserJid(sock), quoted: options.quoted });
441
+ const additionalNodes = normalized.endsWith('@newsletter') ? [{ tag: 'meta', attrs: { questiontype: 'question' } }] : [];
442
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: options.messageId || generated.key.id, ...(additionalNodes.length ? { additionalNodes } : {}) });
443
+ return generated;
444
+ };
445
+ export const makeStatusQuestionAnswerMessage = (key, text) => {
446
+ if (!key?.id || !text?.trim())
447
+ throw new TypeError('status key and answer text are required');
448
+ return { statusQuestionAnswerMessage: { key, text: text.trim() } };
449
+ };
450
+ export const makeStatusQuotedMessage = (originalStatusId, text, thumbnail) => {
451
+ if (!originalStatusId?.id || !text?.trim())
452
+ throw new TypeError('original status key and quoted text are required');
453
+ return { statusQuotedMessage: { type: 1, originalStatusId, text: text.trim(), ...(thumbnail ? { thumbnail } : {}) } };
454
+ };
455
+ export const makeStatusStickerInteractionMessage = (key, stickerKey, type = 1) => {
456
+ if (!key?.id || !stickerKey)
457
+ throw new TypeError('status key and stickerKey are required');
458
+ return { statusStickerInteractionMessage: { key, stickerKey, type } };
459
+ };
460
+ export const makeStatusNotificationMessage = (responseMessageKey, originalMessageKey, type = 1) => {
461
+ if (!responseMessageKey?.id || !originalMessageKey?.id)
462
+ throw new TypeError('response and original message keys are required');
463
+ return { statusNotificationMessage: { responseMessageKey, originalMessageKey, type } };
464
+ };
465
+ export const makeStatusMentionMessage = (targetStatusKey, group = false) => {
466
+ if (!targetStatusKey?.id)
467
+ throw new TypeError('target status key is required');
468
+ const payload = { message: { protocolMessage: { key: targetStatusKey, type: 25 } } };
469
+ return group ? { groupStatusMentionMessage: payload } : { statusMentionMessage: payload };
470
+ };
471
+ export const makeCommentMessage = (targetMessageKey, text) => {
472
+ if (!targetMessageKey?.id || !text?.trim())
473
+ throw new TypeError('target message key and comment are required');
474
+ return { commentMessage: { targetMessageKey, message: { conversation: text.trim() } } };
475
+ };
476
+ export const sendQuestionResponse = async (sock, jid, questionKey, text) => {
477
+ const normalized = normalizeUserJid(jid);
478
+ const generated = generateWAMessageFromContent(normalized, makeQuestionResponseMessage(questionKey, text), { userJid: resolveUserJid(sock) });
479
+ const additionalNodes = normalized.endsWith('@newsletter') ? [{ tag: 'meta', attrs: { questiontype: 'response' } }] : [];
480
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id, ...(additionalNodes.length ? { additionalNodes } : {}) });
481
+ return generated;
482
+ };
483
+ export const sendStatusQuestionAnswer = async (sock, jid, statusKey, text) => {
484
+ const normalized = normalizeUserJid(jid);
485
+ const message = makeStatusQuestionAnswerMessage(statusKey, text);
486
+ const generated = generateWAMessageFromContent(normalized, {
487
+ ...message,
488
+ messageContextInfo: { messageAssociation: { associationType: 16, parentMessageKey: statusKey }, messageSecret: randomBytes(32) }
489
+ }, { userJid: resolveUserJid(sock) });
490
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
491
+ return generated;
492
+ };
493
+ export const sendStatusQuoted = async (sock, jid, statusKey, text, thumbnail) => {
494
+ const normalized = normalizeUserJid(jid);
495
+ const generated = generateWAMessageFromContent(normalized, makeStatusQuotedMessage(statusKey, text, thumbnail), { userJid: resolveUserJid(sock) });
496
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
497
+ return generated;
498
+ };
499
+ export const sendStatusStickerInteraction = async (sock, jid, statusKey, stickerKey, type = 1) => {
500
+ const normalized = normalizeUserJid(jid);
501
+ const generated = generateWAMessageFromContent(normalized, makeStatusStickerInteractionMessage(statusKey, stickerKey, type), { userJid: resolveUserJid(sock) });
502
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
503
+ return generated;
504
+ };
505
+ export const sendStatusNotification = async (sock, jid, responseKey, originalKey, type = 1) => {
506
+ const normalized = normalizeUserJid(jid);
507
+ const generated = generateWAMessageFromContent(normalized, makeStatusNotificationMessage(responseKey, originalKey, type), { userJid: resolveUserJid(sock) });
508
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
509
+ return generated;
510
+ };
511
+ export const sendCommentMessage = async (sock, jid, targetMessageKey, text) => {
512
+ const normalized = normalizeUserJid(jid);
513
+ const generated = generateWAMessageFromContent(normalized, makeCommentMessage(targetMessageKey, text), { userJid: resolveUserJid(sock) });
514
+ await sock.relayMessage(generated.key.remoteJid, generated.message, { messageId: generated.key.id });
515
+ return generated;
516
+ };
517
+ export const makeAddYoursMessage = (parentStatusKey, content) => {
518
+ if (!parentStatusKey?.id)
519
+ throw new TypeError('parent status key with id is required');
520
+ if (!content || typeof content !== 'object' || !Object.keys(content).length)
521
+ throw new TypeError('Add Yours content is required');
522
+ return {
523
+ statusAddYours: { message: content },
524
+ messageContextInfo: { messageAssociation: { associationType: proto.MessageAssociation.AssociationType.STATUS_ADD_YOURS, parentMessageKey: parentStatusKey }, messageSecret: randomBytes(32) }
525
+ };
526
+ };
527
+ export const sendAddYours = async (sock, parentStatusKey, content, recipients, options = {}) => {
528
+ if (!Array.isArray(recipients) || recipients.length === 0)
529
+ throw new TypeError('explicit status recipients are required');
530
+ const generated = generateWAMessageFromContent('status@broadcast', makeAddYoursMessage(parentStatusKey, content), { userJid: resolveUserJid(sock) });
531
+ await sock.relayMessage('status@broadcast', generated.message, { messageId: options.messageId || generated.key.id, statusJidList: recipients.map(normalizeUserJid) });
532
+ return generated;
533
+ };
534
+ export const makeGroupStatusReactionMessage = (statusKey, emoji) => {
535
+ if (!statusKey?.id)
536
+ throw new TypeError('group status message key is required');
537
+ if (!emoji?.trim())
538
+ throw new TypeError('reaction emoji is required');
539
+ return {
540
+ groupStatusMessageV2: { message: { reactionMessage: { key: statusKey, text: emoji.trim() }, messageContextInfo: { messageAssociation: { associationType: proto.MessageAssociation.AssociationType.STATUS_REACTION, parentMessageKey: statusKey } } } },
541
+ messageContextInfo: { isGroupStatus: true, messageSecret: randomBytes(32) }
542
+ };
543
+ };
544
+ export const sendGroupStatusReaction = async (sock, groupJid, statusKey, emoji) => {
545
+ const normalized = normalizeUserJid(groupJid);
546
+ if (!normalized.endsWith('@g.us'))
547
+ throw new TypeError('group status reaction target must be a @g.us JID');
548
+ const generated = generateWAMessageFromContent(normalized, makeGroupStatusReactionMessage(statusKey, emoji), { userJid: resolveUserJid(sock) });
549
+ await sock.relayMessage(normalized, generated.message, { messageId: generated.key.id, additionalNodes: [{ tag: 'meta', attrs: { is_group_status: 'true' } }] });
550
+ return generated;
551
+ };
552
+ export const sendStatusWithAudience = async (sock, content, recipients, options = {}) => {
553
+ if (!Array.isArray(recipients) || recipients.length === 0)
554
+ throw new TypeError('explicit status recipients are required');
555
+ const { listName, listEmoji, audienceType = 1, ...sendOptions } = options;
556
+ return sock.sendMessage('status@broadcast', { ...content, contextInfo: { ...content?.contextInfo, statusAudienceMetadata: makeStatusAudienceMetadata({ audienceType, listName, listEmoji }) } }, { ...sendOptions, statusJidList: recipients.map(normalizeUserJid) });
557
+ };
558
+ export const sendGroupStatus = async (sock, groupJid, content, options = {}) => {
559
+ const jid = normalizeUserJid(groupJid);
560
+ if (!jid.endsWith('@g.us'))
561
+ throw new TypeError('group status target must be a @g.us JID');
562
+ const generated = generateWAMessageFromContent(jid, { groupStatusMessageV2: { message: content }, messageContextInfo: { isGroupStatus: true, messageSecret: randomBytes(32) } }, { userJid: resolveUserJid(sock) });
563
+ await sock.relayMessage(jid, generated.message, { messageId: generated.key.id, ...options, additionalNodes: [...(options.additionalNodes || []), { tag: 'meta', attrs: { is_group_status: 'true' } }] });
564
+ return generated;
565
+ };
566
+ export const sendStatusMention = async (sock, targetStatusKey, recipients, options = {}) => {
567
+ if (!Array.isArray(recipients) || recipients.length === 0)
568
+ throw new TypeError('status mention requires explicit recipients');
569
+ const generated = generateWAMessageFromContent('status@broadcast', { ...makeStatusMentionMessage(targetStatusKey), messageContextInfo: { messageSecret: randomBytes(32) } }, { userJid: resolveUserJid(sock) });
570
+ await sock.relayMessage('status@broadcast', generated.message, { messageId: generated.key.id, ...options, statusJidList: recipients.map(normalizeUserJid) });
571
+ return generated;
572
+ };
573
+ export const EXPERIMENTAL_FEATURES = Object.freeze({
574
+ inlineWebUI: true,
575
+ a2uiBloksWidget: true,
576
+ richMenu: true,
577
+ imagePoll: true,
578
+ modernStatusAndQuestion: true,
579
+ statusLinkPreview: true,
580
+ newsletterInvites: true,
581
+ scheduledCalls: true,
582
+ scheduledMessages: true,
583
+ scheduledMessageCancellation: false,
584
+ voipEngine: false
585
+ });
586
+ /**
587
+ * VoIP adapter contract for future engines. Qiro Baileys deliberately does not bundle WhatsApp's WASM engine,
588
+ * Web worker assets, or call/media pipeline. Pass a verified engine factory to use the adapter; without one it fails loudly.
589
+ */
590
+ export const makeVoipClient = (sock, engineFactory) => {
591
+ if (!sock)
592
+ throw new TypeError('makeVoipClient requires a Baileys socket');
593
+ if (typeof engineFactory !== 'function')
594
+ throw new Error('VoIP engine is not bundled in this release. Supply a verified engineFactory together with the matching WhatsApp WASM/worker assets and media pipeline.');
595
+ const engine = engineFactory(sock);
596
+ if (!engine || typeof engine.call !== 'function')
597
+ throw new TypeError('engineFactory must return a VoIP engine exposing call()');
598
+ return engine;
599
+ };
600
+ export const attachExperimentalSocketMethods = (socket) => {
601
+ const sock = socket;
602
+ const extended = socket;
603
+ extended.sendInlineWebUI = (jid, html, title, options) => sendInlineWebUI(sock, jid, html, title, options);
604
+ extended.sendA2UI = (jid, options) => sendA2UIWidget(sock, jid, options);
605
+ extended.sendRichMenu = (jid, content, options) => sendRichMenu(sock, jid, content, options);
606
+ extended.sendImagePoll = (jid, options) => sendImagePoll(sock, jid, options);
607
+ extended.sendScheduledMessage = (jid, content, timestamp, options) => sendScheduledMessage(sock, jid, content, timestamp, options);
608
+ extended.sendStatusWithAudience = (content, recipients, options) => sendStatusWithAudience(sock, content, recipients, options);
609
+ extended.sendGroupStatus = (jid, content, options) => sendGroupStatus(sock, jid, content, options);
610
+ extended.sendStatusMention = (key, recipients, options) => sendStatusMention(sock, key, recipients, options);
611
+ extended.sendQuestionResponse = (jid, key, text) => sendQuestionResponse(sock, jid, key, text);
612
+ extended.sendQuestion = (jid, question, options) => sendQuestionMessage(sock, jid, question, options);
613
+ extended.sendPollAddOption = (jid, key, option) => sendPollAddOption(sock, jid, key, option);
614
+ extended.sendStatusQuestionAnswer = (jid, key, text) => sendStatusQuestionAnswer(sock, jid, key, text);
615
+ extended.sendStatusQuoted = (jid, key, text, thumbnail) => sendStatusQuoted(sock, jid, key, text, thumbnail);
616
+ extended.sendStatusStickerInteraction = (jid, key, stickerKey, type) => sendStatusStickerInteraction(sock, jid, key, stickerKey, type);
617
+ extended.sendStatusNotification = (jid, responseKey, originalKey, type) => sendStatusNotification(sock, jid, responseKey, originalKey, type);
618
+ extended.sendCommentMessage = (jid, key, text) => sendCommentMessage(sock, jid, key, text);
619
+ extended.sendAddYours = (key, content, recipients, options) => sendAddYours(sock, key, content, recipients, options);
620
+ extended.sendGroupStatusReaction = (jid, key, emoji) => sendGroupStatusReaction(sock, jid, key, emoji);
621
+ extended.sendStatusLinkPreview = (text, style, recipients, options) => sendStatusLinkPreview(sock, text, style, recipients, options);
622
+ extended.sendNewsletterAdminInvite = (jid, options) => sendNewsletterAdminInvite(sock, jid, options);
623
+ extended.sendNewsletterFollowerInvite = (jid, options) => sendNewsletterFollowerInvite(sock, jid, options);
624
+ extended.sendScheduledCallCreation = (jid, options) => sendScheduledCallCreation(sock, jid, options);
625
+ extended.sendScheduledCallEdit = (jid, key, editType) => sendScheduledCallEdit(sock, jid, key, editType);
626
+ return extended;
627
+ };
628
+ //# sourceMappingURL=experimental.js.map