fix: store dates as ISO strings instead of Date objects

Prevents dateString.split crash when Nunjucks | date filter receives
Date objects from MongoDB. All stored dates now use .toISOString().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ricardo
2026-02-12 22:29:13 +01:00
parent 2a98784381
commit d634c70cfe
7 changed files with 26 additions and 22 deletions

View File

@@ -86,7 +86,7 @@ export async function getBlogByFeedUrl(application, feedUrl) {
*/
export async function createBlog(application, data) {
const collection = getCollection(application);
const now = new Date();
const now = new Date().toISOString();
const blog = {
sourceId: data.sourceId ? new ObjectId(data.sourceId) : null,
@@ -127,7 +127,7 @@ export async function updateBlog(application, id, data) {
const update = {
...data,
updatedAt: new Date(),
updatedAt: new Date().toISOString(),
};
// Remove fields that shouldn't be updated directly
@@ -162,8 +162,8 @@ export async function deleteBlog(application, id) {
$set: {
status: "deleted",
hidden: true,
deletedAt: new Date(),
updatedAt: new Date(),
deletedAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
}
);
@@ -181,12 +181,12 @@ export async function updateBlogStatus(application, id, status) {
const objectId = typeof id === "string" ? new ObjectId(id) : id;
const update = {
updatedAt: new Date(),
updatedAt: new Date().toISOString(),
};
if (status.success) {
update.status = "active";
update.lastFetchAt = new Date();
update.lastFetchAt = new Date().toISOString();
update.lastError = null;
if (status.itemCount !== undefined) {
update.itemCount = status.itemCount;
@@ -246,7 +246,7 @@ export async function getCategories(application) {
*/
export async function upsertBlog(application, data) {
const collection = getCollection(application);
const now = new Date();
const now = new Date().toISOString();
// Skip if a blog with this feedUrl was soft-deleted
const deleted = await collection.findOne({

View File

@@ -206,7 +206,7 @@ export async function countItems(application, options = {}) {
*/
export async function upsertItem(application, data) {
const collection = getCollection(application);
const now = new Date();
const now = new Date().toISOString();
const result = await collection.updateOne(
{ blogId: new ObjectId(data.blogId), uid: data.uid },

View File

@@ -45,7 +45,7 @@ export async function getSource(application, id) {
*/
export async function createSource(application, data) {
const collection = getCollection(application);
const now = new Date();
const now = new Date().toISOString();
const source = {
type: data.type, // "opml_url" | "opml_file" | "manual" | "json_feed" | "microsub"
@@ -80,7 +80,7 @@ export async function updateSource(application, id, data) {
const update = {
...data,
updatedAt: new Date(),
updatedAt: new Date().toISOString(),
};
// Remove fields that shouldn't be updated directly
@@ -135,11 +135,11 @@ export async function updateSourceSyncStatus(application, id, status) {
const objectId = typeof id === "string" ? new ObjectId(id) : id;
const update = {
updatedAt: new Date(),
updatedAt: new Date().toISOString(),
};
if (status.success) {
update.lastSyncAt = new Date();
update.lastSyncAt = new Date().toISOString();
update.lastSyncError = null;
} else {
update.lastSyncError = status.error;

View File

@@ -142,8 +142,8 @@ function parseJsonFeed(content, feedUrl, maxItems) {
text: item.content_text,
},
summary: decodeEntities(item.summary) || truncateText(item.content_text, 300),
published: item.date_published ? new Date(item.date_published) : new Date(),
updated: item.date_modified ? new Date(item.date_modified) : undefined,
published: item.date_published ? new Date(item.date_published).toISOString() : new Date().toISOString(),
updated: item.date_modified ? new Date(item.date_modified).toISOString() : undefined,
author: item.author || (item.authors?.[0]),
photo: item.image ? [item.image] : undefined,
categories: item.tags || [],
@@ -168,6 +168,10 @@ function parseJsonFeed(content, feedUrl, maxItems) {
function normalizeItem(item, feedUrl) {
const description = item.description || item.summary || "";
// Convert dates to ISO strings - feedparser returns Date objects
const published = item.pubdate || item.date;
const updated = item.date;
return {
uid: generateUid(feedUrl, item.guid || item.link),
url: item.link || item.origlink,
@@ -177,8 +181,8 @@ function normalizeItem(item, feedUrl) {
text: stripHtml(description),
},
summary: truncateText(stripHtml(item.summary || description), 300),
published: item.pubdate || item.date || new Date(),
updated: item.date,
published: published ? (published instanceof Date ? published.toISOString() : new Date(published).toISOString()) : new Date().toISOString(),
updated: updated ? (updated instanceof Date ? updated.toISOString() : new Date(updated).toISOString()) : undefined,
author: item.author ? { name: item.author } : undefined,
photo: extractPhotos(item),
categories: item.categories || [],

View File

@@ -100,8 +100,8 @@ export async function syncMicrosubSource(application, source) {
$set: {
status: "deleted",
hidden: true,
deletedAt: new Date(),
updatedAt: new Date(),
deletedAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
}
);
@@ -227,8 +227,8 @@ export async function handleMicrosubWebhook(application, data) {
{
$set: {
status: "inactive",
unsubscribedAt: new Date(),
updatedAt: new Date(),
unsubscribedAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
}
);

View File

@@ -110,7 +110,7 @@ export async function runFullSync(application, options = {}) {
{
$set: {
key: "syncStats",
lastFullSync: new Date(),
lastFullSync: new Date().toISOString(),
duration,
sources: {
total: enabledSources.length,

View File

@@ -1,6 +1,6 @@
{
"name": "@rmdes/indiekit-endpoint-blogroll",
"version": "1.0.16",
"version": "1.0.17",
"description": "Blogroll endpoint for Indiekit. Aggregates blog feeds from OPML, JSON feeds, or manual entry.",
"keywords": [
"indiekit",