Revise watch-history tags to use month IDs

Refactors the watch-history system to prioritize `YYYY-MM` month identifiers over legacy snapshot IDs in event tags, storage keys, and cross-module references. Updates event schemas, storage keying (v3), and client interfaces to align with the new month-based structure. Renames `snapshotId` parameters to `taskId` for republishing operations.
This commit is contained in:
google-labs-jules[bot] committed 2026-01-05 14:21:53 +00:00
1 parent 50e2481e46
commit 498d9cb5b2
3 files changed
+26 -20

No files matched your search

+4 -4
View File
@@ -3377,14 +3377,14 @@ export class NostrClient {
persistWatchHistoryEntryToManager(this.watchHistory, actorInput, entry);
}
cancelWatchHistoryRepublish(snapshotId = null) {
cancelWatchHistoryRepublishForManager(this.watchHistory, snapshotId);
cancelWatchHistoryRepublish(taskId = null) {
cancelWatchHistoryRepublishForManager(this.watchHistory, taskId);
}
scheduleWatchHistoryRepublish(snapshotId, operation, options = {}) {
scheduleWatchHistoryRepublish(taskId, operation, options = {}) {
return scheduleWatchHistoryRepublishForManager(
this.watchHistory,
snapshotId,
taskId,
operation,
options,
);
+13 -15
View File
@@ -28,7 +28,7 @@ import { devLogger, userLogger } from "../utils/logger.js";
* relay publishing, fetch/decrypt flows, and exposes a manager factory that is
* dependency-injected with the nostr client hooks it needs.
*/
const WATCH_HISTORY_STORAGE_KEY = "bitvid:watch-history:v2";
const WATCH_HISTORY_STORAGE_KEY = "bitvid:watch-history:v3";
const WATCH_HISTORY_STORAGE_VERSION = 3;
const WATCH_HISTORY_REPUBLISH_BASE_DELAY_MS = 2000;
const WATCH_HISTORY_REPUBLISH_MAX_DELAY_MS = 5 * 60 * 1000;
@@ -1227,8 +1227,8 @@ class WatchHistoryManager {
}
}
cancelRepublish(snapshotId = null) {
if (!snapshotId) {
cancelRepublish(taskId = null) {
if (!taskId) {
for (const entry of this.republishTimers.values()) {
if (entry && typeof entry.timer === "number") {
clearTimeout(entry.timer);
@@ -1241,7 +1241,7 @@ class WatchHistoryManager {
this.republishTimers.clear();
return;
}
const key = typeof snapshotId === "string" ? snapshotId.trim() : "";
const key = typeof taskId === "string" ? taskId.trim() : "";
if (!key) {
return;
}
@@ -1256,8 +1256,8 @@ class WatchHistoryManager {
this.republishTimers.delete(key);
}
scheduleRepublish(snapshotId, operation, options = {}) {
const key = typeof snapshotId === "string" ? snapshotId.trim() : "";
scheduleRepublish(taskId, operation, options = {}) {
const key = typeof taskId === "string" ? taskId.trim() : "";
if (!key || typeof operation !== "function") {
return;
}
@@ -1288,7 +1288,7 @@ class WatchHistoryManager {
);
if (onSchedule) {
try {
onSchedule({ snapshotId: key, attempt: attempt + 1, delay });
onSchedule({ taskId: key, attempt: attempt + 1, delay });
} catch (error) {
devLogger.warn(
`[nostr] Failed to notify watch history republish schedule for ${key}:`,
@@ -1476,7 +1476,7 @@ class WatchHistoryManager {
ok: allOk,
retryable: anyRetryable,
results,
snapshotId: months.join(','), // Fake snapshot ID representing the batch
snapshotId: "", // No single snapshot ID
// Return last event as pointerEvent? Or null?
pointerEvent: results.length > 0 ? results[results.length-1].pointerEvent : null
};
@@ -1567,7 +1567,6 @@ class WatchHistoryManager {
// They should already be sorted by canonicalize, but ensure it.
items.sort((a, b) => (b.watchedAt || 0) - (a.watchedAt || 0));
const snapshotId = monthIdentifier;
const { payload, included, skipped } = buildWatchHistoryPayload(
monthIdentifier,
items,
@@ -1871,7 +1870,6 @@ class WatchHistoryManager {
const event = buildWatchHistoryEvent({
pubkey: actorPubkey,
created_at: createdAtCursor,
snapshotId,
monthIdentifier,
pointerTags,
content: ciphertext,
@@ -1922,7 +1920,7 @@ class WatchHistoryManager {
ok: success,
retryable: !success,
actor: actorPubkey,
snapshotId,
monthIdentifier,
items: items, // Return items for this month
pointerEvent: signedEvent,
publishResults: {
@@ -2716,17 +2714,17 @@ export function persistWatchHistoryEntry(manager, actorInput, entry) {
return manager.persistEntry(actorInput, entry);
}
export function cancelWatchHistoryRepublish(manager, snapshotId = null) {
return manager.cancelRepublish(snapshotId);
export function cancelWatchHistoryRepublish(manager, taskId = null) {
return manager.cancelRepublish(taskId);
}
export function scheduleWatchHistoryRepublish(
manager,
snapshotId,
taskId,
operation,
options = {},
) {
return manager.scheduleRepublish(snapshotId, operation, options);
return manager.scheduleRepublish(taskId, operation, options);
}
export function getWatchHistoryFingerprint(
+9 -1
View File
@@ -1358,22 +1358,29 @@ export function buildWatchHistoryIndexEvent({
const schema = getNostrEventSchema(NOTE_TYPES.WATCH_HISTORY_INDEX);
const tags = [];
const identifierName = schema?.identifierTag?.name || "d";
// Prioritize monthIdentifier, fallback to snapshotId (legacy)
const identifierValue =
(typeof monthIdentifier === "string" && monthIdentifier.trim()) ||
(typeof snapshotId === "string" && snapshotId.trim()) ||
schema?.identifierTag?.value ||
WATCH_HISTORY_LIST_IDENTIFIER;
if (identifierName && identifierValue) {
tags.push([identifierName, identifierValue]);
}
// Ensure "month" tag is present if we have an identifier (assuming it's a month)
const monthTagName = schema?.monthTagName || "month";
if (monthTagName && identifierValue) {
tags.push([monthTagName, identifierValue]);
}
const pointerTagName = schema?.monthPointerTagName || schema?.chunkPointerTagName || "a";
const resolvedMonthAddresses = Array.isArray(monthAddresses) && monthAddresses.length
? monthAddresses
: chunkAddresses;
resolvedMonthAddresses?.forEach((address) => {
if (typeof address === "string" && address) {
tags.push([pointerTagName, address]);
@@ -1428,7 +1435,8 @@ export function buildWatchHistoryEvent({
const schema = getNostrEventSchema(NOTE_TYPES.WATCH_HISTORY_CHUNK);
const tags = [];
const identifierName = schema?.identifierTag?.name || "d";
// Prioritize monthIdentifier, fallback to snapshotId (which should now be the month), or schema default
// Prioritize monthIdentifier, fallback to snapshotId
const identifierValue =
(typeof monthIdentifier === "string" && monthIdentifier.trim()) ||
(typeof snapshotId === "string" && snapshotId.trim()) ||