Add watch history pointer tags and fallback tests

This commit is contained in:
thePR0M3TH3AN committed 2025-09-30 13:53:20 -04:00
1 parent b4b2baef32
commit 712e9207e3
2 files changed
+135 -5

No files matched your search

+23 -5
View File
@@ -1100,12 +1100,15 @@ class NostrClient {
}
async decryptWatchHistoryEvent(pointerEvent, actorPubkey) {
const fallbackItems = extractPointerItemsFromEvent(pointerEvent);
const fallbackPayload = { version: 0, items: fallbackItems };
const normalizedActor =
typeof actorPubkey === "string" && actorPubkey.trim()
? actorPubkey.trim().toLowerCase()
: "";
if (!normalizedActor) {
return { version: 0, items: extractPointerItemsFromEvent(pointerEvent) };
return fallbackPayload;
}
const ciphertext =
@@ -1114,7 +1117,7 @@ class NostrClient {
: "";
if (!ciphertext) {
return { version: 0, items: extractPointerItemsFromEvent(pointerEvent) };
return fallbackPayload;
}
const normalizedLogged =
@@ -1131,7 +1134,10 @@ class NostrClient {
ciphertext
);
const parsed = parseWatchHistoryPayload(plaintext);
return parsed;
if (parsed.items.length || fallbackItems.length === 0) {
return parsed;
}
return { ...parsed, items: fallbackItems };
} catch (error) {
if (isDevMode) {
console.warn(
@@ -1164,7 +1170,10 @@ class NostrClient {
ciphertext
);
const parsed = parseWatchHistoryPayload(plaintext);
return parsed;
if (parsed.items.length || fallbackItems.length === 0) {
return parsed;
}
return { ...parsed, items: fallbackItems };
} catch (error) {
if (isDevMode) {
console.warn(
@@ -1175,7 +1184,7 @@ class NostrClient {
}
}
return { version: 0, items: extractPointerItemsFromEvent(pointerEvent) };
return fallbackPayload;
}
cancelWatchHistoryRepublish(actor) {
@@ -1300,9 +1309,18 @@ class NostrClient {
return encryptionResult;
}
const pointerTags = trimmedItems.map((item) => {
const tag = [item.type, item.value];
if (item.relay) {
tag.push(item.relay);
}
return tag;
});
const tags = [
["d", WATCH_HISTORY_LIST_IDENTIFIER],
["encrypted", "nip04"],
...pointerTags,
];
const event = {
+112
View File
@@ -0,0 +1,112 @@
import "./test-helpers/setup-localstorage.mjs";
import assert from "node:assert/strict";
if (typeof globalThis.window === "undefined") {
globalThis.window = {};
}
if (!globalThis.window.NostrTools) {
globalThis.window.NostrTools = {};
}
globalThis.window.NostrTools.getEventHash = (event) => {
const payload = `${event.kind}:${event.pubkey}:${event.created_at}`;
return `hash-${Buffer.from(payload).toString("hex")}`;
};
globalThis.window.NostrTools.signEvent = (event, privateKey) =>
`sig-${privateKey.slice(0, 8)}-${event.created_at}`;
delete globalThis.window.NostrTools.nip04;
delete globalThis.window.nostr;
const { nostrClient } = await import("../js/nostr.js");
function createPublishingClient(actorPubkey) {
const client = new nostrClient.constructor();
client.pool = {
publish(urls, event) {
return {
on(eventName, handler) {
if (eventName === "ok" || eventName === "seen") {
setTimeout(handler, 0);
}
},
};
},
};
client.relays = ["wss://unit.test"];
client.pubkey = "";
client.sessionActor = { pubkey: actorPubkey, privateKey: "unit-secret" };
client.ensureSessionActor = async () => actorPubkey;
client.encryptWatchHistoryPayload = async () => ({
ok: true,
ciphertext: "ciphertext",
});
client.persistWatchHistoryEntry = () => {};
client.cancelWatchHistoryRepublish = () => {};
client.scheduleWatchHistoryRepublish = () => {};
return client;
}
function createDecryptClient(actorPubkey) {
const client = new nostrClient.constructor();
client.sessionActor = { pubkey: actorPubkey, privateKey: "unit-secret" };
client.ensureSessionActor = async () => actorPubkey;
return client;
}
const ACTOR = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
const POINTER_A = {
type: "a",
value: `30078:${ACTOR}:watch-history`,
relay: "wss://relay.unit",
};
const POINTER_E = { type: "e", value: "event-id-123", relay: null };
const publishingClient = createPublishingClient(ACTOR);
const publishResult = await publishingClient.publishWatchHistorySnapshot(
ACTOR,
[POINTER_A, POINTER_E]
);
assert.equal(publishResult.ok, true, "publish should report success");
const pointerTags = publishResult.event.tags.filter((tag) =>
tag && (tag[0] === "a" || tag[0] === "e")
);
assert.deepEqual(pointerTags, [
["a", POINTER_A.value, POINTER_A.relay],
["e", POINTER_E.value],
]);
assert.deepEqual(
publishResult.items.map((item) => ({
type: item.type,
value: item.value,
relay: item.relay || null,
})),
[
{ type: "a", value: POINTER_A.value, relay: POINTER_A.relay },
{ type: "e", value: POINTER_E.value, relay: null },
]
);
delete globalThis.window.nostr;
delete globalThis.window.NostrTools.nip04;
const decryptClient = createDecryptClient(ACTOR);
const decrypted = await decryptClient.decryptWatchHistoryEvent(
publishResult.event,
ACTOR
);
assert.deepEqual(decrypted, {
version: 0,
items: [
{ type: "a", value: POINTER_A.value, relay: POINTER_A.relay },
{ type: "e", value: POINTER_E.value, relay: null },
],
});
console.log("watch history tests passed");