fix: reactions in browser mode (BrowserAdapter)
- Include mid on the wire in sendChat() so recipients can reference it - Handle incoming 'reaction' wire message in PeerConn._onControl - Add PeerConn.sendReaction() to send the reaction wire message - Handle 'send_reaction' IPC command in BrowserAdapter.send() - Emit 'reaction' IPC event on receive and on local send - Use wire mid (not synthetic peer-ts mid) when receiving chat messages Reactions now work across all combinations: daemon↔daemon, browser↔browser, and daemon↔browser. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -433,9 +433,17 @@ class PeerConn {
|
||||
nick: m['nick'] as string || '', caps: m['caps'] || []
|
||||
})
|
||||
} else if (m['type'] === 'chat') {
|
||||
const ts = (m['ts'] as number) || Date.now()
|
||||
this.on('chat', {
|
||||
peer: this.peerId, room: m['room'] as string || 'general',
|
||||
text: m['text'] as string, ts: m['ts'] as number || Date.now()
|
||||
text: m['text'] as string, ts,
|
||||
mid: (m['mid'] as string) || `${this.peerId}-${ts}`,
|
||||
})
|
||||
} else if (m['type'] === 'reaction') {
|
||||
this.on('reaction', {
|
||||
peer: this.peerId,
|
||||
mid: m['reaction_mid'] as string,
|
||||
emoji: m['reaction_emoji'] as string,
|
||||
})
|
||||
} else if (m['type'] === 'pm') {
|
||||
this.on('pm', { peer: this.peerId, text: m['text'] as string, ts: m['ts'] as number || Date.now() })
|
||||
@@ -556,14 +564,18 @@ class PeerConn {
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
|
||||
sendChat(room: string, text: string) {
|
||||
this._dc({ type: 'chat', room, text, ts: Date.now() })
|
||||
sendChat(room: string, text: string, mid: string) {
|
||||
this._dc({ type: 'chat', room, text, ts: Date.now(), mid })
|
||||
}
|
||||
|
||||
sendPm(text: string) {
|
||||
this._dc({ type: 'pm', text, ts: Date.now() })
|
||||
}
|
||||
|
||||
sendReaction(mid: string, emoji: string) {
|
||||
this._dc({ type: 'reaction', reaction_mid: mid, reaction_emoji: emoji })
|
||||
}
|
||||
|
||||
private _dc(obj: object) {
|
||||
if (this.dc?.readyState === 'open') this.dc.send(JSON.stringify(obj))
|
||||
}
|
||||
@@ -755,9 +767,17 @@ export class BrowserAdapter {
|
||||
public_key: data['peer'] as string, created_at: new Date().toISOString()
|
||||
},
|
||||
})
|
||||
} else if (event === 'reaction') {
|
||||
this.emit({
|
||||
type: 'reaction',
|
||||
network_id: this.networkId,
|
||||
peer_id: data['peer'] as unknown as import('../types').PeerID,
|
||||
reaction_mid: data['mid'] as string,
|
||||
reaction_emoji: data['emoji'] as string,
|
||||
})
|
||||
} else if (event === 'chat') {
|
||||
const ts = (data['ts'] as number) || Date.now()
|
||||
const mid = `${data['peer']}-${ts}`
|
||||
const mid = (data['mid'] as string) || `${data['peer']}-${ts}`
|
||||
this.emit({
|
||||
type: 'message_received',
|
||||
network_id: this.networkId,
|
||||
@@ -910,8 +930,8 @@ export class BrowserAdapter {
|
||||
},
|
||||
})
|
||||
} else {
|
||||
// Broadcast
|
||||
this.peers.forEach(p => p.sendChat(room, text))
|
||||
// Broadcast — include mid on the wire so recipients can reference it in reactions
|
||||
this.peers.forEach(p => p.sendChat(room, text, mid))
|
||||
this.emit({
|
||||
type: 'message_received',
|
||||
network_id: this.networkId,
|
||||
@@ -924,6 +944,22 @@ export class BrowserAdapter {
|
||||
return
|
||||
}
|
||||
|
||||
if (msg.type === 'send_reaction') {
|
||||
const mid = msg.reaction_mid
|
||||
const emoji = msg.reaction_emoji
|
||||
if (!mid || !emoji) return
|
||||
this.peers.forEach(p => p.sendReaction(mid, emoji))
|
||||
// Emit locally so the sender sees their own reaction immediately
|
||||
this.emit({
|
||||
type: 'reaction',
|
||||
network_id: this.networkId,
|
||||
peer_id: this.identity.id as unknown as import('../types').PeerID,
|
||||
reaction_mid: mid,
|
||||
reaction_emoji: emoji,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (msg.type === 'export_identity') {
|
||||
if (!msg.passphrase) return
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user