@wahooks/channel 0.6.1 → 0.7.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 +68 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -22,6 +22,39 @@ import WebSocket from "ws";
22
22
  import fs from "node:fs";
23
23
  import path from "node:path";
24
24
  import os from "node:os";
25
+ // Minimal mime type detection from extension
26
+ const MIME_MAP = {
27
+ ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png",
28
+ ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml",
29
+ ".pdf": "application/pdf", ".doc": "application/msword",
30
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
31
+ ".xls": "application/vnd.ms-excel",
32
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
33
+ ".mp4": "video/mp4", ".webm": "video/webm", ".mov": "video/quicktime",
34
+ ".mp3": "audio/mpeg", ".ogg": "audio/ogg", ".wav": "audio/wav",
35
+ ".m4a": "audio/mp4", ".opus": "audio/opus",
36
+ ".zip": "application/zip", ".txt": "text/plain", ".csv": "text/csv",
37
+ ".json": "application/json",
38
+ };
39
+ function getMimeType(filePath) {
40
+ const ext = path.extname(filePath).toLowerCase();
41
+ return MIME_MAP[ext] ?? "application/octet-stream";
42
+ }
43
+ /** Resolve file_path/data/url into API-ready body fields */
44
+ function resolveMedia(args) {
45
+ if (args.file_path) {
46
+ const fileData = fs.readFileSync(args.file_path);
47
+ return {
48
+ data: fileData.toString("base64"),
49
+ mimetype: args.mimetype ?? getMimeType(args.file_path),
50
+ filename: args.filename ?? path.basename(args.file_path),
51
+ };
52
+ }
53
+ if (args.data) {
54
+ return { data: args.data, mimetype: args.mimetype };
55
+ }
56
+ return { url: args.url };
57
+ }
25
58
  // ─── Config ─────────────────────────────────────────────────────────────
26
59
  const CONFIG_DIR = path.join(os.homedir(), ".claude", "channels", "wahooks");
27
60
  const ENV_FILE = path.join(CONFIG_DIR, ".env");
@@ -175,53 +208,66 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
175
208
  },
176
209
  {
177
210
  name: "wahooks_send_image",
178
- description: "Send an image via WhatsApp.",
211
+ description: "Send an image via WhatsApp. Provide url, file_path (local file), or data (base64).",
179
212
  inputSchema: {
180
213
  type: "object",
181
214
  properties: {
182
- to: { type: "string", description: "Phone number" },
215
+ to: { type: "string", description: "Recipient (phone number or chat ID from channel event)" },
183
216
  url: { type: "string", description: "Image URL" },
217
+ file_path: { type: "string", description: "Local file path" },
218
+ data: { type: "string", description: "Base64-encoded image data" },
219
+ mimetype: { type: "string", description: "MIME type (auto-detected from file_path)" },
184
220
  caption: { type: "string", description: "Optional caption" },
185
221
  },
186
- required: ["to", "url"],
222
+ required: ["to"],
187
223
  },
188
224
  },
189
225
  {
190
226
  name: "wahooks_send_document",
191
- description: "Send a document/file via WhatsApp.",
227
+ description: "Send a document/file via WhatsApp. Provide url, file_path (local file), or data (base64).",
192
228
  inputSchema: {
193
229
  type: "object",
194
230
  properties: {
195
- to: { type: "string", description: "Phone number" },
231
+ to: { type: "string", description: "Recipient" },
196
232
  url: { type: "string", description: "Document URL" },
197
- filename: { type: "string", description: "Filename" },
233
+ file_path: { type: "string", description: "Local file path" },
234
+ data: { type: "string", description: "Base64-encoded file data" },
235
+ mimetype: { type: "string", description: "MIME type" },
236
+ filename: { type: "string", description: "Filename (auto-detected from file_path)" },
237
+ caption: { type: "string", description: "Optional caption" },
198
238
  },
199
- required: ["to", "url"],
239
+ required: ["to"],
200
240
  },
201
241
  },
202
242
  {
203
243
  name: "wahooks_send_video",
204
- description: "Send a video via WhatsApp.",
244
+ description: "Send a video via WhatsApp. Provide url, file_path (local file), or data (base64).",
205
245
  inputSchema: {
206
246
  type: "object",
207
247
  properties: {
208
- to: { type: "string", description: "Phone number" },
248
+ to: { type: "string", description: "Recipient" },
209
249
  url: { type: "string", description: "Video URL" },
250
+ file_path: { type: "string", description: "Local file path" },
251
+ data: { type: "string", description: "Base64-encoded video data" },
252
+ mimetype: { type: "string", description: "MIME type" },
210
253
  caption: { type: "string", description: "Optional caption" },
211
254
  },
212
- required: ["to", "url"],
255
+ required: ["to"],
213
256
  },
214
257
  },
215
258
  {
216
259
  name: "wahooks_send_audio",
217
- description: "Send an audio/voice message via WhatsApp.",
260
+ description: "Send an audio/voice message via WhatsApp. Provide url, file_path (local file), or data (base64).",
218
261
  inputSchema: {
219
262
  type: "object",
220
263
  properties: {
221
- to: { type: "string", description: "Phone number" },
264
+ to: { type: "string", description: "Recipient" },
222
265
  url: { type: "string", description: "Audio URL" },
266
+ file_path: { type: "string", description: "Local file path" },
267
+ data: { type: "string", description: "Base64-encoded audio data" },
268
+ mimetype: { type: "string", description: "MIME type" },
223
269
  },
224
- required: ["to", "url"],
270
+ required: ["to"],
225
271
  },
226
272
  },
227
273
  {
@@ -276,33 +322,37 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
276
322
  return { content: [{ type: "text", text: `Sent to ${args.to}` }] };
277
323
  }
278
324
  case "wahooks_send_image": {
325
+ const media = resolveMedia(args);
279
326
  await api("POST", `/connections/${connectionId}/send-image`, {
280
327
  chatId: toChatId(args.to),
281
- url: args.url,
328
+ ...media,
282
329
  caption: args.caption,
283
330
  });
284
331
  return { content: [{ type: "text", text: `Image sent to ${args.to}` }] };
285
332
  }
286
333
  case "wahooks_send_document": {
334
+ const media = resolveMedia(args);
287
335
  await api("POST", `/connections/${connectionId}/send-document`, {
288
336
  chatId: toChatId(args.to),
289
- url: args.url,
290
- filename: args.filename,
337
+ ...media,
338
+ caption: args.caption,
291
339
  });
292
340
  return { content: [{ type: "text", text: `Document sent to ${args.to}` }] };
293
341
  }
294
342
  case "wahooks_send_video": {
343
+ const media = resolveMedia(args);
295
344
  await api("POST", `/connections/${connectionId}/send-video`, {
296
345
  chatId: toChatId(args.to),
297
- url: args.url,
346
+ ...media,
298
347
  caption: args.caption,
299
348
  });
300
349
  return { content: [{ type: "text", text: `Video sent to ${args.to}` }] };
301
350
  }
302
351
  case "wahooks_send_audio": {
352
+ const media = resolveMedia(args);
303
353
  await api("POST", `/connections/${connectionId}/send-audio`, {
304
354
  chatId: toChatId(args.to),
305
- url: args.url,
355
+ ...media,
306
356
  });
307
357
  return { content: [{ type: "text", text: `Audio sent to ${args.to}` }] };
308
358
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wahooks/channel",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "WhatsApp channel for Claude Code — chat with Claude via WhatsApp",
5
5
  "type": "module",
6
6
  "bin": {