bloby-bot 0.23.3 → 0.23.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bloby-bot",
3
- "version": "0.23.3",
3
+ "version": "0.23.4",
4
4
  "releaseNotes": [
5
5
  "1. new stuff",
6
6
  "2. ",
@@ -138,11 +138,54 @@ export class ChannelManager {
138
138
  this.providers.clear();
139
139
  }
140
140
 
141
- /** Send a message via a specific channel */
141
+ /** Send a message via a specific channel, processing any custom UI tags */
142
142
  async sendMessage(channel: ChannelType, to: string, text: string): Promise<void> {
143
143
  const provider = this.providers.get(channel);
144
144
  if (!provider) throw new Error(`Channel ${channel} not available`);
145
- await provider.sendMessage(to, text);
145
+
146
+ // Process custom tags for channel delivery
147
+ let processed = text;
148
+
149
+ // <BlobyImage> — send the image natively, remove tag from text
150
+ const imgRegex = /<BlobyImage\s+src="([^"]+)"(?:\s+alt="([^"]*)")?\s*\/>/g;
151
+ const images: { src: string; alt: string }[] = [];
152
+ let imgMatch;
153
+ while ((imgMatch = imgRegex.exec(text)) !== null) {
154
+ images.push({ src: imgMatch[1], alt: imgMatch[2] || '' });
155
+ }
156
+ processed = processed.replace(imgRegex, '').trim();
157
+
158
+ // <BlobyText> — flatten to plain title + content
159
+ processed = processed.replace(
160
+ /<BlobyText\s+title="([^"]+)">([\s\S]*?)<\/BlobyText>/g,
161
+ (_match, title, content) => `📄 *${title}*\n\n${content.trim()}`,
162
+ );
163
+
164
+ // Send text (if any remains after stripping tags)
165
+ if (processed) {
166
+ await provider.sendMessage(to, processed);
167
+ }
168
+
169
+ // Send images natively via WhatsApp
170
+ if (images.length > 0 && provider instanceof WhatsAppChannel) {
171
+ for (const img of images) {
172
+ try {
173
+ // Resolve the file path from the /api/files/ URL
174
+ const relPath = img.src.replace(/^\/api\/files\//, '');
175
+ const absPath = path.join(WORKSPACE_DIR, relPath);
176
+ if (fs.existsSync(absPath)) {
177
+ const buffer = fs.readFileSync(absPath);
178
+ const ext = path.extname(absPath).slice(1);
179
+ const mimeMap: Record<string, string> = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp' };
180
+ await provider.sendImage(to, buffer, img.alt || undefined, mimeMap[ext] || 'image/png');
181
+ } else {
182
+ log.warn(`[channels] Image file not found: ${absPath}`);
183
+ }
184
+ } catch (err: any) {
185
+ log.warn(`[channels] Failed to send image via WhatsApp: ${err.message}`);
186
+ }
187
+ }
188
+ }
146
189
  }
147
190
 
148
191
  /** Show "typing..." indicator in a chat */
@@ -114,6 +114,23 @@ export class WhatsAppChannel implements ChannelProvider {
114
114
  log.info(`[whatsapp] Sent message to ${jid} (id=${result?.key?.id || 'unknown'})`);
115
115
  }
116
116
 
117
+ /** Send an image via WhatsApp */
118
+ async sendImage(to: string, image: Buffer, caption?: string, mimetype?: string): Promise<void> {
119
+ if (!this.sock || !this.connected) {
120
+ log.warn('[whatsapp] Cannot send image — not connected');
121
+ return;
122
+ }
123
+ const jid = to.includes('@') ? to : `${to.replace(/[^0-9]/g, '')}@s.whatsapp.net`;
124
+ this.stopTyping(jid);
125
+
126
+ const msg: any = { image, mimetype: mimetype || 'image/png' };
127
+ if (caption) msg.caption = caption;
128
+
129
+ const result = await this.sock.sendMessage(jid, msg);
130
+ if (result?.key?.id) this.trackSentId(result.key.id);
131
+ log.info(`[whatsapp] Sent image to ${jid} (id=${result?.key?.id || 'unknown'})`);
132
+ }
133
+
117
134
  /** Show "typing..." indicator in a chat. Re-sends every 20s to keep it visible. */
118
135
  startTyping(jid: string): void {
119
136
  if (!this.sock || !this.connected) return;