From d279b33fe13f482047633c3bb226e64171975f54 Mon Sep 17 00:00:00 2001 From: Alper Samur <85391235+alpersamur3@users.noreply.github.com> Date: Thu, 6 Aug 2026 14:43:37 +0300 Subject: [PATCH] feat: expose call outcome on call_log messages --- example.js | 8 ++++++ index.d.ts | 6 +++++ src/structures/Message.js | 20 ++++++++++++++ tests/callLog.js | 56 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 tests/callLog.js diff --git a/example.js b/example.js index 7b2af48bff9..f8d14fe7d8a 100644 --- a/example.js +++ b/example.js @@ -67,6 +67,14 @@ client.on('ready', async () => { client.on('message', async (msg) => { console.log('MESSAGE RECEIVED', msg); + if (msg.type === 'call_log') { + // Call log messages carry the outcome of a call, e.g. 'AcceptedElsewhere' + // when the call was answered on one of your other linked devices + console.log( + `Call from ${msg.from} ended with outcome: ${msg.callOutcome}`, + ); + } + if (msg.body === '!ping reply') { // Send a new message as a reply to the current one msg.reply('pong'); diff --git a/index.d.ts b/index.d.ts index b155be8391d..637f3ad381c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1193,6 +1193,12 @@ declare namespace WAWebJS { isGif: boolean; /** Indicates if the message will disappear after it expires */ isEphemeral: boolean; + /** Outcome of the call, for `call_log` messages (e.g. 'Completed', 'Missed', 'Rejected', 'AcceptedElsewhere') */ + callOutcome?: string; + /** Duration of the call in seconds, for `call_log` messages */ + callDuration?: number; + /** Indicates if the call was a video call, for `call_log` messages */ + isVideoCall?: boolean; /** ID for the Chat that this message was sent to, except if the message was sent by the current user */ from: string; /** Indicates if the message was sent by the current user */ diff --git a/src/structures/Message.js b/src/structures/Message.js index ed7991352d7..5d4935f1272 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -344,6 +344,26 @@ class Message extends Base { : []; } + if (this.type === MessageTypes.CALL_LOG) { + /** + * Outcome of the call, for `call_log` messages. Common values are + * 'Completed', 'Missed', 'Rejected', 'Cancelled', 'Failed' and + * 'AcceptedElsewhere' (the call was answered on another device) + * @type {string} + */ + this.callOutcome = data.callOutcome; + /** + * Duration of the call in seconds, for `call_log` messages + * @type {number} + */ + this.callDuration = data.callDuration; + /** + * Indicates if the call was a video call, for `call_log` messages + * @type {boolean} + */ + this.isVideoCall = Boolean(data.isVideoCall); + } + return super._patch(data); } diff --git a/tests/callLog.js b/tests/callLog.js new file mode 100644 index 00000000000..7309fb821a9 --- /dev/null +++ b/tests/callLog.js @@ -0,0 +1,56 @@ +const chai = require('chai'); +const Message = require('../src/structures/Message'); + +const expect = chai.expect; + +// Unit test: constructs a Message from a call_log payload and checks that the +// call metadata is exposed. No live session needed. +describe('Message call_log', function () { + const client = {}; + + function build(overrides) { + return new Message(client, { + id: { + id: 'ABCDEF0123456789', + _serialized: 'false_123@c.us_ABCDEF0123456789', + fromMe: false, + remote: '123@c.us', + }, + type: 'call_log', + t: 1700000000, + from: '123@c.us', + to: '456@c.us', + ...overrides, + }); + } + + it('exposes the call outcome, duration and video flag', function () { + const msg = build({ + callOutcome: 'AcceptedElsewhere', + callDuration: 0, + isVideoCall: false, + }); + expect(msg.type).to.equal('call_log'); + expect(msg.callOutcome).to.equal('AcceptedElsewhere'); + expect(msg.callDuration).to.equal(0); + expect(msg.isVideoCall).to.equal(false); + }); + + it('reports a completed video call', function () { + const msg = build({ + callOutcome: 'Completed', + callDuration: 42, + isVideoCall: true, + }); + expect(msg.callOutcome).to.equal('Completed'); + expect(msg.callDuration).to.equal(42); + expect(msg.isVideoCall).to.equal(true); + }); + + it('does not set call fields on non call_log messages', function () { + const msg = build({ type: 'chat', body: 'hi' }); + expect(msg.callOutcome).to.equal(undefined); + expect(msg.callDuration).to.equal(undefined); + expect(msg.isVideoCall).to.equal(undefined); + }); +});