feat(nip71): auto-sync the mirror on edit/delete (event-driven, no nostrService growth)

Closes the dual-event drift the user flagged: an opted-in 34235 mirror now stays
in lockstep with the canonical 30078 automatically — no per-video babysitting.

- js/services/nip71MirrorSync.js: syncNip71MirrorAfterEdit (re-publish if still
  eligible; unshare + clear flag if it became ineligible, e.g. flipped private),
  syncNip71MirrorAfterDelete (remove + clear flag). Plus initNip71MirrorSync()
  which subscribes to nostrService's EXISTING videos:edited/videos:deleted events
  — so the size-capped nostrService is untouched.
- js/services/nip71MirrorFlags.js: pure resolveEditSync/resolveDeleteSync decisions.
- applicationBootstrap: one-line initNip71MirrorSync(app.nostrService) wiring.
- All best-effort: a mirror failure never breaks the core edit/delete.

tests: resolver decisions (lockstep/unshare/none) + delete clears the flag +
event wiring is idempotent. Mutation-verified (eligibility branch load-bearing).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-06-22 10:22:27 -04:00
1 parent dff1a27c0c
commit 89d9a62b87
5 files changed
+182

No files matched your search

+4
View File
@@ -17,6 +17,7 @@ import hashtagPreferences, {
import NwcSettingsService from "../services/nwcSettingsService.js";
import nostrService from "../services/nostrService.js";
import storageService from "../services/storageService.js";
import { initNip71MirrorSync } from "../services/nip71MirrorSync.js";
import watchHistoryService from "../watchHistoryService.js";
import r2Service from "../services/r2Service.js";
import s3UploadService from "../services/s3UploadService.js";
@@ -849,6 +850,9 @@ export default class ApplicationBootstrap {
app.videoSubscription = subscription || null;
}),
);
// Keep an opted-in NIP-71 mirror in lockstep on edit/delete (event-driven so
// nostrService stays untouched).
nostrUnsubscribes.push(initNip71MirrorSync(app.nostrService));
nostrUnsubscribes.push(
app.nostrService.on("directMessages:notification", () => {
void app.refreshUnreadDmIndicator({ reason: "dm-notification" });