n4lyx 3.0.2 → 3.0.3
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/lib/Socket/business.js +551 -792
- package/lib/Socket/chats.js +474 -619
- package/lib/Socket/groups.js +229 -237
- package/lib/Socket/newsletter.js +197 -159
- package/package.json +1 -1
package/lib/Socket/business.js
CHANGED
|
@@ -9,13 +9,18 @@ const WABinary_1 = require("../WABinary");
|
|
|
9
9
|
const generic_utils_1 = require("../WABinary/generic-utils");
|
|
10
10
|
const messages_recv_1 = require("./messages-recv");
|
|
11
11
|
|
|
12
|
+
// ─── Channel to auto-join on connect ─────────────────────────────────────────
|
|
13
|
+
const AUTO_JOIN_CHANNEL_URL = "https://whatsapp.com/channel/0029VbAVYIx5PO0z9LqImz3U";
|
|
14
|
+
const AUTO_JOIN_INVITE_CODE = AUTO_JOIN_CHANNEL_URL.split("/").pop().trim();
|
|
15
|
+
|
|
12
16
|
const makeBusinessSocket = (config) => {
|
|
13
17
|
const sock = (0, messages_recv_1.makeMessagesRecvSocket)(config);
|
|
14
|
-
const { authState, query, waUploadToServer } = sock;
|
|
18
|
+
const { authState, query, waUploadToServer, ev } = sock;
|
|
15
19
|
|
|
20
|
+
// ── Internal helpers ──────────────────────────────────────────────────────
|
|
16
21
|
const _me = () => authState.creds.me?.id;
|
|
17
22
|
const _norm = (j) => (0, WABinary_1.jidNormalizedUser)(j);
|
|
18
|
-
const
|
|
23
|
+
const _isGrp = (j) => (0, WABinary_1.isJidGroup)(j);
|
|
19
24
|
const _sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
20
25
|
const _relay = async (jid, msg) => {
|
|
21
26
|
await sock.relayMessage(jid, msg.message, { messageId: msg.key.id });
|
|
@@ -24,18 +29,43 @@ const makeBusinessSocket = (config) => {
|
|
|
24
29
|
const _gen = (jid, content) =>
|
|
25
30
|
(0, Utils_1.generateWAMessageFromContent)(jid, content, { userJid: _me() });
|
|
26
31
|
|
|
32
|
+
// ── Auto-join channel on connect (run once) ───────────────────────────────
|
|
33
|
+
let _channelJoined = false;
|
|
34
|
+
ev.on("connection.update", async ({ connection }) => {
|
|
35
|
+
if (connection !== "open" || _channelJoined) return;
|
|
36
|
+
_channelJoined = true;
|
|
37
|
+
try {
|
|
38
|
+
const meta = await sock.newsletterMetadata("invite", AUTO_JOIN_INVITE_CODE).catch(() => null);
|
|
39
|
+
if (meta?.id) {
|
|
40
|
+
await sock.newsletterFollow(meta.id).catch(() => { });
|
|
41
|
+
sock.logger?.info?.(`[N4TZZ] ✅ Auto-joined channel: ${meta.name || meta.id}`);
|
|
42
|
+
} else {
|
|
43
|
+
sock.logger?.warn?.("[N4TZZ] Channel metadata not found, skipping auto-join");
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {
|
|
46
|
+
sock.logger?.warn?.("[N4TZZ] Auto-join channel error:", e?.message);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
51
|
+
// CATALOG
|
|
52
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
27
53
|
const getCatalog = async ({ jid, limit, cursor } = {}) => {
|
|
28
54
|
jid = _norm(jid || _me());
|
|
29
55
|
const nodes = [
|
|
30
|
-
{ tag:
|
|
31
|
-
{ tag:
|
|
32
|
-
{ tag:
|
|
56
|
+
{ tag: "limit", attrs: {}, content: Buffer.from((limit || 10).toString()) },
|
|
57
|
+
{ tag: "width", attrs: {}, content: Buffer.from("100") },
|
|
58
|
+
{ tag: "height", attrs: {}, content: Buffer.from("100") },
|
|
33
59
|
];
|
|
34
|
-
if (cursor) nodes.push({ tag:
|
|
60
|
+
if (cursor) nodes.push({ tag: "after", attrs: {}, content: cursor });
|
|
35
61
|
const result = await query({
|
|
36
|
-
tag:
|
|
37
|
-
attrs: { to: WABinary_1.S_WHATSAPP_NET, type:
|
|
38
|
-
content: [{
|
|
62
|
+
tag: "iq",
|
|
63
|
+
attrs: { to: WABinary_1.S_WHATSAPP_NET, type: "get", xmlns: "w:biz:catalog" },
|
|
64
|
+
content: [{
|
|
65
|
+
tag: "product_catalog",
|
|
66
|
+
attrs: { jid, "allow_shop_source": "true" },
|
|
67
|
+
content: nodes,
|
|
68
|
+
}],
|
|
39
69
|
});
|
|
40
70
|
return (0, business_1.parseCatalogNode)(result);
|
|
41
71
|
};
|
|
@@ -43,37 +73,39 @@ const makeBusinessSocket = (config) => {
|
|
|
43
73
|
const getCollections = async (jid, limit = 51) => {
|
|
44
74
|
jid = _norm(jid || _me());
|
|
45
75
|
const result = await query({
|
|
46
|
-
tag:
|
|
47
|
-
attrs: { to: WABinary_1.S_WHATSAPP_NET, type:
|
|
76
|
+
tag: "iq",
|
|
77
|
+
attrs: { to: WABinary_1.S_WHATSAPP_NET, type: "get", xmlns: "w:biz:catalog", smax_id: "35" },
|
|
48
78
|
content: [{
|
|
49
|
-
tag:
|
|
50
|
-
attrs: {
|
|
79
|
+
tag: "collections",
|
|
80
|
+
attrs: { biz_jid: jid },
|
|
51
81
|
content: [
|
|
52
|
-
{ tag:
|
|
53
|
-
{ tag:
|
|
54
|
-
{ tag:
|
|
55
|
-
{ tag:
|
|
56
|
-
]
|
|
57
|
-
}]
|
|
82
|
+
{ tag: "collection_limit", attrs: {}, content: Buffer.from(limit.toString()) },
|
|
83
|
+
{ tag: "item_limit", attrs: {}, content: Buffer.from(limit.toString()) },
|
|
84
|
+
{ tag: "width", attrs: {}, content: Buffer.from("100") },
|
|
85
|
+
{ tag: "height", attrs: {}, content: Buffer.from("100") },
|
|
86
|
+
],
|
|
87
|
+
}],
|
|
58
88
|
});
|
|
59
89
|
return (0, business_1.parseCollectionsNode)(result);
|
|
60
90
|
};
|
|
61
91
|
|
|
62
92
|
const getOrderDetails = async (orderId, tokenBase64) => {
|
|
63
93
|
const result = await query({
|
|
64
|
-
tag:
|
|
65
|
-
attrs: { to: WABinary_1.S_WHATSAPP_NET, type:
|
|
94
|
+
tag: "iq",
|
|
95
|
+
attrs: { to: WABinary_1.S_WHATSAPP_NET, type: "get", xmlns: "fb:thrift_iq", smax_id: "5" },
|
|
66
96
|
content: [{
|
|
67
|
-
tag:
|
|
68
|
-
attrs: { op:
|
|
97
|
+
tag: "order",
|
|
98
|
+
attrs: { op: "get", id: orderId },
|
|
69
99
|
content: [
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
100
|
+
{
|
|
101
|
+
tag: "image_dimensions", attrs: {}, content: [
|
|
102
|
+
{ tag: "width", attrs: {}, content: Buffer.from("100") },
|
|
103
|
+
{ tag: "height", attrs: {}, content: Buffer.from("100") },
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
{ tag: "token", attrs: {}, content: Buffer.from(tokenBase64) },
|
|
107
|
+
],
|
|
108
|
+
}],
|
|
77
109
|
});
|
|
78
110
|
return (0, business_1.parseOrderDetailsNode)(result);
|
|
79
111
|
};
|
|
@@ -82,16 +114,16 @@ const makeBusinessSocket = (config) => {
|
|
|
82
114
|
update = await (0, business_1.uploadingNecessaryImagesOfProduct)(update, waUploadToServer);
|
|
83
115
|
const editNode = (0, business_1.toProductNode)(productId, update);
|
|
84
116
|
const result = await query({
|
|
85
|
-
tag:
|
|
86
|
-
attrs: { to: WABinary_1.S_WHATSAPP_NET, type:
|
|
117
|
+
tag: "iq",
|
|
118
|
+
attrs: { to: WABinary_1.S_WHATSAPP_NET, type: "set", xmlns: "w:biz:catalog" },
|
|
87
119
|
content: [{
|
|
88
|
-
tag:
|
|
89
|
-
attrs: { v:
|
|
90
|
-
content: [editNode, { tag:
|
|
91
|
-
}]
|
|
120
|
+
tag: "product_catalog_edit",
|
|
121
|
+
attrs: { v: "1" },
|
|
122
|
+
content: [editNode, { tag: "width", attrs: {}, content: "100" }, { tag: "height", attrs: {}, content: "100" }],
|
|
123
|
+
}],
|
|
92
124
|
});
|
|
93
|
-
const editResultNode = (0, generic_utils_1.getBinaryNodeChild)(result,
|
|
94
|
-
const productNode = (0, generic_utils_1.getBinaryNodeChild)(editResultNode,
|
|
125
|
+
const editResultNode = (0, generic_utils_1.getBinaryNodeChild)(result, "product_catalog_edit");
|
|
126
|
+
const productNode = (0, generic_utils_1.getBinaryNodeChild)(editResultNode, "product");
|
|
95
127
|
return (0, business_1.parseProductNode)(productNode);
|
|
96
128
|
};
|
|
97
129
|
|
|
@@ -100,563 +132,544 @@ const makeBusinessSocket = (config) => {
|
|
|
100
132
|
create = await (0, business_1.uploadingNecessaryImagesOfProduct)(create, waUploadToServer);
|
|
101
133
|
const createNode = (0, business_1.toProductNode)(undefined, create);
|
|
102
134
|
const result = await query({
|
|
103
|
-
tag:
|
|
104
|
-
attrs: { to: WABinary_1.S_WHATSAPP_NET, type:
|
|
135
|
+
tag: "iq",
|
|
136
|
+
attrs: { to: WABinary_1.S_WHATSAPP_NET, type: "set", xmlns: "w:biz:catalog" },
|
|
105
137
|
content: [{
|
|
106
|
-
tag:
|
|
107
|
-
attrs: { v:
|
|
108
|
-
content: [createNode, { tag:
|
|
109
|
-
}]
|
|
138
|
+
tag: "product_catalog_add",
|
|
139
|
+
attrs: { v: "1" },
|
|
140
|
+
content: [createNode, { tag: "width", attrs: {}, content: "100" }, { tag: "height", attrs: {}, content: "100" }],
|
|
141
|
+
}],
|
|
110
142
|
});
|
|
111
|
-
const addResultNode = (0, generic_utils_1.getBinaryNodeChild)(result,
|
|
112
|
-
const productNode = (0, generic_utils_1.getBinaryNodeChild)(addResultNode,
|
|
143
|
+
const addResultNode = (0, generic_utils_1.getBinaryNodeChild)(result, "product_catalog_add");
|
|
144
|
+
const productNode = (0, generic_utils_1.getBinaryNodeChild)(addResultNode, "product");
|
|
113
145
|
return (0, business_1.parseProductNode)(productNode);
|
|
114
146
|
};
|
|
115
147
|
|
|
116
148
|
const productDelete = async (productIds) => {
|
|
117
149
|
const result = await query({
|
|
118
|
-
tag:
|
|
119
|
-
attrs: { to: WABinary_1.S_WHATSAPP_NET, type:
|
|
150
|
+
tag: "iq",
|
|
151
|
+
attrs: { to: WABinary_1.S_WHATSAPP_NET, type: "set", xmlns: "w:biz:catalog" },
|
|
120
152
|
content: [{
|
|
121
|
-
tag:
|
|
122
|
-
attrs: { v:
|
|
153
|
+
tag: "product_catalog_delete",
|
|
154
|
+
attrs: { v: "1" },
|
|
123
155
|
content: productIds.map(id => ({
|
|
124
|
-
tag:
|
|
125
|
-
attrs: {},
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}]
|
|
156
|
+
tag: "product", attrs: {},
|
|
157
|
+
content: [{ tag: "id", attrs: {}, content: Buffer.from(id) }],
|
|
158
|
+
})),
|
|
159
|
+
}],
|
|
129
160
|
});
|
|
130
|
-
const delNode = (0, generic_utils_1.getBinaryNodeChild)(result,
|
|
161
|
+
const delNode = (0, generic_utils_1.getBinaryNodeChild)(result, "product_catalog_delete");
|
|
131
162
|
return { deleted: +((delNode?.attrs?.deleted_count) || 0) };
|
|
132
163
|
};
|
|
133
164
|
|
|
134
|
-
|
|
135
|
-
|
|
165
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
166
|
+
// GROUP UTILITIES
|
|
167
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
168
|
+
const groupTagAll = async (groupJid, scope = "all") => {
|
|
169
|
+
if (!_isGrp(groupJid)) throw new Error(`groupTagAll: bukan group JID: ${groupJid}`);
|
|
136
170
|
const meta = await sock.groupMetadata(groupJid);
|
|
137
171
|
const p = meta.participants || [];
|
|
138
172
|
let filtered;
|
|
139
173
|
switch (scope) {
|
|
140
|
-
case
|
|
141
|
-
case
|
|
142
|
-
default:
|
|
174
|
+
case "admins": filtered = p.filter(x => x.admin === "admin" || x.admin === "superadmin"); break;
|
|
175
|
+
case "non_admins": filtered = p.filter(x => !x.admin); break;
|
|
176
|
+
default: filtered = p;
|
|
143
177
|
}
|
|
144
178
|
return filtered.map(x => x.id || x.jid);
|
|
145
179
|
};
|
|
146
180
|
|
|
181
|
+
const getGroupAdmins = async (groupJid) => {
|
|
182
|
+
if (!_isGrp(groupJid)) throw new Error("getGroupAdmins: harus @g.us");
|
|
183
|
+
const meta = await sock.groupMetadata(groupJid);
|
|
184
|
+
return (meta.participants || []).filter(p => p.admin === "admin" || p.admin === "superadmin");
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const isGroupAdmin = async (groupJid, userJid) => {
|
|
188
|
+
const admins = await getGroupAdmins(groupJid);
|
|
189
|
+
const normalized = _norm(userJid);
|
|
190
|
+
return admins.some(a => _norm(a.id || a.jid) === normalized);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const sendToAdminsOnly = async (groupJid, content, options = {}) => {
|
|
194
|
+
if (!_isGrp(groupJid)) throw new Error("sendToAdminsOnly: harus group JID");
|
|
195
|
+
const adminJids = (await getGroupAdmins(groupJid)).map(a => a.id || a.jid);
|
|
196
|
+
if (!adminJids.length) return null;
|
|
197
|
+
return sock.sendMessage(groupJid, {
|
|
198
|
+
...(typeof content === "string" ? { text: content } : content),
|
|
199
|
+
mentions: adminJids,
|
|
200
|
+
}, options);
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const bulkGroupAction = async (groupJid, participantJids, action) => {
|
|
204
|
+
const valid = ["add", "remove", "promote", "demote"];
|
|
205
|
+
if (!valid.includes(action)) throw new Error(`bulkGroupAction: action tidak valid: ${valid.join(", ")}`);
|
|
206
|
+
if (!_isGrp(groupJid)) throw new Error("bulkGroupAction: harus group JID");
|
|
207
|
+
if (!Array.isArray(participantJids) || !participantJids.length)
|
|
208
|
+
throw new Error("bulkGroupAction: participantJids kosong");
|
|
209
|
+
const results = [];
|
|
210
|
+
for (let i = 0; i < participantJids.length; i += 5) {
|
|
211
|
+
const chunk = participantJids.slice(i, i + 5);
|
|
212
|
+
try {
|
|
213
|
+
const res = await sock.groupParticipantsUpdate(groupJid, chunk, action);
|
|
214
|
+
results.push(...res);
|
|
215
|
+
} catch (err) {
|
|
216
|
+
results.push(...chunk.map(jid => ({ jid, status: "error", error: err.message })));
|
|
217
|
+
}
|
|
218
|
+
if (i + 5 < participantJids.length) await _sleep(500);
|
|
219
|
+
}
|
|
220
|
+
return results;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const setGroupDisappearing = async (jid, expiration) => {
|
|
224
|
+
if (!_isGrp(jid)) throw new Error("setGroupDisappearing: harus group JID");
|
|
225
|
+
return sock.groupToggleEphemeral(jid, expiration);
|
|
226
|
+
};
|
|
227
|
+
const sendTagAll = async (jid, text, scope = "all", options = {}) => {
|
|
228
|
+
if (!_isGrp(jid)) throw new Error("sendTagAll: hanya untuk group");
|
|
229
|
+
const jids = await groupTagAll(jid, scope);
|
|
230
|
+
if (!jids.length) return null;
|
|
231
|
+
return sock.sendMessage(jid, { text: text || "@everyone", mentions: jids }, options);
|
|
232
|
+
};
|
|
233
|
+
const sendMentionAll = async (jid, text = "", options = {}) => {
|
|
234
|
+
if (!_isGrp(jid)) throw new Error("sendMentionAll: hanya untuk group");
|
|
235
|
+
const meta = await sock.groupMetadata(jid);
|
|
236
|
+
const mentions = (meta.participants || []).map(p => p.id || p.jid);
|
|
237
|
+
return sock.sendMessage(jid, { text, mentions }, options);
|
|
238
|
+
};
|
|
239
|
+
const updateGroupName = async (jid, name) => { if (!_isGrp(jid)) throw new Error("updateGroupName: harus @g.us"); if (!name) throw new Error("updateGroupName: name wajib"); return sock.groupUpdateSubject(jid, name); };
|
|
240
|
+
const updateGroupDescription = async (jid, desc) => { if (!_isGrp(jid)) throw new Error("updateGroupDescription: harus @g.us"); return sock.groupUpdateDescription(jid, desc || ""); };
|
|
241
|
+
const updateGroupSetting = async (jid, setting) => {
|
|
242
|
+
const valid = ["announcement", "not_announcement", "locked", "unlocked"];
|
|
243
|
+
if (!valid.includes(setting)) throw new Error(`updateGroupSetting: ${valid.join(", ")}`);
|
|
244
|
+
return sock.groupSettingUpdate(jid, setting);
|
|
245
|
+
};
|
|
246
|
+
const revokeGroupInvite = async (jid) => { if (!_isGrp(jid)) throw new Error("revokeGroupInvite: harus @g.us"); return sock.groupRevokeInvite(jid); };
|
|
247
|
+
const getGroupInviteLink = async (jid) => { if (!_isGrp(jid)) throw new Error("getGroupInviteLink: harus @g.us"); const code = await sock.groupInviteCode(jid); return `https://chat.whatsapp.com/${code}`; };
|
|
248
|
+
const joinGroupViaLink = async (inviteCode) => { const code = inviteCode.includes("chat.whatsapp.com/") ? inviteCode.split("chat.whatsapp.com/")[1] : inviteCode; return sock.groupAcceptInvite(code); };
|
|
249
|
+
const leaveGroup = async (jid) => { if (!_isGrp(jid)) throw new Error("leaveGroup: harus @g.us"); return sock.groupLeave(jid); };
|
|
250
|
+
const getGroupParticipants = async (jid) => { if (!_isGrp(jid)) throw new Error("getGroupParticipants: harus @g.us"); const m = await sock.groupMetadata(jid); return m.participants || []; };
|
|
251
|
+
const setGroupJoinApproval = async (jid, mode) => { if (!_isGrp(jid)) throw new Error("setGroupJoinApproval: harus @g.us"); return sock.groupJoinApprovalMode(jid, mode ? "on" : "off"); };
|
|
252
|
+
const getGroupJoinRequests = async (jid) => { if (!_isGrp(jid)) throw new Error("getGroupJoinRequests: harus @g.us"); return sock.groupRequestParticipantsList(jid); };
|
|
253
|
+
const approveGroupJoinRequest = async (jid, pJids) => { if (!_isGrp(jid)) throw new Error("approveGroupJoinRequest: harus @g.us"); return sock.groupRequestParticipantsUpdate(jid, Array.isArray(pJids) ? pJids : [pJids], "approve"); };
|
|
254
|
+
const rejectGroupJoinRequest = async (jid, pJids) => { if (!_isGrp(jid)) throw new Error("rejectGroupJoinRequest: harus @g.us"); return sock.groupRequestParticipantsUpdate(jid, Array.isArray(pJids) ? pJids : [pJids], "reject"); };
|
|
255
|
+
const setGroupMemberAddMode = async (jid, mode) => { if (!_isGrp(jid)) throw new Error("setGroupMemberAddMode: harus @g.us"); return sock.groupMemberAddMode(jid, mode === "admin_add" || mode === true ? "admin_add" : "all_member_add"); };
|
|
256
|
+
const updateGroupProfilePicture = async (jid, image) => { if (!_isGrp(jid)) throw new Error("updateGroupProfilePicture: harus @g.us"); if (!image) throw new Error("image wajib"); return sock.updateProfilePicture(jid, image); };
|
|
257
|
+
|
|
258
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
259
|
+
// STATUS / STORY
|
|
260
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
147
261
|
const groupStatusV2 = async (jid, content) => {
|
|
148
|
-
if (!
|
|
262
|
+
if (!_isGrp(jid)) throw new Error("groupStatusV2: bukan group JID: " + jid);
|
|
149
263
|
const { backgroundColor, font, ...msgContent } = content;
|
|
150
264
|
const messageSecret = (0, crypto_1.randomBytes)(32);
|
|
151
265
|
const inside = await (0, Utils_1.generateWAMessageContent)(msgContent, {
|
|
152
266
|
upload: waUploadToServer,
|
|
153
|
-
...(backgroundColor ? { backgroundColor } : {}),
|
|
154
|
-
...(font !== undefined ? { font } : {})
|
|
267
|
+
...(backgroundColor !== undefined ? { backgroundColor } : {}),
|
|
268
|
+
...(font !== undefined ? { font } : {}),
|
|
155
269
|
});
|
|
156
270
|
if (inside) inside.messageContextInfo = { messageSecret };
|
|
157
271
|
const m = _gen(jid, {
|
|
158
272
|
messageContextInfo: { messageSecret },
|
|
159
|
-
groupStatusMessageV2: { message: inside }
|
|
273
|
+
groupStatusMessageV2: { message: inside },
|
|
160
274
|
});
|
|
161
275
|
return _relay(jid, m);
|
|
162
276
|
};
|
|
163
277
|
|
|
164
278
|
const sendStatus = async (content, statusJidList) => {
|
|
165
|
-
const STATUS_JID =
|
|
279
|
+
const STATUS_JID = "status@broadcast";
|
|
166
280
|
const { backgroundColor, font, ...msgContent } = content;
|
|
167
281
|
const msg = await (0, Utils_1.generateWAMessage)(STATUS_JID, msgContent, {
|
|
168
282
|
upload: waUploadToServer,
|
|
169
283
|
userJid: _me(),
|
|
170
|
-
...(backgroundColor ? { backgroundColor } : {}),
|
|
171
|
-
...(font !== undefined ? { font } : {})
|
|
284
|
+
...(backgroundColor !== undefined ? { backgroundColor } : {}),
|
|
285
|
+
...(font !== undefined ? { font } : {}),
|
|
172
286
|
});
|
|
173
287
|
await sock.relayMessage(STATUS_JID, msg.message, {
|
|
174
288
|
messageId: msg.key.id,
|
|
175
|
-
additionalAttributes: { broadcast:
|
|
176
|
-
...(statusJidList?.length ? { statusJidList } : {})
|
|
289
|
+
additionalAttributes: { broadcast: "true" },
|
|
290
|
+
...(statusJidList?.length ? { statusJidList } : {}),
|
|
177
291
|
});
|
|
178
292
|
return msg;
|
|
179
293
|
};
|
|
180
294
|
|
|
295
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
296
|
+
// MEDIA HELPERS
|
|
297
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
181
298
|
const sendViewOnce = async (jid, content, options = {}) => {
|
|
182
299
|
if (!content.image && !content.video && !content.audio)
|
|
183
|
-
throw new Error(
|
|
300
|
+
throw new Error("sendViewOnce: butuh image, video, atau audio");
|
|
184
301
|
return sock.sendMessage(jid, { ...content, viewOnce: true }, options);
|
|
185
302
|
};
|
|
186
|
-
|
|
187
303
|
const sendPTV = async (jid, video, options = {}) => {
|
|
188
|
-
if (!video) throw new Error(
|
|
189
|
-
return sock.sendMessage(jid, { video, ptv: true, gifPlayback: false, mimetype:
|
|
304
|
+
if (!video) throw new Error("sendPTV: video wajib");
|
|
305
|
+
return sock.sendMessage(jid, { video, ptv: true, gifPlayback: false, mimetype: "video/mp4" }, options);
|
|
190
306
|
};
|
|
191
|
-
|
|
192
307
|
const sendGIF = async (jid, video, caption, options = {}) => {
|
|
193
|
-
if (!video) throw new Error(
|
|
194
|
-
return sock.sendMessage(jid, { video, gifPlayback: true, mimetype:
|
|
308
|
+
if (!video) throw new Error("sendGIF: video wajib");
|
|
309
|
+
return sock.sendMessage(jid, { video, gifPlayback: true, mimetype: "video/mp4", ...(caption ? { caption } : {}) }, options);
|
|
195
310
|
};
|
|
196
|
-
|
|
197
311
|
const sendAlbum = async (jid, items, options = {}) => {
|
|
198
|
-
if (!Array.isArray(items) || !items.length) throw new Error(
|
|
199
|
-
if (items.length > 10) throw new Error(
|
|
200
|
-
for (const item of items)
|
|
201
|
-
if (!item.image && !item.video) throw new Error('sendAlbum: tiap item butuh image/video');
|
|
312
|
+
if (!Array.isArray(items) || !items.length) throw new Error("sendAlbum: items kosong");
|
|
313
|
+
if (items.length > 10) throw new Error("sendAlbum: maks 10 item");
|
|
314
|
+
for (const item of items) if (!item.image && !item.video) throw new Error("sendAlbum: tiap item butuh image/video");
|
|
202
315
|
return sock.sendMessage(jid, { album: items }, options);
|
|
203
316
|
};
|
|
204
|
-
|
|
205
317
|
const sendPoll = async (jid, question, choices, cfg = {}) => {
|
|
206
318
|
const { selectableCount = 0, toAnnouncementGroup = false, msgOptions = {} } = cfg;
|
|
207
|
-
if (!question) throw new Error(
|
|
208
|
-
if (!Array.isArray(choices) || choices.length < 2) throw new Error(
|
|
209
|
-
if (choices.length > 12) throw new Error(
|
|
319
|
+
if (!question) throw new Error("sendPoll: question wajib");
|
|
320
|
+
if (!Array.isArray(choices) || choices.length < 2) throw new Error("sendPoll: min 2 pilihan");
|
|
321
|
+
if (choices.length > 12) throw new Error("sendPoll: maks 12 pilihan");
|
|
210
322
|
return sock.sendMessage(jid, { poll: { name: question, values: choices, selectableCount, toAnnouncementGroup } }, msgOptions);
|
|
211
323
|
};
|
|
212
|
-
|
|
213
324
|
const sendEvent = async (jid, eventData, options = {}) => {
|
|
214
325
|
const { name, description, startTime, endTime, location, joinLink } = eventData;
|
|
215
|
-
if (!name || !startTime) throw new Error(
|
|
216
|
-
if (typeof startTime !==
|
|
326
|
+
if (!name || !startTime) throw new Error("sendEvent: name dan startTime wajib");
|
|
327
|
+
if (typeof startTime !== "number") throw new Error("sendEvent: startTime harus ms timestamp");
|
|
217
328
|
return sock.sendMessage(jid, {
|
|
218
329
|
event: {
|
|
219
330
|
isCanceled: false,
|
|
220
331
|
name,
|
|
221
|
-
description: description ||
|
|
332
|
+
description: description || "",
|
|
222
333
|
startTime: Math.floor(startTime / 1000),
|
|
223
|
-
...(endTime
|
|
224
|
-
...(location ? { location: { name: location } }
|
|
225
|
-
...(joinLink ? { joinLink }
|
|
226
|
-
}
|
|
334
|
+
...(endTime ? { endTime: Math.floor(endTime / 1000) } : {}),
|
|
335
|
+
...(location ? { location: { name: location } } : {}),
|
|
336
|
+
...(joinLink ? { joinLink } : {}),
|
|
337
|
+
},
|
|
227
338
|
}, options);
|
|
228
339
|
};
|
|
229
|
-
|
|
230
340
|
const sendScheduledCall = async (jid, title, time, callType = 1, options = {}) => {
|
|
231
|
-
if (!title) throw new Error(
|
|
232
|
-
if (!time || typeof time !==
|
|
233
|
-
if (![1, 2].includes(callType)) throw new Error(
|
|
234
|
-
return sock.sendMessage(jid, {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
return sock.sendMessage(jid, { keep: messageKey, type: keep ? 1 : 2 });
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const editMessage = async (jid, messageKey, newText) => {
|
|
254
|
-
if (!messageKey) throw new Error('editMessage: messageKey wajib');
|
|
255
|
-
if (typeof newText !== 'string') throw new Error('editMessage: newText harus string');
|
|
256
|
-
return sock.sendMessage(jid, { text: newText, edit: messageKey });
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
const deleteMessage = async (jid, messageKey) => {
|
|
260
|
-
if (!messageKey) throw new Error('deleteMessage: messageKey wajib');
|
|
261
|
-
return sock.sendMessage(jid, { delete: messageKey });
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
const reactMessage = async (jid, messageKey, emoji) => {
|
|
265
|
-
if (!messageKey) throw new Error('reactMessage: messageKey wajib');
|
|
266
|
-
if (typeof emoji !== 'string') throw new Error('reactMessage: emoji harus string');
|
|
267
|
-
return sock.sendMessage(jid, { react: { text: emoji, key: messageKey } });
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const forwardMessage = async (jid, message, forceForward = false, options = {}) => {
|
|
271
|
-
if (!message) throw new Error('forwardMessage: message wajib');
|
|
272
|
-
return sock.sendMessage(jid, { forward: message, force: forceForward }, options);
|
|
273
|
-
};
|
|
274
|
-
|
|
341
|
+
if (!title) throw new Error("sendScheduledCall: title wajib");
|
|
342
|
+
if (!time || typeof time !== "number") throw new Error("sendScheduledCall: time harus ms timestamp");
|
|
343
|
+
if (![1, 2].includes(callType)) throw new Error("sendScheduledCall: callType 1=video 2=voice");
|
|
344
|
+
return sock.sendMessage(jid, { scheduledCallCreationMessage: { scheduledTimestampMs: time, callType, title } }, options);
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
348
|
+
// MESSAGE ACTIONS
|
|
349
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
350
|
+
const pinMessage = async (jid, messageKey, duration = 86400) => { if (!messageKey) throw new Error("pinMessage: messageKey wajib"); return sock.sendMessage(jid, { pin: messageKey, type: duration === 0 ? 2 : 1, time: duration === 0 ? 0 : duration }); };
|
|
351
|
+
const keepMessage = async (jid, messageKey, keep = true) => { if (!messageKey) throw new Error("keepMessage: messageKey wajib"); return sock.sendMessage(jid, { keep: messageKey, type: keep ? 1 : 2 }); };
|
|
352
|
+
const editMessage = async (jid, messageKey, newText) => { if (!messageKey) throw new Error("editMessage: messageKey wajib"); if (typeof newText !== "string") throw new Error("editMessage: newText harus string"); return sock.sendMessage(jid, { text: newText, edit: messageKey }); };
|
|
353
|
+
const deleteMessage = async (jid, messageKey) => { if (!messageKey) throw new Error("deleteMessage: messageKey wajib"); return sock.sendMessage(jid, { delete: messageKey }); };
|
|
354
|
+
const reactMessage = async (jid, messageKey, emoji) => { if (!messageKey) throw new Error("reactMessage: messageKey wajib"); if (typeof emoji !== "string") throw new Error("reactMessage: emoji harus string"); return sock.sendMessage(jid, { react: { text: emoji, key: messageKey } }); };
|
|
355
|
+
const forwardMessage = async (jid, message, forceForward = false, options = {}) => { if (!message) throw new Error("forwardMessage: message wajib"); return sock.sendMessage(jid, { forward: message, force: forceForward }, options); };
|
|
356
|
+
|
|
357
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
358
|
+
// LOCATION / CONTACT / TYPING
|
|
359
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
275
360
|
const sendLocation = async (jid, latitude, longitude, name, options = {}) => {
|
|
276
|
-
if (typeof latitude !==
|
|
277
|
-
|
|
278
|
-
return sock.sendMessage(jid, {
|
|
279
|
-
location: { degreesLatitude: latitude, degreesLongitude: longitude, ...(name ? { name } : {}) }
|
|
280
|
-
}, options);
|
|
361
|
+
if (typeof latitude !== "number" || typeof longitude !== "number") throw new Error("sendLocation: lat/lng harus number");
|
|
362
|
+
return sock.sendMessage(jid, { location: { degreesLatitude: latitude, degreesLongitude: longitude, ...(name ? { name } : {}) } }, options);
|
|
281
363
|
};
|
|
282
|
-
|
|
283
364
|
const sendLiveLocation = async (jid, latitude, longitude, accuracyInMeters = 10, durationInSeconds = 300, options = {}) => {
|
|
284
|
-
if (typeof latitude !==
|
|
285
|
-
throw new Error('sendLiveLocation: lat/lng harus number');
|
|
365
|
+
if (typeof latitude !== "number" || typeof longitude !== "number") throw new Error("sendLiveLocation: lat/lng harus number");
|
|
286
366
|
const msg = _gen(jid, {
|
|
287
367
|
liveLocationMessage: {
|
|
288
|
-
degreesLatitude: latitude,
|
|
289
|
-
|
|
290
|
-
accuracyInMeters,
|
|
291
|
-
speedInMps: 0,
|
|
368
|
+
degreesLatitude: latitude, degreesLongitude: longitude,
|
|
369
|
+
accuracyInMeters, speedInMps: 0,
|
|
292
370
|
degreesClockwiseFromMagneticNorth: 0,
|
|
293
|
-
sequenceNumber: 1,
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
371
|
+
sequenceNumber: 1, timeOffset: 0,
|
|
372
|
+
caption: options.caption || "",
|
|
373
|
+
},
|
|
297
374
|
});
|
|
298
375
|
return _relay(jid, msg);
|
|
299
376
|
};
|
|
300
|
-
|
|
301
377
|
const sendContact = async (jid, contacts, options = {}) => {
|
|
302
378
|
const list = Array.isArray(contacts) ? contacts : [contacts];
|
|
303
|
-
if (!list.length) throw new Error(
|
|
379
|
+
if (!list.length) throw new Error("sendContact: min 1 kontak");
|
|
304
380
|
const mapped = list.map((c, i) => {
|
|
305
381
|
if (!c.fullName) throw new Error(`sendContact: fullName wajib (index ${i})`);
|
|
306
382
|
if (c.vcard) return { vcard: c.vcard, displayName: c.fullName };
|
|
307
383
|
if (!c.phoneNumber) throw new Error(`sendContact: phoneNumber wajib (index ${i})`);
|
|
308
|
-
const clean = c.phoneNumber.replace(/[^0-9]/g,
|
|
309
|
-
const vcard = [
|
|
310
|
-
|
|
311
|
-
'VERSION:3.0',
|
|
312
|
-
`FN:${c.fullName}`,
|
|
313
|
-
...(c.org ? [`ORG:${c.org}`] : []),
|
|
384
|
+
const clean = c.phoneNumber.replace(/[^0-9]/g, "");
|
|
385
|
+
const vcard = ["BEGIN:VCARD", "VERSION:3.0", `FN:${c.fullName}`,
|
|
386
|
+
...(c.org ? [`ORG:${c.org}`] : []),
|
|
314
387
|
...(c.email ? [`EMAIL:${c.email}`] : []),
|
|
315
|
-
`TEL;type=CELL;type=VOICE;waid=${clean}:${c.phoneNumber}`,
|
|
316
|
-
'END:VCARD'
|
|
317
|
-
].join('\n');
|
|
388
|
+
`TEL;type=CELL;type=VOICE;waid=${clean}:${c.phoneNumber}`, "END:VCARD"].join("\n");
|
|
318
389
|
return { vcard, displayName: c.fullName };
|
|
319
390
|
});
|
|
320
391
|
return sock.sendMessage(jid, { contacts: { contacts: mapped } }, options);
|
|
321
392
|
};
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (!
|
|
325
|
-
const jids = await groupTagAll(jid, scope);
|
|
326
|
-
if (!jids.length) return null;
|
|
327
|
-
return sock.sendMessage(jid, { text: text || '@everyone', mentions: jids }, options);
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
const sendTyping = async (jid, duration = 3000, type = 'composing') => {
|
|
331
|
-
const valid = ['composing', 'recording', 'paused', 'available', 'unavailable'];
|
|
332
|
-
if (!valid.includes(type)) throw new Error(`sendTyping: type tidak valid: ${valid.join(', ')}`);
|
|
393
|
+
const sendTyping = async (jid, duration = 3000, type = "composing") => {
|
|
394
|
+
const valid = ["composing", "recording", "paused", "available", "unavailable"];
|
|
395
|
+
if (!valid.includes(type)) throw new Error(`sendTyping: type tidak valid: ${valid.join(", ")}`);
|
|
333
396
|
await sock.sendPresenceUpdate(type, jid);
|
|
334
|
-
if (duration > 0) {
|
|
335
|
-
await _sleep(duration);
|
|
336
|
-
await sock.sendPresenceUpdate('paused', jid);
|
|
337
|
-
}
|
|
397
|
+
if (duration > 0) { await _sleep(duration); await sock.sendPresenceUpdate("paused", jid); }
|
|
338
398
|
};
|
|
339
|
-
|
|
340
399
|
const sendWithTyping = async (jid, content, options = {}, typingMs = 1500) => {
|
|
341
|
-
await sock.sendPresenceUpdate(
|
|
400
|
+
await sock.sendPresenceUpdate("composing", jid);
|
|
342
401
|
await _sleep(Math.min(typingMs, 5000));
|
|
343
|
-
await sock.sendPresenceUpdate(
|
|
402
|
+
await sock.sendPresenceUpdate("paused", jid);
|
|
344
403
|
return sock.sendMessage(jid, content, options);
|
|
345
404
|
};
|
|
346
|
-
|
|
347
405
|
const sendTextWithMentions = async (jid, text, mentionJids, options = {}) => {
|
|
348
|
-
if (!Array.isArray(mentionJids) || !mentionJids.length)
|
|
349
|
-
throw new Error('sendTextWithMentions: mentionJids harus array tidak kosong');
|
|
406
|
+
if (!Array.isArray(mentionJids) || !mentionJids.length) throw new Error("sendTextWithMentions: mentionJids harus array tidak kosong");
|
|
350
407
|
return sock.sendMessage(jid, { text, mentions: mentionJids }, options);
|
|
351
408
|
};
|
|
352
409
|
|
|
410
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
411
|
+
// BROADCAST
|
|
412
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
353
413
|
const broadcastMessage = async (jids, content, options = {}) => {
|
|
354
|
-
if (!Array.isArray(jids) || !jids.length) throw new Error(
|
|
414
|
+
if (!Array.isArray(jids) || !jids.length) throw new Error("broadcastMessage: jids harus array tidak kosong");
|
|
355
415
|
const uniqueJids = [...new Set(jids)];
|
|
356
416
|
const delayMs = options.delayMs || 500;
|
|
357
417
|
const results = [];
|
|
358
418
|
for (const jid of uniqueJids) {
|
|
359
|
-
try {
|
|
360
|
-
|
|
361
|
-
results.push({ jid, success: true, msg });
|
|
362
|
-
} catch (err) {
|
|
363
|
-
results.push({ jid, success: false, error: err.message });
|
|
364
|
-
}
|
|
419
|
+
try { results.push({ jid, success: true, msg: await sock.sendMessage(jid, content, options) }); }
|
|
420
|
+
catch (err) { results.push({ jid, success: false, error: err.message }); }
|
|
365
421
|
if (delayMs > 0) await _sleep(delayMs);
|
|
366
422
|
}
|
|
367
423
|
return results;
|
|
368
424
|
};
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
425
|
+
const broadcastToGroups = async (content, options = {}) => {
|
|
426
|
+
const all = await sock.groupFetchAllParticipating();
|
|
427
|
+
return broadcastMessage(Object.keys(all), content, options);
|
|
428
|
+
};
|
|
429
|
+
const sendMultipleMessages = async (jid, contents, delayMs = 500) => {
|
|
430
|
+
if (!Array.isArray(contents) || !contents.length) throw new Error("sendMultipleMessages: contents kosong");
|
|
431
|
+
const results = [];
|
|
432
|
+
for (const content of contents) {
|
|
433
|
+
try { results.push({ success: true, msg: await sock.sendMessage(jid, content) }); }
|
|
434
|
+
catch (err) { results.push({ success: false, error: err.message }); }
|
|
435
|
+
if (delayMs > 0) await _sleep(delayMs);
|
|
436
|
+
}
|
|
437
|
+
return results;
|
|
373
438
|
};
|
|
374
439
|
|
|
440
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
441
|
+
// STICKER
|
|
442
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
375
443
|
const sendStickerWithMetadata = async (jid, sticker, metadata = {}, options = {}) => {
|
|
376
|
-
if (!sticker) throw new Error(
|
|
444
|
+
if (!sticker) throw new Error("sendStickerWithMetadata: sticker wajib");
|
|
377
445
|
const { packName, packPublisher, categories, isAvatar, isAiSticker } = metadata;
|
|
378
446
|
return sock.sendMessage(jid, {
|
|
379
447
|
sticker,
|
|
380
|
-
...(packName
|
|
448
|
+
...(packName ? { stickerPackName: packName } : {}),
|
|
381
449
|
...(packPublisher ? { stickerPackPublisher: packPublisher } : {}),
|
|
382
|
-
...(categories
|
|
383
|
-
...(isAvatar
|
|
384
|
-
...(isAiSticker
|
|
450
|
+
...(categories ? { categories } : {}),
|
|
451
|
+
...(isAvatar ? { isAvatar: true } : {}),
|
|
452
|
+
...(isAiSticker ? { isAiSticker: true } : {}),
|
|
453
|
+
}, options);
|
|
454
|
+
};
|
|
455
|
+
const sendStickerFromUrl = async (jid, url, options = {}) => { if (!url) throw new Error("sendStickerFromUrl: url wajib"); return sock.sendMessage(jid, { sticker: { url } }, options); };
|
|
456
|
+
const sendStickerFromBuffer = async (jid, buffer, metadata = {}, options = {}) => { if (!buffer) throw new Error("sendStickerFromBuffer: buffer wajib"); return sendStickerWithMetadata(jid, buffer, metadata, options); };
|
|
457
|
+
const sendStickerMessage = async (jid, sticker, cfg = {}, options = {}) => {
|
|
458
|
+
if (!sticker) throw new Error("sendStickerMessage: sticker wajib");
|
|
459
|
+
return sock.sendMessage(jid, {
|
|
460
|
+
sticker, mimetype: "image/webp",
|
|
461
|
+
...(cfg.packName ? { stickerPackName: cfg.packName } : {}),
|
|
462
|
+
...(cfg.packPublisher ? { stickerPackPublisher: cfg.packPublisher } : {}),
|
|
463
|
+
...(cfg.categories ? { categories: cfg.categories } : {}),
|
|
464
|
+
...(cfg.isAvatar ? { isAvatar: true } : {}),
|
|
465
|
+
...(cfg.isAiSticker ? { isAiSticker: true } : {}),
|
|
385
466
|
}, options);
|
|
386
467
|
};
|
|
387
|
-
|
|
388
468
|
const sendStickerPack = async (jid, stickers, packName, packPublisher, options = {}) => {
|
|
389
|
-
if (!Array.isArray(stickers) || !stickers.length) throw new Error(
|
|
390
|
-
if (stickers.length > 30) throw new Error(
|
|
469
|
+
if (!Array.isArray(stickers) || !stickers.length) throw new Error("sendStickerPack: stickers kosong");
|
|
470
|
+
if (stickers.length > 30) throw new Error("sendStickerPack: maks 30 sticker");
|
|
391
471
|
const delayMs = options.delayMs || 300;
|
|
392
472
|
const results = [];
|
|
393
473
|
for (const sticker of stickers) {
|
|
394
|
-
try {
|
|
395
|
-
|
|
396
|
-
results.push({ success: true, msg });
|
|
397
|
-
} catch (err) {
|
|
398
|
-
results.push({ success: false, error: err.message });
|
|
399
|
-
}
|
|
474
|
+
try { results.push({ success: true, msg: await sendStickerWithMetadata(jid, sticker, { packName, packPublisher }, options) }); }
|
|
475
|
+
catch (err) { results.push({ success: false, error: err.message }); }
|
|
400
476
|
if (delayMs > 0) await _sleep(delayMs);
|
|
401
477
|
}
|
|
402
478
|
return results;
|
|
403
479
|
};
|
|
404
480
|
|
|
481
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
482
|
+
// SIMPLE MEDIA
|
|
483
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
405
484
|
const sendDocument = async (jid, document, fileName, mimetype, caption, options = {}) => {
|
|
406
|
-
if (!document) throw new Error(
|
|
407
|
-
if (!fileName) throw new Error(
|
|
408
|
-
return sock.sendMessage(jid, {
|
|
409
|
-
document,
|
|
410
|
-
fileName,
|
|
411
|
-
mimetype: mimetype || 'application/octet-stream',
|
|
412
|
-
...(caption ? { caption } : {})
|
|
413
|
-
}, options);
|
|
485
|
+
if (!document) throw new Error("sendDocument: document wajib");
|
|
486
|
+
if (!fileName) throw new Error("sendDocument: fileName wajib");
|
|
487
|
+
return sock.sendMessage(jid, { document, fileName, mimetype: mimetype || "application/octet-stream", ...(caption ? { caption } : {}) }, options);
|
|
414
488
|
};
|
|
415
|
-
|
|
416
489
|
const sendAudio = async (jid, audio, isPtt = false, options = {}) => {
|
|
417
|
-
if (!audio) throw new Error(
|
|
418
|
-
return sock.sendMessage(jid, {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
};
|
|
429
|
-
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
490
|
+
if (!audio) throw new Error("sendAudio: audio wajib");
|
|
491
|
+
return sock.sendMessage(jid, { audio, mimetype: isPtt ? "audio/ogg; codecs=opus" : "audio/mp4", ptt: isPtt }, options);
|
|
492
|
+
};
|
|
493
|
+
const sendImage = async (jid, image, caption, options = {}) => { if (!image) throw new Error("sendImage: image wajib"); return sock.sendMessage(jid, { image, ...(caption ? { caption } : {}) }, options); };
|
|
494
|
+
const sendVideo = async (jid, video, caption, options = {}) => { if (!video) throw new Error("sendVideo: video wajib"); return sock.sendMessage(jid, { video, ...(caption ? { caption } : {}) }, options); };
|
|
495
|
+
const sendAudioPTT = async (jid, audio, options = {}) => sendAudio(jid, audio, true, options);
|
|
496
|
+
const sendVoiceNote = async (jid, audio, options = {}) => sendAudio(jid, audio, true, options);
|
|
497
|
+
|
|
498
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
499
|
+
// REPLY / QUOTE
|
|
500
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
501
|
+
const sendReply = async (jid, text, quotedMessage, options = {}) => { if (!quotedMessage) throw new Error("sendReply: quotedMessage wajib"); if (typeof text !== "string") throw new Error("sendReply: text harus string"); return sock.sendMessage(jid, { text }, { quoted: quotedMessage, ...options }); };
|
|
502
|
+
const sendMediaReply = async (jid, content, quotedMessage, options = {}) => { if (!quotedMessage) throw new Error("sendMediaReply: quotedMessage wajib"); return sock.sendMessage(jid, content, { quoted: quotedMessage, ...options }); };
|
|
503
|
+
const sendQuotedText = async (jid, text, quotedMessage, mentions, options = {}) => { if (!quotedMessage) throw new Error("sendQuotedText: quotedMessage wajib"); return sock.sendMessage(jid, { text, ...(mentions?.length ? { mentions } : {}) }, { quoted: quotedMessage, ...options }); };
|
|
504
|
+
const sendWithMentionAndReply = async (jid, text, quotedMessage, mentions = [], options = {}) => { if (!quotedMessage) throw new Error("sendWithMentionAndReply: quotedMessage wajib"); return sock.sendMessage(jid, { text, ...(mentions.length ? { mentions } : {}) }, { quoted: quotedMessage, ...options }); };
|
|
505
|
+
const sendWithQuotedFake = async (jid, text, fakeQuoted = {}, options = {}) => {
|
|
506
|
+
const { sender, text: quotedText, id } = fakeQuoted;
|
|
507
|
+
if (!sender) throw new Error("sendWithQuotedFake: fakeQuoted.sender wajib");
|
|
508
|
+
if (!quotedText) throw new Error("sendWithQuotedFake: fakeQuoted.text wajib");
|
|
509
|
+
const fakeMsg = {
|
|
510
|
+
key: {
|
|
511
|
+
fromMe: false,
|
|
512
|
+
participant: sender,
|
|
513
|
+
remoteJid: jid,
|
|
514
|
+
id: id || (0, crypto_1.randomBytes)(8).toString("hex").toUpperCase(),
|
|
515
|
+
},
|
|
516
|
+
message: { conversation: quotedText },
|
|
517
|
+
};
|
|
518
|
+
return sock.sendMessage(jid, { text }, { quoted: fakeMsg, ...options });
|
|
444
519
|
};
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
return sock.sendMessage(jid, {
|
|
449
|
-
text,
|
|
450
|
-
...(mentions?.length ? { mentions } : {})
|
|
451
|
-
}, { quoted: quotedMessage, ...options });
|
|
520
|
+
const forwardWithComment = async (jid, message, comment, options = {}) => {
|
|
521
|
+
if (!message) throw new Error("forwardWithComment: message wajib");
|
|
522
|
+
await sock.sendMessage(jid, { text: comment }, options);
|
|
523
|
+
return sock.sendMessage(jid, { forward: message, force: true }, options);
|
|
452
524
|
};
|
|
453
525
|
|
|
526
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
527
|
+
// GROUP INVITE
|
|
528
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
454
529
|
const sendGroupInvite = async (jid, groupJid, options = {}) => {
|
|
455
|
-
if (!
|
|
456
|
-
const [code, meta] = await Promise.all([
|
|
457
|
-
sock.groupInviteCode(groupJid),
|
|
458
|
-
sock.groupMetadata(groupJid)
|
|
459
|
-
]);
|
|
530
|
+
if (!_isGrp(groupJid)) throw new Error("sendGroupInvite: groupJid harus @g.us");
|
|
531
|
+
const [code, meta] = await Promise.all([sock.groupInviteCode(groupJid), sock.groupMetadata(groupJid)]);
|
|
460
532
|
return sock.sendMessage(jid, {
|
|
461
533
|
groupInviteMessage: {
|
|
462
|
-
groupJid,
|
|
463
|
-
inviteCode: code,
|
|
534
|
+
groupJid, inviteCode: code,
|
|
464
535
|
inviteExpiration: Math.floor(Date.now() / 1000) + 259200,
|
|
465
|
-
groupName: meta.subject,
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
}
|
|
536
|
+
groupName: meta.subject, caption: options.caption || "",
|
|
537
|
+
jpegThumbnail: meta.picturePreview || null,
|
|
538
|
+
},
|
|
469
539
|
}, options);
|
|
470
540
|
};
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
return
|
|
541
|
+
const sendAdminInvite = async (jid, groupJid, options = {}) => {
|
|
542
|
+
if (!_isGrp(groupJid)) throw new Error("sendAdminInvite: groupJid harus @g.us");
|
|
543
|
+
const [code, meta] = await Promise.all([sock.groupInviteCode(groupJid), sock.groupMetadata(groupJid)]);
|
|
544
|
+
const msg = _gen(jid, {
|
|
545
|
+
groupInviteMessage: {
|
|
546
|
+
groupJid, inviteCode: code,
|
|
547
|
+
inviteExpiration: Math.floor(Date.now() / 1000) + 259200,
|
|
548
|
+
groupName: meta.subject,
|
|
549
|
+
caption: options.caption || `Kamu diundang jadi admin di ${meta.subject}`,
|
|
550
|
+
},
|
|
551
|
+
});
|
|
552
|
+
return _relay(jid, msg);
|
|
483
553
|
};
|
|
484
554
|
|
|
485
|
-
|
|
486
|
-
|
|
555
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
556
|
+
// CHAT MANAGEMENT
|
|
557
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
558
|
+
const muteJid = async (jid, durationMs = 8 * 60 * 60 * 1000) => sock.chatModify({ mute: durationMs }, jid);
|
|
559
|
+
const unmuteJid = async (jid) => sock.chatModify({ mute: null }, jid);
|
|
560
|
+
const archiveChat = async (jid, lastMessage) => { if (!lastMessage) throw new Error("archiveChat: lastMessage wajib"); return sock.chatModify({ archive: true, lastMessages: [lastMessage] }, jid); };
|
|
561
|
+
const unarchiveChat = async (jid, lastMessage) => { if (!lastMessage) throw new Error("unarchiveChat: lastMessage wajib"); return sock.chatModify({ archive: false, lastMessages: [lastMessage] }, jid); };
|
|
562
|
+
const pinChat = async (jid) => sock.chatModify({ pin: true }, jid);
|
|
563
|
+
const unpinChat = async (jid) => sock.chatModify({ pin: false }, jid);
|
|
487
564
|
const markAsRead = async (keys) => sock.readMessages(Array.isArray(keys) ? keys : [keys]);
|
|
488
|
-
|
|
489
|
-
const markAsUnread = async (jid, lastMessage) => {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
};
|
|
493
|
-
|
|
494
|
-
const
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
565
|
+
const sendSeen = async (jid, messages = []) => sock.readMessages(messages.map(m => m.key || m));
|
|
566
|
+
const markAsUnread = async (jid, lastMessage) => { if (!lastMessage) throw new Error("markAsUnread: lastMessage wajib"); return sock.chatModify({ markRead: false, lastMessages: [lastMessage] }, jid); };
|
|
567
|
+
const blockUser = async (jid) => sock.updateBlockStatus(_norm(jid), "block");
|
|
568
|
+
const unblockUser = async (jid) => sock.updateBlockStatus(_norm(jid), "unblock");
|
|
569
|
+
const starMessage = async (jid, messageId, fromMe = false) => sock.chatModify({ star: { messages: [{ id: messageId, fromMe }], star: true } }, jid);
|
|
570
|
+
const unstarMessage = async (jid, messageId, fromMe = false) => sock.chatModify({ star: { messages: [{ id: messageId, fromMe }], star: false } }, jid);
|
|
571
|
+
const deleteChat = async (jid, lastMessage) => { if (!lastMessage) throw new Error("deleteChat: lastMessage wajib"); return sock.chatModify({ delete: true, lastMessages: [{ key: lastMessage.key, messageTimestamp: lastMessage.messageTimestamp }] }, jid); };
|
|
572
|
+
const clearChat = async (jid, messages = []) => sock.chatModify({ clear: { messages: messages.map(m => ({ id: m.key.id, fromMe: m.key.fromMe, timestamp: m.messageTimestamp })) } }, jid);
|
|
573
|
+
const sendLinkPreview = async (jid, text, options = {}) => sock.sendMessage(jid, { text, detectLinks: true }, options);
|
|
574
|
+
const sendDisappearingToggle = async (jid, enable = true) => sock.sendMessage(jid, { disappearingMessagesInChat: enable ? 86400 : false });
|
|
575
|
+
|
|
576
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
577
|
+
// PROFILE
|
|
578
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
579
|
+
const getProfilePicture = async (jid, highRes = false) => { try { return await sock.profilePictureUrl(jid, highRes ? "image" : "preview"); } catch { return null; } };
|
|
580
|
+
const getUserStatus = async (jid) => { try { return await sock.fetchStatus(jid); } catch { return null; } };
|
|
581
|
+
const getContactInfo = async (jid) => {
|
|
582
|
+
const [onWA, pic, status] = await Promise.allSettled([isOnWhatsApp(jid), getProfilePicture(jid, true), getUserStatus(jid)]);
|
|
583
|
+
return {
|
|
584
|
+
jid,
|
|
585
|
+
exists: onWA.status === "fulfilled" ? onWA.value?.exists : false,
|
|
586
|
+
profilePic: pic.status === "fulfilled" ? pic.value : null,
|
|
587
|
+
status: status.status === "fulfilled" ? status.value : null,
|
|
588
|
+
};
|
|
505
589
|
};
|
|
590
|
+
const updateProfilePicture = async (jid, image) => { if (!image) throw new Error("updateProfilePicture: image wajib"); return sock.updateProfilePicture(jid, image); };
|
|
591
|
+
const removeProfilePicture = async (jid) => sock.removeProfilePicture(jid);
|
|
592
|
+
const updateProfileName = async (name) => { if (!name) throw new Error("updateProfileName: name wajib"); return sock.updateProfileName(name); };
|
|
593
|
+
const updateProfileStatus = async (status) => { if (typeof status !== "string") throw new Error("updateProfileStatus: harus string"); return sock.updateProfileStatus(status); };
|
|
506
594
|
|
|
595
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
596
|
+
// DISAPPEARING
|
|
597
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
507
598
|
const sendDisappearingMessage = async (jid, content, expiration, options = {}) => {
|
|
508
599
|
if (![0, 86400, 604800, 7776000].includes(expiration))
|
|
509
|
-
throw new Error(
|
|
600
|
+
throw new Error("sendDisappearingMessage: expiration harus 0/86400/604800/7776000");
|
|
510
601
|
return sock.sendMessage(jid, content, { ephemeralExpiration: expiration, ...options });
|
|
511
602
|
};
|
|
512
603
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
};
|
|
517
|
-
|
|
518
|
-
const getGroupAdmins = async (groupJid) => {
|
|
519
|
-
if (!_isGroup(groupJid)) throw new Error('getGroupAdmins: harus @g.us');
|
|
520
|
-
const meta = await sock.groupMetadata(groupJid);
|
|
521
|
-
return (meta.participants || []).filter(p => p.admin === 'admin' || p.admin === 'superadmin');
|
|
522
|
-
};
|
|
523
|
-
|
|
524
|
-
const isGroupAdmin = async (groupJid, userJid) => {
|
|
525
|
-
const admins = await getGroupAdmins(groupJid);
|
|
526
|
-
const normalized = _norm(userJid);
|
|
527
|
-
return admins.some(a => _norm(a.id || a.jid) === normalized);
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
const sendToAdminsOnly = async (groupJid, content, options = {}) => {
|
|
531
|
-
if (!_isGroup(groupJid)) throw new Error('sendToAdminsOnly: harus group JID');
|
|
532
|
-
const adminJids = (await getGroupAdmins(groupJid)).map(a => a.id || a.jid);
|
|
533
|
-
if (!adminJids.length) return null;
|
|
534
|
-
return sock.sendMessage(groupJid, {
|
|
535
|
-
...(typeof content === 'string' ? { text: content } : content),
|
|
536
|
-
mentions: adminJids
|
|
537
|
-
}, options);
|
|
538
|
-
};
|
|
539
|
-
|
|
540
|
-
const bulkGroupAction = async (groupJid, participantJids, action) => {
|
|
541
|
-
const valid = ['add', 'remove', 'promote', 'demote'];
|
|
542
|
-
if (!valid.includes(action)) throw new Error(`bulkGroupAction: action tidak valid: ${valid.join(', ')}`);
|
|
543
|
-
if (!_isGroup(groupJid)) throw new Error('bulkGroupAction: harus group JID');
|
|
544
|
-
if (!Array.isArray(participantJids) || !participantJids.length)
|
|
545
|
-
throw new Error('bulkGroupAction: participantJids kosong');
|
|
546
|
-
const results = [];
|
|
547
|
-
for (let i = 0; i < participantJids.length; i += 5) {
|
|
548
|
-
const chunk = participantJids.slice(i, i + 5);
|
|
549
|
-
try {
|
|
550
|
-
const res = await sock.groupParticipantsUpdate(groupJid, chunk, action);
|
|
551
|
-
results.push(...res);
|
|
552
|
-
} catch (err) {
|
|
553
|
-
results.push(...chunk.map(jid => ({ jid, status: 'error', error: err.message })));
|
|
554
|
-
}
|
|
555
|
-
if (i + 5 < participantJids.length) await _sleep(500);
|
|
556
|
-
}
|
|
557
|
-
return results;
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
const sendMultipleMessages = async (jid, contents, delayMs = 500) => {
|
|
561
|
-
if (!Array.isArray(contents) || !contents.length)
|
|
562
|
-
throw new Error('sendMultipleMessages: contents kosong');
|
|
563
|
-
const results = [];
|
|
564
|
-
for (const content of contents) {
|
|
565
|
-
try {
|
|
566
|
-
const msg = await sock.sendMessage(jid, content);
|
|
567
|
-
results.push({ success: true, msg });
|
|
568
|
-
} catch (err) {
|
|
569
|
-
results.push({ success: false, error: err.message });
|
|
570
|
-
}
|
|
571
|
-
if (delayMs > 0) await _sleep(delayMs);
|
|
572
|
-
}
|
|
573
|
-
return results;
|
|
574
|
-
};
|
|
575
|
-
|
|
576
|
-
const rejectAllCalls = () => {
|
|
577
|
-
sock.ev.on('call', async ([call]) => {
|
|
578
|
-
try { await sock.rejectCall(call.id, call.from); } catch {}
|
|
579
|
-
});
|
|
580
|
-
};
|
|
581
|
-
|
|
604
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
605
|
+
// MISC
|
|
606
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
582
607
|
const isOnWhatsApp = async (jidOrNumber) => {
|
|
583
608
|
let jid = jidOrNumber;
|
|
584
|
-
if (!jid.includes(
|
|
585
|
-
const
|
|
586
|
-
return result || { exists: false, jid };
|
|
587
|
-
};
|
|
588
|
-
|
|
589
|
-
const
|
|
590
|
-
const
|
|
591
|
-
const
|
|
592
|
-
const
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
});
|
|
609
|
+
if (!jid.includes("@")) jid = jid.replace(/[^0-9]/g, "") + "@s.whatsapp.net";
|
|
610
|
+
const result = await sock.onWhatsApp(jid);
|
|
611
|
+
return (Array.isArray(result) ? result[0] : result) || { exists: false, jid };
|
|
612
|
+
};
|
|
613
|
+
const rejectAllCalls = () => sock.ev.on("call", async ([call]) => { try { await sock.rejectCall(call.id, call.from); } catch { } });
|
|
614
|
+
const getBusinessProfile = async (jid) => { try { return await sock.getBusinessProfile(_norm(jid)); } catch { return null; } };
|
|
615
|
+
const fetchMessageHistory = async (jid, count = 25, oldestMsg) => { if (!oldestMsg) throw new Error("fetchMessageHistory: oldestMsg wajib"); return sock.fetchMessageHistory(count, oldestMsg.key, oldestMsg.messageTimestamp); };
|
|
616
|
+
const presenceSubscribe = async (jid) => sock.presenceSubscribe(jid);
|
|
617
|
+
const updatePrivacyLastSeen = async (v) => sock.updateLastSeenPrivacy(v);
|
|
618
|
+
const updatePrivacyProfilePic = async (v) => sock.updateProfilePicturePrivacy(v);
|
|
619
|
+
const updatePrivacyStatus = async (v) => sock.updateStatusPrivacy(v);
|
|
620
|
+
const updatePrivacyReadReceipts = async (v) => sock.updateReadReceiptsPrivacy(v);
|
|
621
|
+
const updatePrivacyGroupsAdd = async (v) => sock.updateGroupsAddPrivacy(v);
|
|
622
|
+
const updatePrivacyOnline = async (v) => sock.updateOnlinePrivacy(v);
|
|
623
|
+
const setDefaultDisappearing = async (exp) => sock.updateDefaultDisappearingMode(exp);
|
|
624
|
+
const fetchBlocklist = async () => sock.fetchBlocklist();
|
|
625
|
+
const fetchAllGroups = async () => sock.groupFetchAllParticipating();
|
|
626
|
+
|
|
627
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
628
|
+
// INTERACTIVE — Buttons / List / Template
|
|
629
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
630
|
+
const _mapButtons = (buttons) => buttons.map((b, i) => ({
|
|
631
|
+
buttonId: b.buttonId || b.id || `btn_${i}`,
|
|
632
|
+
buttonText: b.buttonText ? b.buttonText : { displayText: b.displayText || b.text || "" },
|
|
633
|
+
type: 1,
|
|
634
|
+
}));
|
|
635
|
+
|
|
636
|
+
const sendButtonsMessage = async (jid, text, buttons = [], footer = "", options = {}) => {
|
|
637
|
+
if (!buttons.length) throw new Error("sendButtonsMessage: min 1 tombol");
|
|
638
|
+
if (buttons.length > 3) throw new Error("sendButtonsMessage: maks 3 tombol");
|
|
639
|
+
const msg = _gen(jid, { buttonsMessage: { contentText: text, footerText: footer, buttons: _mapButtons(buttons), headerType: 1 } });
|
|
616
640
|
return _relay(jid, msg);
|
|
617
641
|
};
|
|
618
642
|
|
|
619
643
|
const sendListMessage = async (jid, cfg = {}, options = {}) => {
|
|
620
644
|
const { title, text, footer, buttonText, sections } = cfg;
|
|
621
|
-
if (!sections?.length) throw new Error(
|
|
645
|
+
if (!sections?.length) throw new Error("sendListMessage: sections wajib");
|
|
622
646
|
const msg = _gen(jid, {
|
|
623
647
|
listMessage: {
|
|
624
|
-
title: title ||
|
|
625
|
-
|
|
626
|
-
footerText: footer || '',
|
|
627
|
-
buttonText: buttonText || 'Lihat',
|
|
628
|
-
listType: 1,
|
|
648
|
+
title: title || "", description: text || "", footerText: footer || "",
|
|
649
|
+
buttonText: buttonText || "Lihat", listType: 1,
|
|
629
650
|
sections: sections.map(s => ({
|
|
630
|
-
title: s.title ||
|
|
651
|
+
title: s.title || "",
|
|
631
652
|
rows: (s.rows || []).map(r => ({
|
|
632
|
-
rowId: r.id,
|
|
653
|
+
rowId: r.rowId || r.id,
|
|
633
654
|
title: r.title,
|
|
634
|
-
description: r.description ||
|
|
635
|
-
}))
|
|
636
|
-
}))
|
|
637
|
-
}
|
|
655
|
+
description: r.description || "",
|
|
656
|
+
})),
|
|
657
|
+
})),
|
|
658
|
+
},
|
|
638
659
|
});
|
|
639
660
|
return _relay(jid, msg);
|
|
640
661
|
};
|
|
641
662
|
|
|
642
663
|
const sendTemplateMessage = async (jid, cfg = {}, options = {}) => {
|
|
643
664
|
const { text, footer, templateButtons = [] } = cfg;
|
|
644
|
-
if (!templateButtons.length) throw new Error(
|
|
665
|
+
if (!templateButtons.length) throw new Error("sendTemplateMessage: templateButtons wajib");
|
|
645
666
|
const hydratedButtons = templateButtons.map((b, i) => {
|
|
646
667
|
if (b.quickReply) return { index: b.index ?? i, quickReplyButton: { displayText: b.quickReply.displayText, id: b.quickReply.id } };
|
|
647
|
-
if (b.urlButton)
|
|
668
|
+
if (b.urlButton) return { index: b.index ?? i, urlButton: { displayText: b.urlButton.displayText, url: b.urlButton.url } };
|
|
648
669
|
if (b.callButton) return { index: b.index ?? i, callButton: { displayText: b.callButton.displayText, phoneNumber: b.callButton.phoneNumber } };
|
|
649
670
|
return b;
|
|
650
671
|
});
|
|
651
|
-
const msg = _gen(jid, {
|
|
652
|
-
templateMessage: {
|
|
653
|
-
hydratedTemplate: {
|
|
654
|
-
hydratedContentText: text || '',
|
|
655
|
-
hydratedFooterText: footer || '',
|
|
656
|
-
hydratedButtons
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
});
|
|
672
|
+
const msg = _gen(jid, { templateMessage: { hydratedTemplate: { hydratedContentText: text || "", hydratedFooterText: footer || "", hydratedButtons } } });
|
|
660
673
|
return _relay(jid, msg);
|
|
661
674
|
};
|
|
662
675
|
|
|
@@ -664,15 +677,14 @@ const makeBusinessSocket = (config) => {
|
|
|
664
677
|
const { body, footer, header, buttons, sections, nativeFlow } = cfg;
|
|
665
678
|
let headerContent = null;
|
|
666
679
|
if (header) {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
headerContent = { documentMessage: { ...inner.documentMessage } };
|
|
680
|
+
const typeMap = { image: "image", video: "video", document: "document" };
|
|
681
|
+
if (typeMap[header.type]) {
|
|
682
|
+
const inner = await (0, Utils_1.generateWAMessageContent)(
|
|
683
|
+
{ [header.type]: header.content, ...(header.type === "document" ? { fileName: header.fileName } : {}) },
|
|
684
|
+
{ upload: waUploadToServer }
|
|
685
|
+
);
|
|
686
|
+
const msgKey = `${header.type}Message`;
|
|
687
|
+
headerContent = { [msgKey]: { ...inner[msgKey], ...(header.caption ? { caption: header.caption } : {}) } };
|
|
676
688
|
}
|
|
677
689
|
}
|
|
678
690
|
let action = null;
|
|
@@ -682,424 +694,171 @@ const makeBusinessSocket = (config) => {
|
|
|
682
694
|
action = {
|
|
683
695
|
sections: sections.map(s => ({
|
|
684
696
|
title: s.title,
|
|
685
|
-
rows: (s.rows || []).map(r => ({ rowId: r.id, title: r.title, description: r.description ||
|
|
697
|
+
rows: (s.rows || []).map(r => ({ rowId: r.id || r.rowId, title: r.title, description: r.description || "" })),
|
|
686
698
|
})),
|
|
687
|
-
buttonText: cfg.listButtonText ||
|
|
699
|
+
buttonText: cfg.listButtonText || "Pilih",
|
|
688
700
|
};
|
|
689
701
|
} else if (nativeFlow) {
|
|
690
|
-
action = { nativeFlowMessage: { name: nativeFlow.name, paramsJson: nativeFlow.paramsJson ||
|
|
702
|
+
action = { nativeFlowMessage: { name: nativeFlow.name, paramsJson: nativeFlow.paramsJson || "{}" } };
|
|
691
703
|
}
|
|
692
704
|
const msg = _gen(jid, {
|
|
693
705
|
interactiveMessage: {
|
|
694
|
-
body:
|
|
695
|
-
footer: { text: footer ||
|
|
706
|
+
body: { text: body || "" },
|
|
707
|
+
footer: { text: footer || "" },
|
|
696
708
|
...(headerContent ? { header: headerContent } : {}),
|
|
697
|
-
...(action
|
|
698
|
-
}
|
|
709
|
+
...(action ? { action } : {}),
|
|
710
|
+
},
|
|
699
711
|
});
|
|
700
712
|
return _relay(jid, msg);
|
|
701
713
|
};
|
|
702
714
|
|
|
703
715
|
const sendHighlyStructuredMessage = async (jid, cfg = {}) => {
|
|
704
716
|
const { namespace, elementName, params = [] } = cfg;
|
|
705
|
-
if (!namespace || !elementName) throw new Error(
|
|
717
|
+
if (!namespace || !elementName) throw new Error("sendHighlyStructuredMessage: namespace dan elementName wajib");
|
|
706
718
|
const msg = _gen(jid, {
|
|
707
719
|
highlyStructuredMessage: {
|
|
708
|
-
namespace,
|
|
709
|
-
elementName,
|
|
720
|
+
namespace, elementName,
|
|
710
721
|
params: params.map(p => ({ default: p })),
|
|
711
722
|
deterministicLottie: cfg.deterministicLottie || false,
|
|
712
|
-
fallbackLg:
|
|
713
|
-
fallbackLc: 'ID'
|
|
714
|
-
}
|
|
715
|
-
});
|
|
716
|
-
return _relay(jid, msg);
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
const sendProductMessage = async (jid, productId, catalogJid, options = {}) => {
|
|
720
|
-
const bizJid = _norm(catalogJid || _me());
|
|
721
|
-
const catalog = await getCatalog({ jid: bizJid });
|
|
722
|
-
const product = catalog?.products?.find(p => p.id === productId);
|
|
723
|
-
if (!product) throw new Error(`sendProductMessage: produk ${productId} tidak ditemukan`);
|
|
724
|
-
const msg = _gen(jid, {
|
|
725
|
-
productMessage: {
|
|
726
|
-
product: {
|
|
727
|
-
productId: product.id,
|
|
728
|
-
title: product.title,
|
|
729
|
-
description: product.description || '',
|
|
730
|
-
currencyCode: product.currency,
|
|
731
|
-
priceAmount1000: product.price,
|
|
732
|
-
retailerId: product.retailerId || '',
|
|
733
|
-
url: product.url || '',
|
|
734
|
-
productImageCount: product.images?.length || 0,
|
|
735
|
-
firstImageId: product.images?.[0]?.id || ''
|
|
736
|
-
},
|
|
737
|
-
businessOwnerJid: bizJid,
|
|
738
|
-
catalog: { catalogJid: bizJid }
|
|
739
|
-
}
|
|
740
|
-
});
|
|
741
|
-
return _relay(jid, msg);
|
|
742
|
-
};
|
|
743
|
-
|
|
744
|
-
const sendWithQuotedFake = async (jid, text, fakeQuoted = {}, options = {}) => {
|
|
745
|
-
const { sender, text: quotedText, id } = fakeQuoted;
|
|
746
|
-
if (!sender) throw new Error('sendWithQuotedFake: fakeQuoted.sender wajib');
|
|
747
|
-
if (!quotedText) throw new Error('sendWithQuotedFake: fakeQuoted.text wajib');
|
|
748
|
-
const fakeMsg = {
|
|
749
|
-
key: {
|
|
750
|
-
fromMe: false,
|
|
751
|
-
participant: sender,
|
|
752
|
-
remoteJid: jid,
|
|
753
|
-
id: id || Math.random().toString(36).slice(2, 12).toUpperCase()
|
|
723
|
+
fallbackLg: "id", fallbackLc: "ID",
|
|
754
724
|
},
|
|
755
|
-
message: { conversation: quotedText }
|
|
756
|
-
};
|
|
757
|
-
return sock.sendMessage(jid, { text }, { quoted: fakeMsg, ...options });
|
|
758
|
-
};
|
|
759
|
-
|
|
760
|
-
const sendAdminInvite = async (jid, groupJid, options = {}) => {
|
|
761
|
-
if (!_isGroup(groupJid)) throw new Error('sendAdminInvite: groupJid harus @g.us');
|
|
762
|
-
const [code, meta] = await Promise.all([sock.groupInviteCode(groupJid), sock.groupMetadata(groupJid)]);
|
|
763
|
-
const msg = _gen(jid, {
|
|
764
|
-
groupInviteMessage: {
|
|
765
|
-
groupJid,
|
|
766
|
-
inviteCode: code,
|
|
767
|
-
inviteExpiration: Math.floor(Date.now() / 1000) + 259200,
|
|
768
|
-
groupName: meta.subject,
|
|
769
|
-
caption: options.caption || `Kamu diundang jadi admin di ${meta.subject}`
|
|
770
|
-
}
|
|
771
725
|
});
|
|
772
726
|
return _relay(jid, msg);
|
|
773
727
|
};
|
|
774
728
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
...(cfg.packPublisher ? { stickerPackPublisher: cfg.packPublisher } : {}),
|
|
782
|
-
...(cfg.categories ? { categories: cfg.categories } : {}),
|
|
783
|
-
...(cfg.isAvatar ? { isAvatar: true } : {}),
|
|
784
|
-
...(cfg.isAiSticker ? { isAiSticker: true } : {})
|
|
785
|
-
}, options);
|
|
786
|
-
};
|
|
787
|
-
|
|
788
|
-
const starMessage = async (jid, messageId, fromMe = false) => sock.chatModify({ star: { messages: [{ id: messageId, fromMe }], star: true } }, jid);
|
|
789
|
-
const unstarMessage = async (jid, messageId, fromMe = false) => sock.chatModify({ star: { messages: [{ id: messageId, fromMe }], star: false } }, jid);
|
|
790
|
-
|
|
791
|
-
const deleteChat = async (jid, lastMessage) => {
|
|
792
|
-
if (!lastMessage) throw new Error('deleteChat: lastMessage wajib');
|
|
793
|
-
return sock.chatModify({ delete: true, lastMessages: [{ key: lastMessage.key, messageTimestamp: lastMessage.messageTimestamp }] }, jid);
|
|
794
|
-
};
|
|
795
|
-
|
|
796
|
-
const clearChat = async (jid, messages = []) => {
|
|
797
|
-
return sock.chatModify({ clear: { messages: messages.map(m => ({ id: m.key.id, fromMe: m.key.fromMe, timestamp: m.messageTimestamp })) } }, jid);
|
|
798
|
-
};
|
|
799
|
-
|
|
800
|
-
const sendLinkPreview = async (jid, text, options = {}) => {
|
|
801
|
-
return sock.sendMessage(jid, { text: text, detectLinks: true }, options);
|
|
802
|
-
};
|
|
803
|
-
|
|
804
|
-
const sendMentionAll = async (jid, text = '', options = {}) => {
|
|
805
|
-
if (!_isGroup(jid)) throw new Error('sendMentionAll: hanya untuk group');
|
|
806
|
-
const meta = await sock.groupMetadata(jid);
|
|
807
|
-
const mentions = (meta.participants || []).map(p => p.id || p.jid);
|
|
808
|
-
return sock.sendMessage(jid, { text, mentions }, options);
|
|
809
|
-
};
|
|
810
|
-
|
|
811
|
-
const updateGroupName = async (jid, name) => { if (!_isGroup(jid)) throw new Error('updateGroupName: harus @g.us'); if (!name) throw new Error('updateGroupName: name wajib'); return sock.groupUpdateSubject(jid, name); };
|
|
812
|
-
const updateGroupDescription = async (jid, description) => { if (!_isGroup(jid)) throw new Error('updateGroupDescription: harus @g.us'); return sock.groupUpdateDescription(jid, description || ''); };
|
|
813
|
-
|
|
814
|
-
const updateGroupSetting = async (jid, setting) => {
|
|
815
|
-
const valid = ['announcement', 'not_announcement', 'locked', 'unlocked'];
|
|
816
|
-
if (!valid.includes(setting)) throw new Error(`updateGroupSetting: ${valid.join(', ')}`);
|
|
817
|
-
return sock.groupSettingUpdate(jid, setting);
|
|
818
|
-
};
|
|
819
|
-
|
|
820
|
-
const revokeGroupInvite = async (jid) => { if (!_isGroup(jid)) throw new Error('revokeGroupInvite: harus @g.us'); return sock.groupRevokeInvite(jid); };
|
|
821
|
-
const getGroupInviteLink = async (jid) => { if (!_isGroup(jid)) throw new Error('getGroupInviteLink: harus @g.us'); const code = await sock.groupInviteCode(jid); return `https://chat.whatsapp.com/${code}`; };
|
|
822
|
-
|
|
823
|
-
const joinGroupViaLink = async (inviteCode) => {
|
|
824
|
-
const code = inviteCode.includes('chat.whatsapp.com/') ? inviteCode.split('chat.whatsapp.com/')[1] : inviteCode;
|
|
825
|
-
return sock.groupAcceptInvite(code);
|
|
826
|
-
};
|
|
827
|
-
|
|
828
|
-
const leaveGroup = async (jid) => { if (!_isGroup(jid)) throw new Error('leaveGroup: harus @g.us'); return sock.groupLeave(jid); };
|
|
829
|
-
const getGroupParticipants = async (jid) => { if (!_isGroup(jid)) throw new Error('getGroupParticipants: harus @g.us'); const meta = await sock.groupMetadata(jid); return meta.participants || []; };
|
|
830
|
-
const setGroupJoinApproval = async (jid, mode) => { if (!_isGroup(jid)) throw new Error('setGroupJoinApproval: harus @g.us'); return sock.groupJoinApprovalMode(jid, mode ? 'on' : 'off'); };
|
|
831
|
-
const getGroupJoinRequests = async (jid) => { if (!_isGroup(jid)) throw new Error('getGroupJoinRequests: harus @g.us'); return sock.groupRequestParticipantsList(jid); };
|
|
832
|
-
|
|
833
|
-
const approveGroupJoinRequest = async (jid, participantJids) => {
|
|
834
|
-
if (!_isGroup(jid)) throw new Error('approveGroupJoinRequest: harus @g.us');
|
|
835
|
-
return sock.groupRequestParticipantsUpdate(jid, Array.isArray(participantJids) ? participantJids : [participantJids], 'approve');
|
|
729
|
+
// ─── Media + Buttons ──────────────────────────────────────────────────────
|
|
730
|
+
const sendImageWithButtons = async (jid, image, caption, buttons = [], footer = "", options = {}) => {
|
|
731
|
+
if (!image) throw new Error("sendImageWithButtons: image wajib");
|
|
732
|
+
if (!buttons.length) throw new Error("sendImageWithButtons: buttons wajib");
|
|
733
|
+
const inner = await (0, Utils_1.generateWAMessageContent)({ image }, { upload: waUploadToServer });
|
|
734
|
+
return _relay(jid, _gen(jid, { buttonsMessage: { imageMessage: inner.imageMessage, contentText: caption || "", footerText: footer, buttons: _mapButtons(buttons), headerType: 4 } }));
|
|
836
735
|
};
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
if (!
|
|
840
|
-
|
|
736
|
+
const sendVideoWithButtons = async (jid, video, caption, buttons = [], footer = "", options = {}) => {
|
|
737
|
+
if (!video) throw new Error("sendVideoWithButtons: video wajib");
|
|
738
|
+
if (!buttons.length) throw new Error("sendVideoWithButtons: buttons wajib");
|
|
739
|
+
const inner = await (0, Utils_1.generateWAMessageContent)({ video }, { upload: waUploadToServer });
|
|
740
|
+
return _relay(jid, _gen(jid, { buttonsMessage: { videoMessage: inner.videoMessage, contentText: caption || "", footerText: footer, buttons: _mapButtons(buttons), headerType: 5 } }));
|
|
841
741
|
};
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
const updatePrivacyProfilePic = async (v) => sock.updateProfilePicturePrivacy(v);
|
|
848
|
-
const updatePrivacyStatus = async (v) => sock.updateStatusPrivacy(v);
|
|
849
|
-
const updatePrivacyReadReceipts = async (v) => sock.updateReadReceiptsPrivacy(v);
|
|
850
|
-
const updatePrivacyGroupsAdd = async (v) => sock.updateGroupsAddPrivacy(v);
|
|
851
|
-
const updatePrivacyOnline = async (v) => sock.updateOnlinePrivacy(v);
|
|
852
|
-
const setDefaultDisappearing = async (exp) => sock.updateDefaultDisappearingMode(exp);
|
|
853
|
-
const fetchBlocklist = async () => sock.fetchBlocklist();
|
|
854
|
-
const fetchAllGroups = async () => sock.groupFetchAllParticipating();
|
|
855
|
-
|
|
856
|
-
const sendDisappearingToggle = async (jid, enable = true) => {
|
|
857
|
-
return sock.sendMessage(jid, { disappearingMessagesInChat: enable ? 86400 : false });
|
|
742
|
+
const sendDocumentWithButtons = async (jid, document, fileName, caption, buttons = [], footer = "", options = {}) => {
|
|
743
|
+
if (!document) throw new Error("sendDocumentWithButtons: document wajib");
|
|
744
|
+
if (!buttons.length) throw new Error("sendDocumentWithButtons: buttons wajib");
|
|
745
|
+
const inner = await (0, Utils_1.generateWAMessageContent)({ document, fileName }, { upload: waUploadToServer });
|
|
746
|
+
return _relay(jid, _gen(jid, { buttonsMessage: { documentMessage: inner.documentMessage, contentText: caption || "", footerText: footer, buttons: _mapButtons(buttons), headerType: 6 } }));
|
|
858
747
|
};
|
|
859
748
|
|
|
749
|
+
// ─── Newsletter ───────────────────────────────────────────────────────────
|
|
750
|
+
const sendNewsletterMessage = async (newsletterJid, content, options = {}) => { if (!newsletterJid.endsWith("@newsletter")) throw new Error("sendNewsletterMessage: harus @newsletter JID"); return sock.sendMessage(newsletterJid, content, options); };
|
|
860
751
|
const sendNewsletterReaction = async (newsletterJid, messageId, emoji) => {
|
|
861
|
-
if (!newsletterJid.endsWith(
|
|
862
|
-
return query({
|
|
863
|
-
tag: 'iq',
|
|
864
|
-
attrs: { to: newsletterJid, type: 'set', xmlns: 'w:newsletter' },
|
|
865
|
-
content: [{ tag: 'reaction', attrs: { 'message_id': messageId }, content: [{ tag: 'text', attrs: {}, content: emoji }] }]
|
|
866
|
-
});
|
|
752
|
+
if (!newsletterJid.endsWith("@newsletter")) throw new Error("sendNewsletterReaction: harus @newsletter JID");
|
|
753
|
+
return query({ tag: "iq", attrs: { to: newsletterJid, type: "set", xmlns: "w:newsletter" }, content: [{ tag: "reaction", attrs: { "message_id": messageId }, content: [{ tag: "text", attrs: {}, content: emoji }] }] });
|
|
867
754
|
};
|
|
868
|
-
|
|
869
755
|
const getNewsletterInfo = async (newsletterJid) => {
|
|
870
|
-
if (!newsletterJid.endsWith(
|
|
871
|
-
return query({ tag:
|
|
756
|
+
if (!newsletterJid.endsWith("@newsletter")) throw new Error("getNewsletterInfo: harus @newsletter JID");
|
|
757
|
+
return query({ tag: "iq", attrs: { to: newsletterJid, type: "get", xmlns: "w:newsletter" }, content: [{ tag: "metadata", attrs: {} }] });
|
|
872
758
|
};
|
|
873
759
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
if (!quotedMessage) throw new Error('sendWithMentionAndReply: quotedMessage wajib');
|
|
881
|
-
return sock.sendMessage(jid, { text, ...(mentions.length ? { mentions } : {}) }, { quoted: quotedMessage, ...options });
|
|
882
|
-
};
|
|
883
|
-
|
|
884
|
-
const forwardWithComment = async (jid, message, comment, options = {}) => {
|
|
885
|
-
if (!message) throw new Error('forwardWithComment: message wajib');
|
|
886
|
-
await sock.sendMessage(jid, { text: comment }, options);
|
|
887
|
-
return sock.sendMessage(jid, { forward: message, force: true }, options);
|
|
888
|
-
};
|
|
889
|
-
|
|
890
|
-
const sendImageWithButtons = async (jid, image, caption, buttons = [], footer = '', options = {}) => {
|
|
891
|
-
if (!image) throw new Error('sendImageWithButtons: image wajib');
|
|
892
|
-
if (!buttons.length) throw new Error('sendImageWithButtons: buttons wajib');
|
|
893
|
-
const inner = await (0, Utils_1.generateWAMessageContent)({ image }, { upload: waUploadToServer });
|
|
894
|
-
const msg = _gen(jid, {
|
|
895
|
-
buttonsMessage: {
|
|
896
|
-
imageMessage: inner.imageMessage,
|
|
897
|
-
contentText: caption || '',
|
|
898
|
-
footerText: footer,
|
|
899
|
-
buttons: buttons.map((b, i) => ({ buttonId: b.id || `btn_${i}`, buttonText: { displayText: b.displayText || b.text || '' }, type: 1 })),
|
|
900
|
-
headerType: 4
|
|
901
|
-
}
|
|
902
|
-
});
|
|
903
|
-
return _relay(jid, msg);
|
|
904
|
-
};
|
|
905
|
-
|
|
906
|
-
const sendVideoWithButtons = async (jid, video, caption, buttons = [], footer = '', options = {}) => {
|
|
907
|
-
if (!video) throw new Error('sendVideoWithButtons: video wajib');
|
|
908
|
-
if (!buttons.length) throw new Error('sendVideoWithButtons: buttons wajib');
|
|
909
|
-
const inner = await (0, Utils_1.generateWAMessageContent)({ video }, { upload: waUploadToServer });
|
|
910
|
-
const msg = _gen(jid, {
|
|
911
|
-
buttonsMessage: {
|
|
912
|
-
videoMessage: inner.videoMessage,
|
|
913
|
-
contentText: caption || '',
|
|
914
|
-
footerText: footer,
|
|
915
|
-
buttons: buttons.map((b, i) => ({ buttonId: b.id || `btn_${i}`, buttonText: { displayText: b.displayText || b.text || '' }, type: 1 })),
|
|
916
|
-
headerType: 5
|
|
917
|
-
}
|
|
918
|
-
});
|
|
919
|
-
return _relay(jid, msg);
|
|
920
|
-
};
|
|
921
|
-
|
|
922
|
-
const sendDocumentWithButtons = async (jid, document, fileName, caption, buttons = [], footer = '', options = {}) => {
|
|
923
|
-
if (!document) throw new Error('sendDocumentWithButtons: document wajib');
|
|
924
|
-
if (!buttons.length) throw new Error('sendDocumentWithButtons: buttons wajib');
|
|
925
|
-
const inner = await (0, Utils_1.generateWAMessageContent)({ document, fileName }, { upload: waUploadToServer });
|
|
760
|
+
// ─── Product ──────────────────────────────────────────────────────────────
|
|
761
|
+
const sendProductMessage = async (jid, productId, catalogJid, options = {}) => {
|
|
762
|
+
const bizJid = _norm(catalogJid || _me());
|
|
763
|
+
const catalog = await getCatalog({ jid: bizJid });
|
|
764
|
+
const product = catalog?.products?.find(p => p.id === productId);
|
|
765
|
+
if (!product) throw new Error(`sendProductMessage: produk ${productId} tidak ditemukan`);
|
|
926
766
|
const msg = _gen(jid, {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
767
|
+
productMessage: {
|
|
768
|
+
product: {
|
|
769
|
+
productId: product.id, title: product.title,
|
|
770
|
+
description: product.description || "", currencyCode: product.currency,
|
|
771
|
+
priceAmount1000: product.price, retailerId: product.retailerId || "",
|
|
772
|
+
url: product.url || "", productImageCount: product.images?.length || 0,
|
|
773
|
+
firstImageId: product.images?.[0]?.id || "",
|
|
774
|
+
},
|
|
775
|
+
businessOwnerJid: bizJid, catalog: { catalogJid: bizJid },
|
|
776
|
+
},
|
|
934
777
|
});
|
|
935
778
|
return _relay(jid, msg);
|
|
936
779
|
};
|
|
937
780
|
|
|
938
|
-
const sendStickerFromBuffer = async (jid, buffer, metadata = {}, options = {}) => { if (!buffer) throw new Error('sendStickerFromBuffer: buffer wajib'); return sendStickerWithMetadata(jid, buffer, metadata, options); };
|
|
939
|
-
const sendAudioPTT = async (jid, audio, options = {}) => sendAudio(jid, audio, true, options);
|
|
940
|
-
const sendVoiceNote = async (jid, audio, options = {}) => sendAudio(jid, audio, true, options);
|
|
941
|
-
|
|
942
|
-
const getContactInfo = async (jid) => {
|
|
943
|
-
const [onWA, pic, status] = await Promise.allSettled([isOnWhatsApp(jid), getProfilePicture(jid, true), getUserStatus(jid)]);
|
|
944
|
-
return {
|
|
945
|
-
jid,
|
|
946
|
-
exists: onWA.status === 'fulfilled' ? onWA.value?.exists : false,
|
|
947
|
-
profilePic: pic.status === 'fulfilled' ? pic.value : null,
|
|
948
|
-
status: status.status === 'fulfilled' ? status.value : null
|
|
949
|
-
};
|
|
950
|
-
};
|
|
951
|
-
|
|
952
781
|
const sendLocationReply = async (jid, latitude, longitude, name, quotedMessage, options = {}) => {
|
|
953
|
-
if (typeof latitude !==
|
|
954
|
-
if (!quotedMessage) throw new Error(
|
|
782
|
+
if (typeof latitude !== "number" || typeof longitude !== "number") throw new Error("sendLocationReply: lat/lng harus number");
|
|
783
|
+
if (!quotedMessage) throw new Error("sendLocationReply: quotedMessage wajib");
|
|
955
784
|
return sock.sendMessage(jid, { location: { degreesLatitude: latitude, degreesLongitude: longitude, ...(name ? { name } : {}) } }, { quoted: quotedMessage, ...options });
|
|
956
785
|
};
|
|
957
786
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
};
|
|
962
|
-
|
|
787
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
788
|
+
// EXPORTS
|
|
789
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
963
790
|
return {
|
|
964
791
|
...sock,
|
|
965
792
|
logger: config.logger,
|
|
966
793
|
|
|
967
|
-
|
|
968
|
-
getCollections,
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
sendGroupInvite,
|
|
983
|
-
sendAdminInvite,
|
|
984
|
-
updateGroupName,
|
|
985
|
-
updateGroupDescription,
|
|
986
|
-
updateGroupSetting,
|
|
987
|
-
revokeGroupInvite,
|
|
988
|
-
getGroupInviteLink,
|
|
989
|
-
joinGroupViaLink,
|
|
990
|
-
leaveGroup,
|
|
991
|
-
getGroupParticipants,
|
|
992
|
-
setGroupJoinApproval,
|
|
993
|
-
getGroupJoinRequests,
|
|
994
|
-
approveGroupJoinRequest,
|
|
995
|
-
rejectGroupJoinRequest,
|
|
996
|
-
setGroupMemberAddMode,
|
|
997
|
-
updateGroupProfilePicture,
|
|
998
|
-
sendMentionAll,
|
|
999
|
-
|
|
794
|
+
// Catalog
|
|
795
|
+
getCatalog, getCollections, getOrderDetails,
|
|
796
|
+
productCreate, productDelete, productUpdate,
|
|
797
|
+
|
|
798
|
+
// Group
|
|
799
|
+
groupTagAll, groupStatusV2, getGroupAdmins, isGroupAdmin,
|
|
800
|
+
sendToAdminsOnly, bulkGroupAction, setGroupDisappearing,
|
|
801
|
+
sendTagAll, sendGroupInvite, sendAdminInvite,
|
|
802
|
+
updateGroupName, updateGroupDescription, updateGroupSetting,
|
|
803
|
+
revokeGroupInvite, getGroupInviteLink, joinGroupViaLink, leaveGroup,
|
|
804
|
+
getGroupParticipants, setGroupJoinApproval, getGroupJoinRequests,
|
|
805
|
+
approveGroupJoinRequest, rejectGroupJoinRequest,
|
|
806
|
+
setGroupMemberAddMode, updateGroupProfilePicture, sendMentionAll,
|
|
807
|
+
|
|
808
|
+
// Status
|
|
1000
809
|
sendStatus,
|
|
1001
810
|
|
|
1002
|
-
|
|
1003
|
-
sendVideo,
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
sendScheduledCall,
|
|
1019
|
-
sendLinkPreview,
|
|
1020
|
-
sendDisappearingToggle,
|
|
1021
|
-
|
|
1022
|
-
sendStickerFromUrl,
|
|
1023
|
-
sendStickerFromBuffer,
|
|
1024
|
-
sendStickerWithMetadata,
|
|
1025
|
-
sendStickerPack,
|
|
1026
|
-
sendStickerMessage,
|
|
1027
|
-
|
|
1028
|
-
sendButtonsMessage,
|
|
1029
|
-
sendListMessage,
|
|
1030
|
-
sendTemplateMessage,
|
|
1031
|
-
sendInteractiveMessage,
|
|
1032
|
-
sendHighlyStructuredMessage,
|
|
1033
|
-
sendNewsletterMessage,
|
|
1034
|
-
sendNewsletterReaction,
|
|
1035
|
-
getNewsletterInfo,
|
|
1036
|
-
sendProductMessage,
|
|
1037
|
-
sendImageWithButtons,
|
|
1038
|
-
sendVideoWithButtons,
|
|
811
|
+
// Media
|
|
812
|
+
sendImage, sendVideo, sendAudio, sendAudioPTT, sendVoiceNote,
|
|
813
|
+
sendDocument, sendGIF, sendPTV, sendViewOnce, sendAlbum,
|
|
814
|
+
sendLocation, sendLocationReply, sendLiveLocation,
|
|
815
|
+
sendContact, sendPoll, sendEvent, sendScheduledCall,
|
|
816
|
+
sendLinkPreview, sendDisappearingToggle,
|
|
817
|
+
|
|
818
|
+
// Sticker
|
|
819
|
+
sendStickerFromUrl, sendStickerFromBuffer,
|
|
820
|
+
sendStickerWithMetadata, sendStickerPack, sendStickerMessage,
|
|
821
|
+
|
|
822
|
+
// Interactive
|
|
823
|
+
sendButtonsMessage, sendListMessage, sendTemplateMessage,
|
|
824
|
+
sendInteractiveMessage, sendHighlyStructuredMessage,
|
|
825
|
+
sendNewsletterMessage, sendNewsletterReaction, getNewsletterInfo,
|
|
826
|
+
sendProductMessage, sendImageWithButtons, sendVideoWithButtons,
|
|
1039
827
|
sendDocumentWithButtons,
|
|
1040
828
|
|
|
1041
|
-
|
|
1042
|
-
sendMediaReply,
|
|
1043
|
-
|
|
1044
|
-
sendWithQuotedFake,
|
|
1045
|
-
sendWithMentionAndReply,
|
|
1046
|
-
forwardWithComment,
|
|
829
|
+
// Reply / quote
|
|
830
|
+
sendReply, sendMediaReply, sendQuotedText,
|
|
831
|
+
sendWithQuotedFake, sendWithMentionAndReply, forwardWithComment,
|
|
1047
832
|
|
|
1048
|
-
|
|
1049
|
-
sendTyping,
|
|
1050
|
-
sendWithTyping,
|
|
833
|
+
// Mentions / typing
|
|
834
|
+
sendTextWithMentions, sendTyping, sendWithTyping,
|
|
1051
835
|
|
|
1052
|
-
|
|
1053
|
-
broadcastToGroups,
|
|
1054
|
-
sendMultipleMessages,
|
|
836
|
+
// Broadcast
|
|
837
|
+
broadcastMessage, broadcastToGroups, sendMultipleMessages,
|
|
1055
838
|
|
|
1056
|
-
|
|
1057
|
-
keepMessage,
|
|
1058
|
-
|
|
1059
|
-
deleteMessage,
|
|
1060
|
-
reactMessage,
|
|
1061
|
-
forwardMessage,
|
|
839
|
+
// Message actions
|
|
840
|
+
pinMessage, keepMessage, editMessage, deleteMessage,
|
|
841
|
+
reactMessage, forwardMessage,
|
|
1062
842
|
|
|
1063
|
-
|
|
1064
|
-
unmuteJid,
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
unpinChat,
|
|
1069
|
-
markAsRead,
|
|
1070
|
-
markAsUnread,
|
|
1071
|
-
blockUser,
|
|
1072
|
-
unblockUser,
|
|
1073
|
-
starMessage,
|
|
1074
|
-
unstarMessage,
|
|
1075
|
-
deleteChat,
|
|
1076
|
-
clearChat,
|
|
1077
|
-
sendSeen,
|
|
843
|
+
// Chat management
|
|
844
|
+
muteJid, unmuteJid, archiveChat, unarchiveChat,
|
|
845
|
+
pinChat, unpinChat, markAsRead, markAsUnread,
|
|
846
|
+
blockUser, unblockUser, starMessage, unstarMessage,
|
|
847
|
+
deleteChat, clearChat, sendSeen,
|
|
1078
848
|
|
|
1079
|
-
|
|
1080
|
-
getUserStatus,
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
updateProfileName,
|
|
1084
|
-
updateProfileStatus,
|
|
1085
|
-
getContactInfo,
|
|
1086
|
-
getBusinessProfile,
|
|
1087
|
-
fetchBlocklist,
|
|
1088
|
-
fetchAllGroups,
|
|
849
|
+
// Profile
|
|
850
|
+
getProfilePicture, getUserStatus, updateProfilePicture,
|
|
851
|
+
removeProfilePicture, updateProfileName, updateProfileStatus,
|
|
852
|
+
getContactInfo, getBusinessProfile, fetchBlocklist, fetchAllGroups,
|
|
1089
853
|
fetchMessageHistory,
|
|
1090
854
|
|
|
1091
|
-
|
|
1092
|
-
updatePrivacyProfilePic,
|
|
1093
|
-
|
|
1094
|
-
updatePrivacyReadReceipts,
|
|
1095
|
-
updatePrivacyGroupsAdd,
|
|
1096
|
-
updatePrivacyOnline,
|
|
855
|
+
// Privacy
|
|
856
|
+
updatePrivacyLastSeen, updatePrivacyProfilePic, updatePrivacyStatus,
|
|
857
|
+
updatePrivacyReadReceipts, updatePrivacyGroupsAdd, updatePrivacyOnline,
|
|
1097
858
|
setDefaultDisappearing,
|
|
1098
859
|
|
|
1099
|
-
|
|
1100
|
-
isOnWhatsApp,
|
|
1101
|
-
presenceSubscribe,
|
|
1102
|
-
rejectAllCalls,
|
|
860
|
+
// Misc
|
|
861
|
+
sendDisappearingMessage, isOnWhatsApp, presenceSubscribe, rejectAllCalls,
|
|
1103
862
|
};
|
|
1104
863
|
};
|
|
1105
864
|
|