@daolmedo/openclaw-twilio-whatsapp 1.1.26 → 1.1.28

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
@@ -1,6 +1,11 @@
1
1
  // index.ts
2
2
  import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
3
3
 
4
+ // src/channel.ts
5
+ import {
6
+ buildChannelOutboundSessionRoute
7
+ } from "openclaw/plugin-sdk/channel-core";
8
+
4
9
  // src/accounts.ts
5
10
  var getTwilioChannelConfig = (cfg) => cfg.channels && cfg.channels["twilio-whatsapp"] ? cfg.channels["twilio-whatsapp"] : void 0;
6
11
  function listTwilioAccountIds(cfg) {
@@ -35,7 +40,10 @@ function findTwilioAccountByPhoneNumber(cfg, phoneNumber) {
35
40
  return void 0;
36
41
  }
37
42
  function normalizePhoneNumber(phone) {
38
- return phone.replace(/^whatsapp:/, "").replace(/\s+/g, "");
43
+ return phone.trim().replace(/^(?:(?:twilio-whatsapp|whatsapp):)+/i, "").replace(/\s+/g, "");
44
+ }
45
+ function looksLikePhoneNumber(phone) {
46
+ return /^\+[1-9]\d{6,14}$/.test(normalizePhoneNumber(phone));
39
47
  }
40
48
 
41
49
  // src/outbound-adapter.ts
@@ -163,6 +171,21 @@ function getRuntimeForPhoneNumber(phoneNumber) {
163
171
  }
164
172
 
165
173
  // src/channel.ts
174
+ function resolveTwilioWhatsappOutboundSessionRoute(params) {
175
+ const to = normalizePhoneNumber(params.resolvedTarget?.to ?? params.target);
176
+ if (!looksLikePhoneNumber(to)) return null;
177
+ return buildChannelOutboundSessionRoute({
178
+ cfg: params.cfg,
179
+ agentId: params.agentId,
180
+ channel: "twilio-whatsapp",
181
+ accountId: params.accountId,
182
+ recipientSessionExact: true,
183
+ peer: { kind: "direct", id: to },
184
+ chatType: "direct",
185
+ from: `whatsapp:${to}`,
186
+ to: `whatsapp:${to}`
187
+ });
188
+ }
166
189
  var twilioWhatsappPlugin = {
167
190
  id: "twilio-whatsapp",
168
191
  meta: {
@@ -196,6 +219,15 @@ var twilioWhatsappPlugin = {
196
219
  return listTwilioAccountIds(cfg).length > 0;
197
220
  }
198
221
  },
222
+ messaging: {
223
+ targetPrefixes: ["whatsapp"],
224
+ normalizeTarget: normalizePhoneNumber,
225
+ resolveOutboundSessionRoute: resolveTwilioWhatsappOutboundSessionRoute,
226
+ targetResolver: {
227
+ looksLikeId: (raw, normalized) => looksLikePhoneNumber(normalized ?? raw),
228
+ hint: "<+15551234567>"
229
+ }
230
+ },
199
231
  outbound: twilioWhatsappOutbound,
200
232
  message: twilioWhatsappMessageAdapter,
201
233
  gateway: {
@@ -405,6 +437,22 @@ function resolveMediaBatchFlushMs() {
405
437
  if (Number.isFinite(raw) && raw >= 0) return Math.min(raw, 6e4);
406
438
  return 3e3;
407
439
  }
440
+ function resolveMediaBatchInitialWaitMs() {
441
+ const rawValue = process.env.TWILIO_WHATSAPP_MEDIA_BATCH_INITIAL_WAIT_MS;
442
+ const raw = Number(rawValue);
443
+ if (rawValue !== void 0 && Number.isFinite(raw) && raw >= 0) {
444
+ return Math.min(raw, 6e4);
445
+ }
446
+ if (process.env.TWILIO_WHATSAPP_MEDIA_BATCH_FLUSH_MS !== void 0) {
447
+ return resolveMediaBatchFlushMs();
448
+ }
449
+ return 15e3;
450
+ }
451
+ function resolveMediaBatchMaxWaitMs() {
452
+ const raw = Number(process.env.TWILIO_WHATSAPP_MEDIA_BATCH_MAX_WAIT_MS);
453
+ if (Number.isFinite(raw) && raw >= 0) return Math.min(raw, 6e4);
454
+ return Math.min(resolveMediaBatchInitialWaitMs() + resolveMediaBatchFlushMs(), 6e4);
455
+ }
408
456
  function resolveMediaBatchMaxItems() {
409
457
  const raw = Number(process.env.TWILIO_WHATSAPP_MEDIA_BATCH_MAX_ITEMS);
410
458
  if (Number.isFinite(raw) && raw > 0) return Math.floor(Math.min(raw, 50));
@@ -469,9 +517,13 @@ function stopBatchTimer(batch) {
469
517
  }
470
518
  function armBatchTimer(api, dispatchInbound, key, batch) {
471
519
  stopBatchTimer(batch);
520
+ const batchAgeMs = Math.max(0, Date.now() - batch.firstReceivedAt);
521
+ const desiredWaitMs = batch.items.length === 1 ? resolveMediaBatchInitialWaitMs() : resolveMediaBatchFlushMs();
522
+ const remainingMaxWaitMs = Math.max(0, resolveMediaBatchMaxWaitMs() - batchAgeMs);
523
+ const waitMs = Math.min(desiredWaitMs, remainingMaxWaitMs);
472
524
  batch.timer = setTimeout(() => {
473
525
  void flushPendingMediaBatch(api, dispatchInbound, key, "timer");
474
- }, resolveMediaBatchFlushMs());
526
+ }, waitMs);
475
527
  batch.timer.unref?.();
476
528
  }
477
529
  async function flushPendingMediaBatch(api, dispatchInbound, key, reason) {
@@ -511,7 +563,7 @@ function queueMediaBatch(api, dispatchInbound, key, item) {
511
563
  return new Promise((resolve, reject) => {
512
564
  let batch = pendingMediaByConversation.get(key);
513
565
  if (!batch) {
514
- batch = { items: [] };
566
+ batch = { items: [], firstReceivedAt: item.receivedAt };
515
567
  pendingMediaByConversation.set(key, batch);
516
568
  }
517
569
  batch.items.push({ ...item, resolve, reject });
@@ -2,7 +2,7 @@
2
2
  "id": "twilio-whatsapp",
3
3
  "name": "Twilio WhatsApp",
4
4
  "description": "WhatsApp channel via Twilio Business API (ISV/WABA)",
5
- "version": "1.1.26",
5
+ "version": "1.1.27",
6
6
  "channels": ["twilio-whatsapp"],
7
7
  "channelConfigs": {
8
8
  "twilio-whatsapp": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daolmedo/openclaw-twilio-whatsapp",
3
- "version": "1.1.26",
3
+ "version": "1.1.28",
4
4
  "description": "Twilio WhatsApp channel plugin for OpenClaw (Cody ISV)",
5
5
  "type": "module",
6
6
  "engines": {