mirror of
https://github.com/block/buzz.git
synced 2026-10-27 20:41:57 +00:00
## Summary Hiding a DM row and then receiving a new message from that person never brought the row back — the reader was left with only an Inbox notification. This restores the row from live activity, client-side, with no relay or database changes. - Subscribe to hidden-DM activity **channel-scoped** over the hidden-DM id set (`#h`), re-registering whenever the set changes. The relay's `fan_out_scoped` only routes channel-scoped events (every kind:9 DM carries a `channel_id`) to channel-scoped subscriptions, so a community-global `#p` filter receives nothing. Hiding a DM never drops membership, so `#h` authorization holds. Because every delivered event is already for a hidden DM the reader belongs to, eligibility no longer needs a self `p` tag — untagged CLI/agent DMs resurface too — and no per-event visibility fetch is required. - On qualifying activity, invoke the existing open-DM action (`41010`) to reopen the hidden one-to-one or group DM, validating that the relay reopened the same channel. - Preserve the existing relay-synced hide snapshot (`41012` → `30622`); hide state still syncs across devices. - Let Inbox reopen a hidden DM before navigating to its message, with a busy state on the row and context-menu "Open in channel" action while a reopen is pending. - Coalesce resurface attempts per channel: a concurrent message that arrives while a reopen is in flight triggers a retry on failure instead of being marked handled and dropped. - Write exact dm-visibility query keys on open/hide mutations. This is the client-only replacement agreed in the Buzz design thread and supersedes #6713. The accepted limitation is that resurface only fires while a client is running — a message that arrives while all clients are closed does not restore the row on next launch (the `30622` snapshot has no watermark); Inbox click-through is the safety net for that case. Addresses #6316. --------- Signed-off-by: kenny lopez <klopez4212@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz>
62 lines
1.7 KiB
Dart
62 lines
1.7 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:buzz/features/activity/dm_resurface.dart';
|
|
import 'package:buzz/shared/relay/relay.dart';
|
|
|
|
void main() {
|
|
const self =
|
|
'1111111111111111111111111111111111111111111111111111111111111111';
|
|
const alice =
|
|
'2222222222222222222222222222222222222222222222222222222222222222';
|
|
const bob =
|
|
'3333333333333333333333333333333333333333333333333333333333333333';
|
|
|
|
test('derives group DM peers from authoritative membership', () {
|
|
expect(dmPeerPubkeysFromMembers([self, alice, bob], self), {alice, bob});
|
|
expect(dmPeerPubkeysFromMembers([alice, bob], self), isEmpty);
|
|
});
|
|
|
|
test('accepts external channel messages regardless of p tags', () {
|
|
NostrEvent event({
|
|
int kind = EventKind.streamMessage,
|
|
String? author,
|
|
List<List<String>>? tags,
|
|
}) => NostrEvent(
|
|
id: 'event-1',
|
|
pubkey: author ?? alice,
|
|
createdAt: 1,
|
|
kind: kind,
|
|
tags:
|
|
tags ??
|
|
const [
|
|
['h', 'dm-1'],
|
|
['p', self],
|
|
],
|
|
content: 'hello',
|
|
sig: 'sig',
|
|
);
|
|
|
|
expect(isIncomingChannelMessageFromOther(event(), self), isTrue);
|
|
expect(
|
|
isIncomingChannelMessageFromOther(event(kind: EventKind.reaction), self),
|
|
isFalse,
|
|
);
|
|
expect(
|
|
isIncomingChannelMessageFromOther(event(author: self), self),
|
|
isFalse,
|
|
);
|
|
// #h-scoped delivery already guarantees relevance: an untagged DM from
|
|
// another sender still qualifies.
|
|
expect(
|
|
isIncomingChannelMessageFromOther(
|
|
event(
|
|
tags: const [
|
|
['h', 'dm-1'],
|
|
],
|
|
),
|
|
self,
|
|
),
|
|
isTrue,
|
|
);
|
|
});
|
|
}
|