mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Refactor user blocking to prioritize standard NIP-51 Mute Lists
- Updates `js/userBlocks.js` to write block entries to a standard Kind 10000 Mute List event. - Implements a hybrid storage model: unencrypted public mutes are stored in `p` tags, while private blocks are stored in the encrypted event content. - Maintains read compatibility with legacy `d=user-blocks` lists (both Kind 10000 and Kind 30002) by merging and prioritizing the newest event timestamp. - Updates local caching to persist both public mutes and private blocks, preventing data loss or "zombie" entries on reload. - Updates `js/subscriptions.js` to correctly detect NIP-44 capabilities on `Nip07Adapter` signers, fixing a regression where NIP-04 fallback was skipped. - Updates `js/nostrEventSchemas.js` to mark `USER_BLOCK_LIST` as legacy and define `MUTE_LIST`. - Updates unit tests to verify the new multi-kind fetching and merged publishing logic. Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
8383a4f18b
commit
de5e453b34
3 files changed
+43
-16
No files matched your search
+7
-2
@@ -887,8 +887,13 @@ class SubscriptionsManager {
|
||||
signer = await nostrClient.ensureActiveSignerForPubkey(userPubkey);
|
||||
}
|
||||
|
||||
const signerHasNip04 = typeof signer?.nip04Decrypt === "function";
|
||||
const signerHasNip44 = typeof signer?.nip44Decrypt === "function";
|
||||
const signerCapabilities = signer?.capabilities;
|
||||
const signerHasNip04 =
|
||||
typeof signer?.nip04Decrypt === "function" &&
|
||||
(!signerCapabilities || signerCapabilities.nip04 !== false);
|
||||
const signerHasNip44 =
|
||||
typeof signer?.nip44Decrypt === "function" &&
|
||||
(!signerCapabilities || signerCapabilities.nip44 !== false);
|
||||
|
||||
const nostrApi = allowPermissionPrompt
|
||||
? typeof window !== "undefined"
|
||||
|
||||
+33
-11
@@ -934,9 +934,9 @@ class UserBlockListManager {
|
||||
const hasLocalData = !!localData;
|
||||
|
||||
if (localData) {
|
||||
this._privateBlocks = localData.blockedPubkeys;
|
||||
this._publicMutes = new Set(); // Local cache structure currently only stores 'blockedPubkeys'
|
||||
this.blockedPubkeys = new Set(this._privateBlocks);
|
||||
this._privateBlocks = localData.privateBlocks || localData.blockedPubkeys || new Set();
|
||||
this._publicMutes = localData.publicMutes || new Set();
|
||||
this.blockedPubkeys = new Set([...this._privateBlocks, ...this._publicMutes]);
|
||||
|
||||
if (Number.isFinite(localData.createdAt)) {
|
||||
this.blockEventCreatedAt = localData.createdAt;
|
||||
@@ -1467,8 +1467,8 @@ class UserBlockListManager {
|
||||
? this.blockEventCreatedAt
|
||||
: 0;
|
||||
|
||||
// Concurrent incremental fetch for both kinds
|
||||
const [muteEvents, blockEvents] = await Promise.all([
|
||||
// Concurrent incremental fetch for all variants
|
||||
const [muteEvents, blockEvents, legacyEvents] = await Promise.all([
|
||||
nostrClient.fetchListIncrementally({
|
||||
kind: 10000,
|
||||
pubkey: normalized,
|
||||
@@ -1484,9 +1484,17 @@ class UserBlockListManager {
|
||||
since: fetchSince,
|
||||
timeoutMs: 12000,
|
||||
}),
|
||||
nostrClient.fetchListIncrementally({
|
||||
kind: 30002,
|
||||
pubkey: normalized,
|
||||
dTag: BLOCK_LIST_IDENTIFIER,
|
||||
relayUrls: relays,
|
||||
since: fetchSince,
|
||||
timeoutMs: 12000,
|
||||
}),
|
||||
]);
|
||||
|
||||
const combined = [...muteEvents, ...blockEvents];
|
||||
const combined = [...muteEvents, ...blockEvents, ...legacyEvents];
|
||||
|
||||
// If combined is empty, check if we have loaded state
|
||||
if (!combined.length) {
|
||||
@@ -1518,10 +1526,21 @@ class UserBlockListManager {
|
||||
return { blockedPubkeys: new Set(cached), createdAt: null };
|
||||
}
|
||||
if (cached && typeof cached === "object") {
|
||||
const privateBlocks = new Set(
|
||||
Array.isArray(cached.privateBlocks) ? cached.privateBlocks : [],
|
||||
);
|
||||
const publicMutes = new Set(
|
||||
Array.isArray(cached.publicMutes) ? cached.publicMutes : [],
|
||||
);
|
||||
// Fallback for legacy cache format
|
||||
const blockedPubkeys = new Set(
|
||||
Array.isArray(cached.blockedPubkeys) ? cached.blockedPubkeys : [],
|
||||
);
|
||||
|
||||
return {
|
||||
blockedPubkeys: new Set(
|
||||
Array.isArray(cached.blockedPubkeys) ? cached.blockedPubkeys : [],
|
||||
),
|
||||
privateBlocks,
|
||||
publicMutes,
|
||||
blockedPubkeys,
|
||||
createdAt: Number.isFinite(cached.createdAt) ? cached.createdAt : null,
|
||||
};
|
||||
}
|
||||
@@ -1534,9 +1553,12 @@ class UserBlockListManager {
|
||||
return;
|
||||
}
|
||||
profileCache.setProfileData(normalizedActorHex, "blocks", {
|
||||
blockedPubkeys: Array.from(this._privateBlocks), // Local cache historically stores private blocks
|
||||
privateBlocks: Array.from(this._privateBlocks),
|
||||
publicMutes: Array.from(this._publicMutes),
|
||||
// Keep blockedPubkeys for backward compatibility if needed, or just relying on new keys
|
||||
blockedPubkeys: Array.from(this.blockedPubkeys),
|
||||
createdAt: this.blockEventCreatedAt,
|
||||
version: 1,
|
||||
version: 2,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -100,8 +100,8 @@ await (async () => {
|
||||
|
||||
assert.deepEqual(
|
||||
calls,
|
||||
[...relays, ...relays],
|
||||
"loadBlocks should initiate queries for all relays concurrently (twice, for block list and mute list)"
|
||||
[...relays, ...relays, ...relays],
|
||||
"loadBlocks should initiate queries for all relays concurrently (thrice, for block list, mute list, and legacy kind 30002)"
|
||||
);
|
||||
|
||||
// Reverting to original test data:
|
||||
@@ -254,7 +254,7 @@ await (async () => {
|
||||
|
||||
assert.deepEqual(
|
||||
calls,
|
||||
[...relays, ...relays],
|
||||
[...relays, ...relays, ...relays],
|
||||
"loadBlocks should query fast and background relays concurrently",
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user