mirror of
https://github.com/svemagie/indiekit-endpoint-activitypub.git
synced 2026-04-02 15:44:58 +02:00
fix(mastodon-api): favourite/like 404 for items with BSON Date or timezone-offset published
Three-layer fix for findTimelineItemById cursor mismatches:
1. encodeCursor returns "" (falsy) for invalid dates — serializeStatus
now correctly falls back to item._id.toString() instead of using "0"
as an opaque ID that can never be looked up.
2. findTimelineItemById adds two new fallbacks after the existing string
lookups fail:
- BSON Date lookup: Micropub pipeline (postData.create) may store
published as a JavaScript Date → MongoDB BSON Date; string
comparison never matches.
- ±999 ms ISO range query: some AP servers send published with a
timezone offset (e.g. +01:00). String(Temporal.Instant) preserves
the original offset; decodeCursor normalizes to UTC, so the stored
string and the lookup string differ.
3. timeline-store.js extractObjectData now normalizes published via
new Date(String(...)).toISOString() before storing, ensuring all
future items are stored in UTC ISO format and the exact-match lookup
succeeds without needing the range fallback.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,9 +27,9 @@ const MAX_LIMIT = 40;
|
||||
* @returns {string} Numeric string (ms since epoch)
|
||||
*/
|
||||
export function encodeCursor(published) {
|
||||
if (!published) return "0";
|
||||
if (!published) return "";
|
||||
const ms = new Date(published).getTime();
|
||||
return Number.isFinite(ms) ? String(ms) : "0";
|
||||
return Number.isFinite(ms) && ms > 0 ? String(ms) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -733,7 +733,7 @@ async function findTimelineItemById(collection, id) {
|
||||
// Try cursor-based lookup first (published date from ms-since-epoch)
|
||||
const publishedDate = decodeCursor(id);
|
||||
if (publishedDate) {
|
||||
// Try exact match first (with .000Z suffix from toISOString)
|
||||
// Try exact UTC ISO match (e.g., "2026-03-21T15:33:50.000Z")
|
||||
let item = await collection.findOne({ published: publishedDate });
|
||||
if (item) return item;
|
||||
|
||||
@@ -744,6 +744,24 @@ async function findTimelineItemById(collection, id) {
|
||||
item = await collection.findOne({ published: withoutMs });
|
||||
if (item) return item;
|
||||
}
|
||||
|
||||
// Try BSON Date (Micropub pipeline stores published as Date objects)
|
||||
item = await collection.findOne({ published: new Date(publishedDate) });
|
||||
if (item) return item;
|
||||
|
||||
// Try date-range lookup for timezone-offset stored strings (+01:00 etc.)
|
||||
// Some AP servers emit non-UTC dates; decodeCursor normalizes to UTC but
|
||||
// the stored string may differ. Search a ±1 s window using a regex on the
|
||||
// ms value, or simply try the raw numeric id as a direct uid/url lookup.
|
||||
const ms = Number.parseInt(id, 10);
|
||||
if (ms > 0) {
|
||||
const lo = new Date(ms - 999).toISOString().replace(/\.999Z$/, "Z");
|
||||
const hi = new Date(ms + 999).toISOString().replace(/\.999Z$/, "Z");
|
||||
item = await collection.findOne({
|
||||
published: { $gte: lo, $lte: hi },
|
||||
});
|
||||
if (item) return item;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to ObjectId lookup (legacy IDs)
|
||||
|
||||
Reference in New Issue
Block a user