mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
This is why logged-in removal "worked but threw a flag error", and likely why new watches stopped appearing in history. publishMonthRecord reported success only when EVERY write relay accepted (acceptedCount === relays.length). With a 20+ relay list many always reject (auth-required/rate-limited/not-in-write-set), so every snapshot — removals AND new-watch tracking — was marked "partial-relay-acceptance" -> ok:false -> "watch-history-snapshot-failed". The data WAS published (major relays accepted), but the UI showed a failure and the queue treated it as not-yet-synced. A watch-history event is durable if any relay accepted it (reads take the newest copy per d-tag), so success = acceptedCount > 0; only a zero-accept publish is a retryable failure. Also dropped the redundant partialAcceptance alias to stay within the file-size budget. Tests + mutation-verified: 1-of-3 accept -> ok/non-retryable; 0-of-3 -> failure/retryable. Reverting to the all-relays criterion fails the partial case. Build + full lint green. Co-Authored-By: Claude Opus 4.8 <[email protected]>
78 lines
2.8 KiB
JavaScript
78 lines
2.8 KiB
JavaScript
// A watch-history snapshot must succeed when ANY relay accepts it — a large/flaky
|
|
// relay list always has rejectors, and reads take the newest copy per d-tag, so
|
|
// one accepting relay is durable. Requiring ALL relays made every removal report
|
|
// a false "watch-history-snapshot-failed" and stopped new watches from
|
|
// persisting. Only a zero-accept publish is a (retryable) failure.
|
|
|
|
import "./test-helpers/setup-localstorage.mjs";
|
|
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { createWatchHistoryManager } from "../js/nostr/watchHistory.js";
|
|
|
|
const ACTOR = "a".repeat(64);
|
|
const SESSION_KEY = "b".repeat(64);
|
|
const GOOD = "wss://good.relay";
|
|
|
|
function makeManager(acceptUrls) {
|
|
const accepted = new Set(acceptUrls);
|
|
const toolkit = {
|
|
nip04: { encrypt: async (_p, _pub, txt) => `enc:${txt}` },
|
|
};
|
|
return createWatchHistoryManager({
|
|
getActivePubkey: () => ACTOR,
|
|
getSessionActor: () => ({ pubkey: ACTOR, privateKey: SESSION_KEY }),
|
|
ensureSessionActor: async () => ACTOR,
|
|
resolveActiveSigner: () => null,
|
|
shouldRequestExtensionPermissions: () => false,
|
|
signEventWithPrivateKey: (event) => ({ ...event, id: `id-${event.created_at}-${Math.random()}`, sig: "sig" }),
|
|
ensureNostrTools: async () => toolkit,
|
|
getCachedNostrTools: () => toolkit,
|
|
getWriteRelays: () => [GOOD, "wss://bad1.relay", "wss://bad2.relay"],
|
|
getRelayFallback: () => [GOOD],
|
|
getPool: () => ({
|
|
publish(urls) {
|
|
const url = Array.isArray(urls) ? urls[0] : urls;
|
|
const ok = accepted.has(url);
|
|
return {
|
|
on(name, handler) {
|
|
if (ok && name === "ok") setTimeout(handler, 0);
|
|
if (!ok && name === "failed") setTimeout(() => handler("rejected"), 0);
|
|
return this;
|
|
},
|
|
};
|
|
},
|
|
async list() {
|
|
return [];
|
|
},
|
|
}),
|
|
});
|
|
}
|
|
|
|
test("a month accepted by only ONE of several relays is a success (not a false failure)", async () => {
|
|
const manager = makeManager([GOOD]); // 1 of 3 relays accepts
|
|
try {
|
|
const result = await manager.publishRecords(
|
|
{ "2026-06": [{ type: "e", value: "watched-x", watchedAt: 1 }] },
|
|
{ actorPubkey: ACTOR },
|
|
);
|
|
assert.equal(result.ok, true, "partial acceptance must report success");
|
|
assert.equal(result.retryable, false, "a partial accept is not retryable");
|
|
} finally {
|
|
manager.clear();
|
|
}
|
|
});
|
|
|
|
test("a month rejected by ALL relays is a retryable failure", async () => {
|
|
const manager = makeManager([]); // zero relays accept
|
|
try {
|
|
const result = await manager.publishRecords(
|
|
{ "2026-06": [{ type: "e", value: "watched-x", watchedAt: 1 }] },
|
|
{ actorPubkey: ACTOR },
|
|
);
|
|
assert.equal(result.ok, false, "zero acceptance is a failure");
|
|
assert.equal(result.retryable, true, "a total failure should be retryable");
|
|
} finally {
|
|
manager.clear();
|
|
}
|
|
});
|