Files
bitvid/tests/torrent-metadata-schema.test.mjs
T
thePR0M3TH3ANandClaude Opus 4.8 e81e65ff40 feat(blossom): Phase 2 management — blob delete-on-orphan + kind-10063 server list (#30)
- deleteByUrl maps a Blossom URL back to its content-addressed blob (blobSha256FromUrl) and deletes it via BUD-12, defaulting to the URL's own origin. Wired into the edit-modal orphan cleanup so a superseded Blossom video/thumbnail is reclaimed (best-effort, never blocks the edit).

- BUD-03 kind-10063 server-list discovery: read (serversFromServerListEvent) + build (buildBlossomServerListEvent) + an extracted, testable import/publish helper (blossomServerList.js), plus 'Import from my server list' / 'Publish my server list' controls in the Storage pane's Blossom section.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 10:32:22 -04:00

99 lines
3.8 KiB
JavaScript

// buildTorrentMetadataEvent + infohash-addressing helpers (Phase 0 of the Blossom
// WebTorrent-metadata companion event). Covers the event shape, the base64
// round-trip, the addressing key, and input guards. See
// docs/blossom-torrent-metadata-plan.md.
import test from "node:test";
import assert from "node:assert/strict";
import {
buildTorrentMetadataEvent,
normalizeInfoHash,
torrentMetadataDTag,
TORRENT_METADATA_KIND,
buildBlossomServerListEvent,
BLOSSOM_SERVER_LIST_KIND,
} from "../js/nostrEventSchemas.js";
const INFOHASH = "0123456789abcdef0123456789abcdef01234567"; // 40 hex
const TORRENT_B64 = Buffer.from("d4:infod6:lengthi1eee").toString("base64");
const PK = "a".repeat(64);
test("normalizeInfoHash lowercases valid 40-hex and rejects the rest", () => {
assert.equal(normalizeInfoHash(INFOHASH.toUpperCase()), INFOHASH);
assert.equal(normalizeInfoHash(` ${INFOHASH} `), INFOHASH);
assert.equal(normalizeInfoHash("not-hex"), "");
assert.equal(normalizeInfoHash("abc"), "", "too short");
assert.equal(normalizeInfoHash("a".repeat(64)), "", "sha256-length is not a v1 infohash");
assert.equal(normalizeInfoHash(null), "");
});
test("torrentMetadataDTag builds the addressing key, empty on bad input", () => {
assert.equal(torrentMetadataDTag(INFOHASH), `bitvid:torrent:${INFOHASH}`);
assert.equal(torrentMetadataDTag("nope"), "");
});
test("buildTorrentMetadataEvent produces a kind-30078 event keyed by infohash", () => {
const event = buildTorrentMetadataEvent({
pubkey: PK,
created_at: 1700000000,
infoHash: INFOHASH.toUpperCase(), // caller may pass any case
torrentBase64: TORRENT_B64,
videoEventId: "vid-event-id",
});
assert.equal(event.kind, TORRENT_METADATA_KIND);
assert.equal(event.pubkey, PK);
const dTag = event.tags.find((t) => t[0] === "d");
assert.deepEqual(dTag, ["d", `bitvid:torrent:${INFOHASH}`], "addressed by lowercase infohash");
assert.deepEqual(event.tags.find((t) => t[0] === "x"), ["x", INFOHASH]);
assert.deepEqual(event.tags.find((t) => t[0] === "client"), ["client", "bitvid"]);
assert.deepEqual(event.tags.find((t) => t[0] === "e"), ["e", "vid-event-id"]);
});
test("buildTorrentMetadataEvent content round-trips the exact .torrent bytes", () => {
const event = buildTorrentMetadataEvent({
pubkey: PK,
created_at: 1700000000,
infoHash: INFOHASH,
torrentBase64: TORRENT_B64,
});
const envelope = JSON.parse(event.content);
assert.equal(envelope.v, 1);
assert.equal(envelope.infohash, INFOHASH);
assert.equal(envelope.torrent, TORRENT_B64);
// The recovered bytes are byte-identical to what was embedded.
assert.equal(
Buffer.from(envelope.torrent, "base64").toString(),
"d4:infod6:lengthi1eee",
);
// No back-reference tag when videoEventId is omitted.
assert.equal(event.tags.some((t) => t[0] === "e"), false);
});
test("buildTorrentMetadataEvent rejects an invalid infohash or empty payload", () => {
assert.throws(
() => buildTorrentMetadataEvent({ pubkey: PK, created_at: 1, infoHash: "bad", torrentBase64: TORRENT_B64 }),
/valid 40-hex-char infoHash/,
);
assert.throws(
() => buildTorrentMetadataEvent({ pubkey: PK, created_at: 1, infoHash: INFOHASH, torrentBase64: "" }),
/non-empty base64 torrent payload/,
);
});
test("buildBlossomServerListEvent builds a de-duped kind-10063 server list (BUD-03)", () => {
const ev = buildBlossomServerListEvent({
pubkey: PK,
created_at: 1700000000,
servers: [" https://a ", "https://a", "https://b", ""],
});
assert.equal(ev.kind, BLOSSOM_SERVER_LIST_KIND);
assert.equal(ev.kind, 10063);
assert.deepEqual(
ev.tags.filter((t) => t[0] === "server"),
[["server", "https://a"], ["server", "https://b"]],
"one server tag per unique url, in order",
);
assert.deepEqual(ev.tags.find((t) => t[0] === "client"), ["client", "bitvid"]);
assert.equal(ev.content, "");
});