Skip to content

feat(dm): delete message for everyone via NIP-09 kind 5 events#2394

Merged
NotThatKindOfDrLiz merged 2 commits intomainfrom
feat/dm-delete-for-everyone
Mar 24, 2026
Merged

feat(dm): delete message for everyone via NIP-09 kind 5 events#2394
NotThatKindOfDrLiz merged 2 commits intomainfrom
feat/dm-delete-for-everyone

Conversation

@realmeylisdev
Copy link
Copy Markdown
Contributor

@realmeylisdev realmeylisdev commented Mar 22, 2026

Depends on #2389 — must be merged after that PR closes.

Closes #2388

Summary

  • Delete for everyone — sender long-presses a sent message → "Delete for everyone" → publishes NIP-09 kind 5 event → message disappears for both parties
  • Soft-delete with dedup preservation — sets is_deleted = true instead of removing the row, so gift_wrap_id dedup continues to reject relay re-delivery
  • Kind 5 receive processing — subscription and poll filters now include kind 5; incoming deletions are validated (NIP-09 sender match) before applying
  • Conversation preview refresh — after deletion, the conversation list falls back to the next most recent non-deleted message
  • Long-press actions sheet — Copy (all), Delete for everyone (sent), Report (received)

Layers changed

Layer Files What
Data tables.dart, app_database.dart, direct_messages_dao.dart is_deleted column, migration, markMessageDeleted, getMessageById, filtered queries
Repository dm_repository.dart deleteMessageForEveryone, _handleDeletionEvent, _refreshConversationPreview, updated filters
BLoC conversation_bloc.dart, conversation_event.dart ConversationMessageDeleted event with droppable() transformer
Presentation message_actions_sheet.dart, message_bubble.dart, conversation_view.dart Long-press sheet, onLongPress prop, wiring

Protocol notes

  • Kind 5 references the rumor event ID (kind 14), not the gift wrap (kind 1059)
  • Kind 5 includes p tags for conversation participants so relay #p filters deliver it to the other party
  • Relay deletion is NOT relied upon — this is a client-side signal per the issue requirements
  • NIP-09 sender validation: kind 5 author must match the original message sender

Test plan

  • 31 conversation bloc tests passing (2 new for delete)
  • 70 DM repository tests passing (4 new for delete)
  • 26 DAO tests passing
  • Manual: long-press sent message → "Delete for everyone" → message disappears
  • Manual: other party sees message disappear after kind 5 arrives
  • Manual: long-press received message → no "Delete" option shown
  • Manual: conversation list preview updates after last message deleted

Implement "Delete for everyone" in DM conversations using NIP-09 kind 5
deletion events. Both sender and receiver process the kind 5 client-side
— relay deletion is not relied upon.

Data layer:
- Add `is_deleted` boolean column to `direct_messages` table
- Soft-delete preserves `gift_wrap_id` for dedup on relay re-delivery
- `watchMessages` / `getMessages` exclude deleted rows
- Add `markMessageDeleted` and `getMessageById` to DAO
- Add column migration in `_createMissingTables`

Repository layer:
- `deleteMessageForEveryone`: validates sender, publishes kind 5 with
  `p` tags for relay delivery, soft-deletes locally, refreshes
  conversation preview
- `_handleDeletionEvent`: processes incoming kind 5 events with NIP-09
  sender validation before applying soft-delete
- Subscription and poll filters now include `EventKind.eventDeletion`

BLoC layer:
- Add `ConversationMessageDeleted` event with `droppable()` transformer
- Handler delegates to repository; UI updates via reactive stream

Presentation layer:
- Add `MessageActionsSheet` with Copy, Delete (sent), Report (received)
- Add `onLongPress` callback to `MessageBubble`
- Wire long-press handler in conversation view

Closes #2388
@github-actions
Copy link
Copy Markdown

Mobile PR Preview

Property Value
Preview URL https://022be26e.openvine-app.pages.dev
Pages project openvine-app
Preview branch pr-2394
PR branch feat/dm-delete-for-everyone
Commit f525531

@NotThatKindOfDrLiz
Copy link
Copy Markdown
Member

It looks like #2389 has been merged. @realmeylisdev: Is this ready to go? If so, can you please rebase and mark it as ready for review so that @untreu2 and @omartinma can take a look? Thanks!

…eryone

# Conflicts:
#	mobile/lib/screens/inbox/conversation/conversation_view.dart
#	mobile/lib/screens/inbox/conversation/widgets/message_bubble.dart
@realmeylisdev realmeylisdev marked this pull request as ready for review March 23, 2026 18:47
@NotThatKindOfDrLiz NotThatKindOfDrLiz merged commit 94d6809 into main Mar 24, 2026
7 of 9 checks passed
@NotThatKindOfDrLiz NotThatKindOfDrLiz deleted the feat/dm-delete-for-everyone branch March 24, 2026 01:09
hm21 pushed a commit that referenced this pull request Mar 24, 2026
Implement "Delete for everyone" in DM conversations using NIP-09 kind 5
deletion events. Both sender and receiver process the kind 5 client-side
— relay deletion is not relied upon.

Data layer:
- Add `is_deleted` boolean column to `direct_messages` table
- Soft-delete preserves `gift_wrap_id` for dedup on relay re-delivery
- `watchMessages` / `getMessages` exclude deleted rows
- Add `markMessageDeleted` and `getMessageById` to DAO
- Add column migration in `_createMissingTables`

Repository layer:
- `deleteMessageForEveryone`: validates sender, publishes kind 5 with
  `p` tags for relay delivery, soft-deletes locally, refreshes
  conversation preview
- `_handleDeletionEvent`: processes incoming kind 5 events with NIP-09
  sender validation before applying soft-delete
- Subscription and poll filters now include `EventKind.eventDeletion`

BLoC layer:
- Add `ConversationMessageDeleted` event with `droppable()` transformer
- Handler delegates to repository; UI updates via reactive stream

Presentation layer:
- Add `MessageActionsSheet` with Copy, Delete (sent), Report (received)
- Add `onLongPress` callback to `MessageBubble`
- Wire long-press handler in conversation view

Closes #2388
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(dm): Delete message for everyone via NIP-09 kind 5 events

3 participants