diff --git a/src/Socket/messages-recv.ts b/src/Socket/messages-recv.ts
index 58848a05..9318a1b3 100644
--- a/src/Socket/messages-recv.ts
+++ b/src/Socket/messages-recv.ts
@@ -2258,17 +2258,6 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
return
}
- // Handle view-once unavailable sync from primary device.
- // When the primary device sends a view-once, linked companions receive
- // — no enc content, just a sync signal.
- // Acknowledge and skip decryption (nothing to decrypt).
- const unavailableNode = getBinaryNodeChild(node, 'unavailable')
- if (unavailableNode?.attrs?.type === 'view_once') {
- logger.debug({ id: node.attrs.id, from: node.attrs.from }, 'received view_once unavailable sync from primary device')
- await sendMessageAck(node)
- return
- }
-
const {
fullMessage: msg,
category,
diff --git a/src/Socket/messages-send.ts b/src/Socket/messages-send.ts
index d1ec3132..4724c059 100644
--- a/src/Socket/messages-send.ts
+++ b/src/Socket/messages-send.ts
@@ -1277,21 +1277,32 @@ export const makeMessagesSocket = (config: SocketConfig) => {
: otherRecipients
const effectiveAllRecipients = [...effectiveMeRecipients, ...effectiveOtherRecipients]
- await assertSessions(effectiveAllRecipients)
+ // P2: detect actual view-once media by checking inner message's viewOnce flag.
+ // viewOnceMessage wrapper is also used for interactive messages (buttons, lists, etc)
+ // which do NOT carry viewOnce=true on the media — those must NOT be filtered.
+ const viewOnceInner =
+ message.viewOnceMessageV2?.message ||
+ message.viewOnceMessage?.message ||
+ message.viewOnceMessageV2Extension?.message
+ const isViewOnceMsg = !!(
+ viewOnceInner?.imageMessage?.viewOnce ||
+ viewOnceInner?.videoMessage?.viewOnce ||
+ viewOnceInner?.audioMessage?.viewOnce
+ )
// For view-once: only send DSM to primary phone (device=0).
// Companion devices (device>0) are omitted — WA server generates
// for them automatically.
// Sending explicit from a companion is rejected by the server.
- const isViewOnceMsg = !!(
- message.viewOnceMessageV2 ||
- message.viewOnceMessage ||
- message.viewOnceMessageV2Extension
- )
const viewOnceMeRecipients = isViewOnceMsg
? effectiveMeRecipients.filter(jid => !jidDecode(jid)?.device)
: effectiveMeRecipients
+ // P3: assert sessions only for recipients we actually encrypt for.
+ // For view-once, companions are omitted — asserting their sessions is wasteful
+ // and could block the send if a companion session is corrupted.
+ await assertSessions([...viewOnceMeRecipients, ...effectiveOtherRecipients])
+
const [
{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
{ nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }