File size: 2,355 Bytes
46252cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { MessageStatus } from './entities/message.entity';
import { DeliveryStatus } from '../../engine/interfaces/whatsapp-engine.interface';

/**
 * Maps a neutral engine DeliveryStatus to the stored MessageStatus it implies, or null when the
 * status carries no upgrade beyond the stored `SENT` state. This is how the stored message reflects
 * *real* delivery state (#220): a send that never advances past `sent` stays `SENT`, visibly
 * "not delivered". Engine-specific ack codes are mapped to DeliveryStatus inside the adapter.
 */
export function deliveryStatusToMessageStatus(status: DeliveryStatus): MessageStatus | null {
  switch (status) {
    case 'failed':
      return MessageStatus.FAILED;
    case 'read':
      return MessageStatus.READ;
    case 'delivered':
      return MessageStatus.DELIVERED;
    default:
      return null; // pending / sent — already at/below SENT, no upgrade
  }
}

/**
 * @deprecated Legacy whatsapp-web.js-style ack integer, derived from the neutral DeliveryStatus
 * solely for backward compatibility of the `message.ack`/`message.failed` webhook payload's `ack`
 * field. New consumers should read the neutral `status` field instead. (-1 error, 0 pending,
 * 1 sent, 2 delivered, 3 read.)
 */
export function deliveryStatusToAck(status: DeliveryStatus): number {
  switch (status) {
    case 'failed':
      return -1;
    case 'read':
      return 3;
    case 'delivered':
      return 2;
    case 'sent':
      return 1;
    default:
      return 0; // pending
  }
}

/**
 * The stored statuses a delivery transition may advance FROM. Used as a conditional UPDATE guard so
 * delivery state only moves forward — preventing an out-of-order/late ack from downgrading a higher
 * status (e.g. a DELIVERED ack arriving after READ), even though the writes are fire-and-forget.
 * A late FAILED must not clobber a message already confirmed delivered/read, and vice versa.
 */
export function ackStatusTransitionFrom(target: MessageStatus): MessageStatus[] {
  switch (target) {
    case MessageStatus.DELIVERED:
      return [MessageStatus.PENDING, MessageStatus.SENT];
    case MessageStatus.READ:
      return [MessageStatus.PENDING, MessageStatus.SENT, MessageStatus.DELIVERED];
    case MessageStatus.FAILED:
      return [MessageStatus.PENDING, MessageStatus.SENT];
    default:
      return [];
  }
}