@daolmedo/openclaw-twilio-whatsapp 1.1.4 → 1.1.6

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/dist/index.js CHANGED
@@ -209,6 +209,39 @@ function parseTwilioWebhook(rawBody) {
209
209
  };
210
210
  }
211
211
 
212
+ // src/typing.ts
213
+ async function sendWhatsappTypingIndicator(opts) {
214
+ const auth = Buffer.from(`${opts.accountSid}:${opts.authToken}`).toString("base64");
215
+ const body = new URLSearchParams({ messageId: opts.messageId, channel: "whatsapp" });
216
+ const response = await fetch("https://messaging.twilio.com/v2/Indicators/Typing.json", {
217
+ method: "POST",
218
+ headers: {
219
+ Authorization: `Basic ${auth}`,
220
+ "Content-Type": "application/x-www-form-urlencoded"
221
+ },
222
+ body: body.toString(),
223
+ signal: AbortSignal.timeout(1e4)
224
+ });
225
+ if (!response.ok) {
226
+ throw new Error(`Typing indicator failed: HTTP ${response.status}`);
227
+ }
228
+ }
229
+ function startTypingKeepalive(opts) {
230
+ const { intervalMs = 2e4 } = opts;
231
+ let stopped = false;
232
+ void sendWhatsappTypingIndicator(opts).catch(() => {
233
+ });
234
+ const timer = setInterval(() => {
235
+ if (stopped) return;
236
+ void sendWhatsappTypingIndicator(opts).catch(() => {
237
+ });
238
+ }, intervalMs);
239
+ return () => {
240
+ stopped = true;
241
+ clearInterval(timer);
242
+ };
243
+ }
244
+
212
245
  // src/http-routes.ts
213
246
  var MEDIA_MAX_BYTES = 16 * 1024 * 1024;
214
247
  async function readBody(req) {
@@ -321,6 +354,12 @@ function registerTwilioWhatsappHttpRoutes(api) {
321
354
  MediaUrls: resolvedMedia.map((m) => m.path),
322
355
  MediaTypes: resolvedMedia.map((m) => m.contentType)
323
356
  } : {};
357
+ const stopTyping = fields.messageSid ? startTypingKeepalive({
358
+ accountSid: account.accountSid,
359
+ authToken: account.authToken,
360
+ messageId: fields.messageSid
361
+ }) : () => {
362
+ };
324
363
  dispatchInboundDirectDmWithRuntime({
325
364
  cfg: stored.cfg,
326
365
  runtime: { channel: stored.channelRuntime },
@@ -339,6 +378,7 @@ function registerTwilioWhatsappHttpRoutes(api) {
339
378
  commandAuthorized: true,
340
379
  extraContext: mediaContext,
341
380
  deliver: async (payload) => {
381
+ stopTyping();
342
382
  const text = payload.text ?? "";
343
383
  const mediaUrl = payload.mediaUrl ?? payload.mediaUrls?.[0];
344
384
  if (!text && !mediaUrl) return;
@@ -355,9 +395,11 @@ function registerTwilioWhatsappHttpRoutes(api) {
355
395
  console.error("[twilio-whatsapp] Session record error:", err);
356
396
  },
357
397
  onDispatchError: (err, info) => {
398
+ stopTyping();
358
399
  console.error(`[twilio-whatsapp] Dispatch error (${info.kind}):`, err);
359
400
  }
360
401
  }).catch((err) => {
402
+ stopTyping();
361
403
  console.error("[twilio-whatsapp] Unhandled dispatch error:", err);
362
404
  });
363
405
  return true;
@@ -12,7 +12,6 @@
12
12
  "type": "object",
13
13
  "additionalProperties": false,
14
14
  "properties": {
15
- "enabled": { "type": "boolean" },
16
15
  "dmPolicy": { "type": "string" },
17
16
  "allowFrom": {
18
17
  "type": "array",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daolmedo/openclaw-twilio-whatsapp",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Twilio WhatsApp channel plugin for OpenClaw (Cody ISV)",
5
5
  "type": "module",
6
6
  "exports": {