@daolmedo/openclaw-twilio-whatsapp 1.0.0 → 1.1.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/dist/index.js +49 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -176,6 +176,10 @@ var twilioWhatsappPlugin = {
176
176
 
177
177
  // src/http-routes.ts
178
178
  import { dispatchInboundDirectDmWithRuntime } from "openclaw/plugin-sdk/direct-dm.js";
179
+ import {
180
+ fetchRemoteMedia,
181
+ saveMediaBuffer
182
+ } from "openclaw/plugin-sdk/media-runtime.js";
179
183
 
180
184
  // src/webhook.ts
181
185
  import twilio2 from "twilio";
@@ -207,6 +211,7 @@ function parseTwilioWebhook(rawBody) {
207
211
  }
208
212
 
209
213
  // src/http-routes.ts
214
+ var MEDIA_MAX_BYTES = 16 * 1024 * 1024;
210
215
  async function readBody(req) {
211
216
  return new Promise((resolve, reject) => {
212
217
  const chunks = [];
@@ -225,6 +230,31 @@ function twimlError(res, status, message) {
225
230
  `<?xml version="1.0" encoding="UTF-8"?><Response><Message>${message}</Message></Response>`
226
231
  );
227
232
  }
233
+ async function downloadTwilioMedia(url, account) {
234
+ try {
235
+ const authHeader = "Basic " + Buffer.from(`${account.accountSid}:${account.authToken}`).toString("base64");
236
+ const { buffer, contentType } = await fetchRemoteMedia({
237
+ url,
238
+ fetchImpl: (input, init) => fetch(input, {
239
+ ...init,
240
+ headers: {
241
+ ...init?.headers,
242
+ Authorization: authHeader
243
+ }
244
+ }),
245
+ maxBytes: MEDIA_MAX_BYTES,
246
+ readIdleTimeoutMs: 3e4
247
+ });
248
+ const saved = await saveMediaBuffer(buffer, contentType, "inbound", MEDIA_MAX_BYTES);
249
+ return {
250
+ path: saved.path,
251
+ contentType: saved.contentType ?? contentType ?? "application/octet-stream"
252
+ };
253
+ } catch (err) {
254
+ console.error("[twilio-whatsapp] Failed to download media:", url, err);
255
+ return null;
256
+ }
257
+ }
228
258
  function registerTwilioWhatsappHttpRoutes(api) {
229
259
  api.registerHttpRoute({
230
260
  path: "/twilio/whatsapp/events",
@@ -273,8 +303,24 @@ function registerTwilioWhatsappHttpRoutes(api) {
273
303
  twimlOk(res);
274
304
  return true;
275
305
  }
276
- const bodyForAgent = hasMedia ? [messageText, ...fields.media.map((m) => `[Media: ${m.url}]`)].filter(Boolean).join("\n") : messageText;
277
306
  twimlOk(res);
307
+ const resolvedMedia = [];
308
+ if (hasMedia) {
309
+ const results = await Promise.all(
310
+ fields.media.map((m) => downloadTwilioMedia(m.url, account))
311
+ );
312
+ for (const r of results) {
313
+ if (r) resolvedMedia.push(r);
314
+ }
315
+ }
316
+ const mediaContext = resolvedMedia.length > 0 ? {
317
+ MediaPath: resolvedMedia[0].path,
318
+ MediaUrl: resolvedMedia[0].path,
319
+ MediaType: resolvedMedia[0].contentType,
320
+ MediaPaths: resolvedMedia.map((m) => m.path),
321
+ MediaUrls: resolvedMedia.map((m) => m.path),
322
+ MediaTypes: resolvedMedia.map((m) => m.contentType)
323
+ } : {};
278
324
  dispatchInboundDirectDmWithRuntime({
279
325
  cfg: stored.cfg,
280
326
  runtime: { channel: stored.channelRuntime },
@@ -287,10 +333,11 @@ function registerTwilioWhatsappHttpRoutes(api) {
287
333
  recipientAddress,
288
334
  conversationLabel,
289
335
  rawBody: messageText,
290
- bodyForAgent,
336
+ bodyForAgent: messageText || void 0,
291
337
  messageId: fields.messageSid,
292
338
  timestamp: Date.now(),
293
339
  commandAuthorized: true,
340
+ extraContext: mediaContext,
294
341
  deliver: async (payload) => {
295
342
  const text = payload.text ?? "";
296
343
  const mediaUrl = payload.mediaUrl ?? payload.mediaUrls?.[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daolmedo/openclaw-twilio-whatsapp",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Twilio WhatsApp channel plugin for OpenClaw (Cody ISV)",
5
5
  "type": "module",
6
6
  "exports": {