@laburen/openclaw-plugin-whatsapp-api 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +83 -1
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -97,9 +97,12 @@ const MIME_BY_EXT = {
97
97
  ".m4a": "audio/mp4",
98
98
  ".pdf": "application/pdf",
99
99
  ".txt": "text/plain",
100
+ ".md": "text/markdown",
100
101
  ".csv": "text/csv",
101
102
  ".json": "application/json",
102
- ".zip": "application/zip"
103
+ ".zip": "application/zip",
104
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
105
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
103
106
  };
104
107
  function normalizeMime(value) {
105
108
  const trimmed = value?.trim();
@@ -416,6 +419,48 @@ async function sendWhatsAppApiMedia(params) {
416
419
  }
417
420
  });
418
421
  }
422
+ /**
423
+ * Marks a message as read in the WhatsApp Cloud API.
424
+ *
425
+ * @param params.messageId - The WhatsApp message ID to mark as read
426
+ * @param params.account - Resolved account for Graph auth
427
+ * @returns Graph message id (usually just "unknown" or empty for read marks)
428
+ */
429
+ async function sendWhatsAppApiReadMark(params) {
430
+ const { phoneNumberId, accessToken } = resolveGraphAuth(params.account);
431
+ return await sendWithRetry({
432
+ endpoint: `https://graph.facebook.com/${params.account.outboundApiVersion}/${phoneNumberId}/messages`,
433
+ account: params.account,
434
+ accessToken,
435
+ payload: {
436
+ messaging_product: "whatsapp",
437
+ status: "read",
438
+ message_id: params.messageId
439
+ }
440
+ });
441
+ }
442
+ /**
443
+ * Shows/hides the typing indicator in the WhatsApp Cloud API.
444
+ *
445
+ * @param params.to - Recipient WhatsApp ID
446
+ * @param params.typing - `true` for "typing_on", `false` for "typing_off"
447
+ * @param params.account - Resolved account for Graph auth
448
+ * @returns Graph message id
449
+ */
450
+ async function sendWhatsAppApiTypingIndicator(params) {
451
+ const { phoneNumberId, accessToken } = resolveGraphAuth(params.account);
452
+ return await sendWithRetry({
453
+ endpoint: `https://graph.facebook.com/${params.account.outboundApiVersion}/${phoneNumberId}/messages`,
454
+ account: params.account,
455
+ accessToken,
456
+ payload: {
457
+ messaging_product: "whatsapp",
458
+ recipient_type: "individual",
459
+ to: normalizeRecipient(params.to),
460
+ sender_action: params.typing ? "typing_on" : "typing_off"
461
+ }
462
+ });
463
+ }
419
464
  async function sendWhatsAppApiLocation(params) {
420
465
  const { phoneNumberId, accessToken } = resolveGraphAuth(params.account);
421
466
  return await sendWithRetry({
@@ -1178,9 +1223,33 @@ async function dispatchInboundToAgent(params) {
1178
1223
  OriginatingTo: to
1179
1224
  });
1180
1225
  const dispatchFn = replyApi.dispatchReplyWithBufferedBlockDispatcher;
1226
+ sendWhatsAppApiReadMark({
1227
+ messageId: message.messageId,
1228
+ account
1229
+ }).catch((err) => log$3.warn("failed to mark read", {
1230
+ error: String(err),
1231
+ messageId: message.messageId
1232
+ }));
1181
1233
  await dispatchFn({
1182
1234
  ctx: ctxPayload,
1183
1235
  cfg,
1236
+ typing: {
1237
+ start: async () => {
1238
+ await sendWhatsAppApiTypingIndicator({
1239
+ to: message.from,
1240
+ typing: true,
1241
+ account
1242
+ });
1243
+ },
1244
+ stop: async () => {
1245
+ await sendWhatsAppApiTypingIndicator({
1246
+ to: message.from,
1247
+ typing: false,
1248
+ account
1249
+ });
1250
+ },
1251
+ onStartError: (err) => log$3.warn("failed to start typing", { error: String(err) })
1252
+ },
1184
1253
  dispatcherOptions: {
1185
1254
  deliver: async (payload) => {
1186
1255
  const account = resolveAccount(cfg, accountId);
@@ -1262,6 +1331,19 @@ function createWhatsAppApiChannel(api) {
1262
1331
  account: resolveAccount(cfg, accountId ?? null)
1263
1332
  })
1264
1333
  };
1334
+ },
1335
+ sendMedia: async ({ to, mediaUrl, text, cfg, accountId }) => {
1336
+ const account = resolveAccount(cfg, accountId ?? null);
1337
+ return {
1338
+ channel: CHANNEL_ID,
1339
+ chatId: to,
1340
+ messageId: await sendWhatsAppApiMedia({
1341
+ to,
1342
+ mediaUrl,
1343
+ text: text || void 0,
1344
+ account
1345
+ })
1346
+ };
1265
1347
  }
1266
1348
  },
1267
1349
  gateway: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laburen/openclaw-plugin-whatsapp-api",
3
- "version": "0.3.1",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "WhatsApp API channel plugin for OpenClaw",
6
6
  "main": "index.js",