mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Publishing showed a flat "Video shared successfully!" even when most (or all)
relays rejected the event, so users couldn't tell a partial/failed publish from
a clean one. Now publishVideo captures the per-relay accept/reject summary and
stashes a compact {accepted,total} tally on the returned event via a
non-enumerable key (never serialized, never sent to relays). app.js reads it
back and reports the real outcome:
- all relays accepted -> "Video published to N relays!"
- some rejected -> warning "Video published to N of M relays …"
- none accepted -> error (defensive; this path normally throws first)
Falls back to the generic message when no tally is available.
Tests (describePublishOutcome + attach/readRelayPublishSummary): success/partial/
zero/singular/missing-tally messaging, and that the tally round-trips while
staying out of JSON serialization. Mutation-verified — flipping partial→success
and the summary key to enumerable both fail the suite.
Build + full lint green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
73 lines
2.6 KiB
JavaScript
73 lines
2.6 KiB
JavaScript
// After publishing a video bitvid must tell the user how many relays actually
|
|
// accepted it, instead of an opaque "shared successfully" that hides a partial
|
|
// or total relay failure. describePublishOutcome maps the relay tally to a
|
|
// message + tone; attach/readRelayPublishSummary carry the tally from the
|
|
// signed event to the UI without polluting the serialized event.
|
|
|
|
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import {
|
|
describePublishOutcome,
|
|
attachRelayPublishSummary,
|
|
readRelayPublishSummary,
|
|
RELAY_PUBLISH_SUMMARY_KEY,
|
|
} from "../js/nostrPublish.js";
|
|
|
|
test("full acceptance reports the relay count as success", () => {
|
|
const out = describePublishOutcome({ accepted: 4, total: 4 });
|
|
assert.equal(out.tone, "success");
|
|
assert.match(out.message, /4 relays/);
|
|
});
|
|
|
|
test("singular relay is not pluralized", () => {
|
|
const out = describePublishOutcome({ accepted: 1, total: 1 });
|
|
assert.equal(out.tone, "success");
|
|
assert.match(out.message, /1 relay\b/);
|
|
assert.doesNotMatch(out.message, /1 relays/);
|
|
});
|
|
|
|
test("partial acceptance is surfaced as a warning with both counts", () => {
|
|
const out = describePublishOutcome({ accepted: 2, total: 8 });
|
|
assert.equal(out.tone, "warning");
|
|
assert.match(out.message, /2 of 8/);
|
|
});
|
|
|
|
test("zero acceptance is an error telling the user nothing landed", () => {
|
|
const out = describePublishOutcome({ accepted: 0, total: 8 });
|
|
assert.equal(out.tone, "error");
|
|
assert.match(out.message, /any relay/i);
|
|
});
|
|
|
|
test("missing tally falls back to the generic success message", () => {
|
|
const out = describePublishOutcome({});
|
|
assert.equal(out.tone, "success");
|
|
// No fabricated relay count when we don't actually know one.
|
|
assert.doesNotMatch(out.message, /\d+ of \d+/);
|
|
});
|
|
|
|
test("attached tally round-trips and stays out of serialization", () => {
|
|
const event = { id: "abc", kind: 30078, content: "{}" };
|
|
attachRelayPublishSummary(event, {
|
|
accepted: [{ url: "wss://a" }, { url: "wss://b" }],
|
|
failed: [{ url: "wss://c" }],
|
|
});
|
|
|
|
const tally = readRelayPublishSummary(event);
|
|
assert.deepEqual(tally, { accepted: 2, total: 3 });
|
|
|
|
// The tally must never leak into the event the relays/JSON see.
|
|
assert.ok(
|
|
!Object.keys(event).includes(RELAY_PUBLISH_SUMMARY_KEY),
|
|
"summary key must be non-enumerable",
|
|
);
|
|
assert.ok(
|
|
!JSON.stringify(event).includes(RELAY_PUBLISH_SUMMARY_KEY),
|
|
"summary must not appear in the serialized event",
|
|
);
|
|
});
|
|
|
|
test("reading a summary off an event without one returns null", () => {
|
|
assert.equal(readRelayPublishSummary({ id: "x" }), null);
|
|
assert.equal(readRelayPublishSummary(null), null);
|
|
});
|