diff --git a/js/historyView.js b/js/historyView.js index fb19b7e6..b7fe51cf 100644 --- a/js/historyView.js +++ b/js/historyView.js @@ -2,9 +2,7 @@ import watchHistoryService from "./watchHistoryService.js"; import { nostrClient } from "./nostr.js"; -import { - updateWatchHistoryList as updateWatchHistoryListWithManager, -} from "./nostr/index.js"; +import { updateWatchHistoryList } from "./nostr/watchHistoryBindings.js"; import { pointerKey, normalizePointerInput } from "./nostr/watchHistory.js"; import { WATCH_HISTORY_BATCH_RESOLVE, @@ -36,13 +34,6 @@ const FALLBACK_AVATAR = "assets/svg/default-profile.svg"; const isDevEnv = typeof process !== "undefined" && process?.env?.NODE_ENV !== "production"; -const updateWatchHistoryList = (items, options) => - updateWatchHistoryListWithManager( - nostrClient.watchHistory, - items, - options, - ); - function escapeSelector(value) { if (typeof value !== "string") { return ""; diff --git a/js/nostr.js b/js/nostr.js index 8d1a7784..ccea21da 100644 --- a/js/nostr.js +++ b/js/nostr.js @@ -5,20 +5,16 @@ import { requestDefaultExtensionPermissions, } from "./nostr/defaultClient.js"; import { - updateWatchHistoryList as updateWatchHistoryListWithManager, - removeWatchHistoryItem as removeWatchHistoryItemWithManager, -} from "./nostr/watchHistory.js"; + updateWatchHistoryList, + removeWatchHistoryItem, +} from "./nostr/watchHistoryBindings.js"; export { nostrClient, requestDefaultExtensionPermissions }; export const recordVideoView = (...args) => nostrClient.recordVideoView(...args); -export const updateWatchHistoryList = (...args) => - updateWatchHistoryListWithManager(nostrClient.watchHistory, ...args); - -export const removeWatchHistoryItem = (...args) => - removeWatchHistoryItemWithManager(nostrClient.watchHistory, ...args); +export { updateWatchHistoryList, removeWatchHistoryItem }; export const listVideoViewEvents = (...args) => { if (typeof nostrClient.listVideoViewEvents !== "function") { diff --git a/js/nostr/index.js b/js/nostr/index.js index 5361b3b8..f7e4b76e 100644 --- a/js/nostr/index.js +++ b/js/nostr/index.js @@ -34,9 +34,12 @@ export { parseWatchHistoryContentWithFallback, isNip04EncryptedWatchHistoryEvent, watchHistoryHelpers, +} from "./watchHistory.js"; + +export { updateWatchHistoryList, removeWatchHistoryItem, -} from "./watchHistory.js"; +} from "./watchHistoryBindings.js"; export { deriveViewEventBucketIndex, diff --git a/js/nostr/watchHistoryBindings.js b/js/nostr/watchHistoryBindings.js new file mode 100644 index 00000000..6b1df833 --- /dev/null +++ b/js/nostr/watchHistoryBindings.js @@ -0,0 +1,29 @@ +// js/nostr/watchHistoryBindings.js + +import { nostrClient } from "./defaultClient.js"; +import { + updateWatchHistoryList as updateWatchHistoryListWithManager, + removeWatchHistoryItem as removeWatchHistoryItemWithManager, +} from "./watchHistory.js"; + +function getWatchHistoryManager() { + return nostrClient?.watchHistory || null; +} + +function assertWatchHistoryManager(operation) { + const manager = getWatchHistoryManager(); + if (!manager || typeof manager[operation] !== "function") { + throw new Error("Watch history manager is unavailable in this build."); + } + return manager; +} + +export function updateWatchHistoryList(...args) { + const manager = assertWatchHistoryManager("updateList"); + return updateWatchHistoryListWithManager(manager, ...args); +} + +export function removeWatchHistoryItem(...args) { + const manager = assertWatchHistoryManager("removeItem"); + return removeWatchHistoryItemWithManager(manager, ...args); +} diff --git a/tests/nostr/watchHistoryBindings.test.js b/tests/nostr/watchHistoryBindings.test.js new file mode 100644 index 00000000..5d6f95c2 --- /dev/null +++ b/tests/nostr/watchHistoryBindings.test.js @@ -0,0 +1,83 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { nostrClient } from "../../js/nostr/defaultClient.js"; +import { + updateWatchHistoryList, + removeWatchHistoryItem, +} from "../../js/nostr/watchHistoryBindings.js"; + +const originalWatchHistory = nostrClient.watchHistory; + +test.afterEach(() => { + nostrClient.watchHistory = originalWatchHistory; +}); + +test("updateWatchHistoryList delegates to the client's manager", () => { + const items = [{ type: "e", value: "event" }]; + const options = { actor: "npub123" }; + const expectedResult = { ok: true }; + const calls = []; + + nostrClient.watchHistory = { + updateList(...args) { + calls.push(args); + return expectedResult; + }, + }; + + const result = updateWatchHistoryList(items, options); + + assert.equal(result, expectedResult); + assert.equal(calls.length, 1); + assert.deepEqual(calls[0], [items, options]); +}); + +test("removeWatchHistoryItem delegates to the client's manager", () => { + const pointer = { type: "a", value: "kind:identifier" }; + const options = { reason: "cleanup" }; + const expectedResult = { ok: true }; + const calls = []; + + nostrClient.watchHistory = { + removeItem(...args) { + calls.push(args); + return expectedResult; + }, + }; + + const result = removeWatchHistoryItem(pointer, options); + + assert.equal(result, expectedResult); + assert.equal(calls.length, 1); + assert.deepEqual(calls[0], [pointer, options]); +}); + +test("watch history bindings throw when the manager is unavailable", () => { + nostrClient.watchHistory = null; + + assert.throws( + () => updateWatchHistoryList([], {}), + /Watch history manager is unavailable in this build\./, + ); + assert.throws( + () => removeWatchHistoryItem({ type: "e", value: "abc" }), + /Watch history manager is unavailable in this build\./, + ); +}); + +test("watch history bindings throw when a required method is missing", () => { + nostrClient.watchHistory = {}; + + assert.throws( + () => updateWatchHistoryList([], {}), + /Watch history manager is unavailable in this build\./, + ); + + nostrClient.watchHistory = { updateList: () => {} }; + + assert.throws( + () => removeWatchHistoryItem({ type: "e", value: "123" }), + /Watch history manager is unavailable in this build\./, + ); +});