@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.
- package/dist/index.js +49 -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];
|