CognxSafeTrack commited on
Commit
c4487e4
Β·
1 Parent(s): fed10ef

fix: restore missing loops and fix syntax in whatsapp route

Browse files
Files changed (1) hide show
  1. apps/api/src/routes/whatsapp.ts +66 -48
apps/api/src/routes/whatsapp.ts CHANGED
@@ -101,6 +101,7 @@ export async function whatsappRoutes(fastify: FastifyInstance) {
101
  // ── POST /webhook β€” Incoming Meta events ────────────────────────────────
102
  fastify.post('/webhook', async (request, reply) => {
103
  // ── 1. HMAC Signature Verification ──────────────────────────────────
 
104
  const appSecret = process.env.WHATSAPP_APP_SECRET;
105
 
106
  if (appSecret) {
@@ -173,9 +174,10 @@ export async function whatsappRoutes(fastify: FastifyInstance) {
173
  }
174
 
175
  // ── 4. Background Processing (enqueue to Worker) ──
 
176
  setImmediate(async () => {
177
  try {
178
- const parsed = WebhookPayloadSchema.safeParse(body); // Use 'body' here
179
  if (!parsed.success) {
180
  fastify.log.warn(`[WEBHOOK] Failed to parse webhook payload: ${parsed.error.message}`);
181
  return;
@@ -184,54 +186,70 @@ export async function whatsappRoutes(fastify: FastifyInstance) {
184
  const { scheduleInboundMessage } = await import('../services/queue');
185
  const payload = parsed.data;
186
 
187
- } else if (message.interactive.type === 'list_reply' && message.interactive.list_reply) {
188
- text = message.interactive.list_reply.id;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  }
190
- if (text) await scheduleInboundMessage({ phone, text, messageId });
191
-
192
- } else if (message.type === 'audio' && message.audio) {
193
- // Existing audio logic (queues download-media)
194
- const accessToken = process.env.WHATSAPP_ACCESS_TOKEN || undefined;
195
- const { Queue } = await import('bullmq');
196
- const Redis = (await import('ioredis')).default;
197
- const conn = process.env.REDIS_URL
198
- ? new Redis(process.env.REDIS_URL, { maxRetriesPerRequest: null })
199
- : new Redis({ host: process.env.REDIS_HOST || 'localhost', port: parseInt(process.env.REDIS_PORT || '6379'), maxRetriesPerRequest: null });
200
- const q = new Queue('whatsapp-queue', { connection: conn as any });
201
-
202
- await q.add('download-media', {
203
- mediaId: message.audio.id,
204
- mimeType: message.audio.mime_type || 'audio/ogg',
205
- phone,
206
- ...(accessToken ? { accessToken } : {})
207
- }, { priority: 1, attempts: 3, backoff: { type: 'exponential', delay: 2000 } });
208
-
209
- await q.add('send-message-direct', {
210
- phone,
211
- text: "⏳ J'analyse ton audio..."
212
- });
213
- } else if (message.type === 'image' && message.image) {
214
- console.log(`[IMAGE-FLOW] Image detected! ID: ${message.image.id}`);
215
- const accessToken = process.env.WHATSAPP_ACCESS_TOKEN || undefined;
216
- const { Queue } = await import('bullmq');
217
- const Redis = (await import('ioredis')).default;
218
- const conn = process.env.REDIS_URL
219
- ? new Redis(process.env.REDIS_URL, { maxRetriesPerRequest: null })
220
- : new Redis({ host: process.env.REDIS_HOST || 'localhost', port: parseInt(process.env.REDIS_PORT || '6379'), maxRetriesPerRequest: null });
221
- const q = new Queue('whatsapp-queue', { connection: conn as any });
222
-
223
- console.log(`[IMAGE-FLOW] Enqueuing for download...`);
224
- await q.add('download-media', {
225
- mediaId: message.image.id,
226
- mimeType: 'image/jpeg',
227
- phone,
228
- ...(accessToken ? { accessToken } : {})
229
- }, { priority: 1, attempts: 3, backoff: { type: 'exponential', delay: 2000 } });
230
-
231
- await q.add('send-message-direct', {
232
- phone,
233
- text: "⏳ J'analyse ton image..."
234
- });
235
  }
236
  }
237
  }
 
101
  // ── POST /webhook β€” Incoming Meta events ────────────────────────────────
102
  fastify.post('/webhook', async (request, reply) => {
103
  // ── 1. HMAC Signature Verification ──────────────────────────────────
104
+ console.log("[RAW-WHATSAPP-PAYLOAD]", JSON.stringify(request.body, null, 2));
105
  const appSecret = process.env.WHATSAPP_APP_SECRET;
106
 
107
  if (appSecret) {
 
174
  }
175
 
176
  // ── 4. Background Processing (enqueue to Worker) ──
177
+ const body = request.body;
178
  setImmediate(async () => {
179
  try {
180
+ const parsed = WebhookPayloadSchema.safeParse(body);
181
  if (!parsed.success) {
182
  fastify.log.warn(`[WEBHOOK] Failed to parse webhook payload: ${parsed.error.message}`);
183
  return;
 
186
  const { scheduleInboundMessage } = await import('../services/queue');
187
  const payload = parsed.data;
188
 
189
+ for (const entry of payload.entry || []) {
190
+ for (const change of entry.changes || []) {
191
+ if (change.value?.messages) {
192
+ for (const message of change.value.messages) {
193
+ const phone = message.from;
194
+ const messageId = message.id;
195
+ console.log("[WEBHOOK-TRACE] Processing message for phone:", phone);
196
+
197
+ let text: string | undefined;
198
+ if (message.type === 'text' && message.text) {
199
+ text = message.text.body;
200
+ } else if (message.type === 'interactive' && message.interactive) {
201
+ if (message.interactive.type === 'button_reply' && message.interactive.button_reply) {
202
+ text = message.interactive.button_reply.id;
203
+ } else if (message.interactive.type === 'list_reply' && message.interactive.list_reply) {
204
+ text = message.interactive.list_reply.id;
205
+ }
206
+ }
207
+
208
+ if (text) {
209
+ await scheduleInboundMessage({ phone, text, messageId });
210
+ } else if (message.type === 'audio' && message.audio) {
211
+ const accessToken = process.env.WHATSAPP_ACCESS_TOKEN || undefined;
212
+ const { Queue } = await import('bullmq');
213
+ const Redis = (await import('ioredis')).default;
214
+ const conn = process.env.REDIS_URL
215
+ ? new Redis(process.env.REDIS_URL, { maxRetriesPerRequest: null })
216
+ : new Redis({ host: process.env.REDIS_HOST || 'localhost', port: parseInt(process.env.REDIS_PORT || '6379'), maxRetriesPerRequest: null });
217
+ const q = new Queue('whatsapp-queue', { connection: conn as any });
218
+
219
+ await q.add('download-media', {
220
+ mediaId: message.audio.id,
221
+ mimeType: message.audio.mime_type || 'audio/ogg',
222
+ phone,
223
+ ...(accessToken ? { accessToken } : {})
224
+ }, { priority: 1, attempts: 3, backoff: { type: 'exponential', delay: 2000 } });
225
+
226
+ await q.add('send-message-direct', {
227
+ phone,
228
+ text: "⏳ J'analyse ton audio..."
229
+ });
230
+ } else if (message.type === 'image' && message.image) {
231
+ console.log(`[IMAGE-FLOW] Image detected! ID: ${message.image.id}`);
232
+ const accessToken = process.env.WHATSAPP_ACCESS_TOKEN || undefined;
233
+ const { Queue } = await import('bullmq');
234
+ const Redis = (await import('ioredis')).default;
235
+ const conn = process.env.REDIS_URL
236
+ ? new Redis(process.env.REDIS_URL, { maxRetriesPerRequest: null })
237
+ : new Redis({ host: process.env.REDIS_HOST || 'localhost', port: parseInt(process.env.REDIS_PORT || '6379'), maxRetriesPerRequest: null });
238
+ const q = new Queue('whatsapp-queue', { connection: conn as any });
239
+
240
+ console.log(`[IMAGE-FLOW] Enqueuing for download...`);
241
+ await q.add('download-media', {
242
+ mediaId: message.image.id,
243
+ mimeType: 'image/jpeg',
244
+ phone,
245
+ ...(accessToken ? { accessToken } : {})
246
+ }, { priority: 1, attempts: 3, backoff: { type: 'exponential', delay: 2000 } });
247
+
248
+ await q.add('send-message-direct', {
249
+ phone,
250
+ text: "⏳ J'analyse ton image..."
251
+ });
252
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  }
254
  }
255
  }