Ensure watch history snapshots advance created_at

This commit is contained in:
thePR0M3TH3AN committed 2025-09-30 15:01:55 -04:00
1 parent 61e8cc88fe
commit 32f04b94cb
2 files changed
+97 -1

No files matched your search

+29 -1
View File
@@ -1528,7 +1528,33 @@ class NostrClient {
}
const totalChunks = chunkItemsList.length || 1;
const baseTimestamp = Math.floor(Date.now() / 1000);
const nowSeconds = Math.floor(Date.now() / 1000);
let lastCreatedAt = 0;
const pointerCandidates = [];
if (existingEntry?.pointerEvent) {
pointerCandidates.push(existingEntry.pointerEvent);
}
const cachedPointerEvent = this.watchHistoryCache.get(normalizedActor)?.pointerEvent;
if (cachedPointerEvent) {
pointerCandidates.push(cachedPointerEvent);
}
for (const candidate of pointerCandidates) {
if (!candidate || typeof candidate !== "object") {
continue;
}
const createdAt = Number.isFinite(candidate.created_at)
? Math.floor(candidate.created_at)
: null;
if (createdAt !== null && createdAt > lastCreatedAt) {
lastCreatedAt = createdAt;
}
}
const baseTimestamp = Math.max(nowSeconds, lastCreatedAt + totalChunks);
const chunkResults = [];
let overallSuccess = true;
@@ -1578,6 +1604,8 @@ class NostrClient {
tags.splice(2, 0, ["head", "1"]);
}
// Ensure created_at stays monotonic so chunk 0 always outranks prior snapshots
// even when multiple publishes land within the same wall-clock second.
const event = {
kind: WATCH_HISTORY_KIND,
pubkey: normalizedActor,
+68
View File
@@ -158,6 +158,74 @@ assert.deepEqual(
"chunked fetch should preserve pointer order"
);
const MONOTONIC_ACTOR = `${ACTOR}-monotonic`;
const { client: monotonicPublishingClient, publishedEvents: monotonicEvents } =
createPublishingClient(MONOTONIC_ACTOR);
const monotonicOriginalDateNow = Date.now;
try {
const monotonicBaseSeconds = 1_700_123_456;
Date.now = () => monotonicBaseSeconds * 1000;
const firstMonotonicPointers = [
{ type: "e", value: "event-monotonic-1", relay: null },
{ type: "e", value: "event-monotonic-2", relay: null },
];
const firstSnapshot = await monotonicPublishingClient.publishWatchHistorySnapshot(
MONOTONIC_ACTOR,
firstMonotonicPointers
);
const baselineEntry = monotonicPublishingClient.createWatchHistoryEntry(
firstSnapshot.event,
firstMonotonicPointers,
Date.now()
);
monotonicPublishingClient.watchHistoryCache.set(
MONOTONIC_ACTOR,
baselineEntry
);
const secondMonotonicPointers = [
{ type: "e", value: "event-monotonic-3", relay: null },
{ type: "e", value: "event-monotonic-1", relay: null },
];
const secondSnapshot = await monotonicPublishingClient.publishWatchHistorySnapshot(
MONOTONIC_ACTOR,
secondMonotonicPointers,
baselineEntry
);
assert(
secondSnapshot.event.created_at > firstSnapshot.event.created_at,
"new snapshot should advance created_at when reusing the same second"
);
const monotonicDecryptClient = createDecryptClient(MONOTONIC_ACTOR);
monotonicDecryptClient.pool = { list: async () => monotonicEvents };
const monotonicFetched = await monotonicDecryptClient.fetchWatchHistory(
MONOTONIC_ACTOR
);
assert.deepEqual(
monotonicFetched.items.map((item) => ({
type: item.type,
value: item.value,
relay: item.relay || null,
})),
[
{ type: "e", value: "event-monotonic-3", relay: null },
{ type: "e", value: "event-monotonic-1", relay: null },
],
"newer snapshot should win pointer ordering"
);
} finally {
Date.now = monotonicOriginalDateNow;
}
localStorage.clear();
const originalDateNow = Date.now;