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:
@@ -86,7 +86,7 @@ export async function getBlogByFeedUrl(application, feedUrl) {
|
|||||||
*/
|
*/
|
||||||
export async function createBlog(application, data) {
|
export async function createBlog(application, data) {
|
||||||
const collection = getCollection(application);
|
const collection = getCollection(application);
|
||||||
const now = new Date();
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
const blog = {
|
const blog = {
|
||||||
sourceId: data.sourceId ? new ObjectId(data.sourceId) : null,
|
sourceId: data.sourceId ? new ObjectId(data.sourceId) : null,
|
||||||
@@ -127,7 +127,7 @@ export async function updateBlog(application, id, data) {
|
|||||||
|
|
||||||
const update = {
|
const update = {
|
||||||
...data,
|
...data,
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove fields that shouldn't be updated directly
|
// Remove fields that shouldn't be updated directly
|
||||||
@@ -162,8 +162,8 @@ export async function deleteBlog(application, id) {
|
|||||||
$set: {
|
$set: {
|
||||||
status: "deleted",
|
status: "deleted",
|
||||||
hidden: true,
|
hidden: true,
|
||||||
deletedAt: new Date(),
|
deletedAt: new Date().toISOString(),
|
||||||
updatedAt: new Date(),
|
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 objectId = typeof id === "string" ? new ObjectId(id) : id;
|
||||||
|
|
||||||
const update = {
|
const update = {
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (status.success) {
|
if (status.success) {
|
||||||
update.status = "active";
|
update.status = "active";
|
||||||
update.lastFetchAt = new Date();
|
update.lastFetchAt = new Date().toISOString();
|
||||||
update.lastError = null;
|
update.lastError = null;
|
||||||
if (status.itemCount !== undefined) {
|
if (status.itemCount !== undefined) {
|
||||||
update.itemCount = status.itemCount;
|
update.itemCount = status.itemCount;
|
||||||
@@ -246,7 +246,7 @@ export async function getCategories(application) {
|
|||||||
*/
|
*/
|
||||||
export async function upsertBlog(application, data) {
|
export async function upsertBlog(application, data) {
|
||||||
const collection = getCollection(application);
|
const collection = getCollection(application);
|
||||||
const now = new Date();
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
// Skip if a blog with this feedUrl was soft-deleted
|
// Skip if a blog with this feedUrl was soft-deleted
|
||||||
const deleted = await collection.findOne({
|
const deleted = await collection.findOne({
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ export async function countItems(application, options = {}) {
|
|||||||
*/
|
*/
|
||||||
export async function upsertItem(application, data) {
|
export async function upsertItem(application, data) {
|
||||||
const collection = getCollection(application);
|
const collection = getCollection(application);
|
||||||
const now = new Date();
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
const result = await collection.updateOne(
|
const result = await collection.updateOne(
|
||||||
{ blogId: new ObjectId(data.blogId), uid: data.uid },
|
{ blogId: new ObjectId(data.blogId), uid: data.uid },
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export async function getSource(application, id) {
|
|||||||
*/
|
*/
|
||||||
export async function createSource(application, data) {
|
export async function createSource(application, data) {
|
||||||
const collection = getCollection(application);
|
const collection = getCollection(application);
|
||||||
const now = new Date();
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
const source = {
|
const source = {
|
||||||
type: data.type, // "opml_url" | "opml_file" | "manual" | "json_feed" | "microsub"
|
type: data.type, // "opml_url" | "opml_file" | "manual" | "json_feed" | "microsub"
|
||||||
@@ -80,7 +80,7 @@ export async function updateSource(application, id, data) {
|
|||||||
|
|
||||||
const update = {
|
const update = {
|
||||||
...data,
|
...data,
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove fields that shouldn't be updated directly
|
// 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 objectId = typeof id === "string" ? new ObjectId(id) : id;
|
||||||
|
|
||||||
const update = {
|
const update = {
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (status.success) {
|
if (status.success) {
|
||||||
update.lastSyncAt = new Date();
|
update.lastSyncAt = new Date().toISOString();
|
||||||
update.lastSyncError = null;
|
update.lastSyncError = null;
|
||||||
} else {
|
} else {
|
||||||
update.lastSyncError = status.error;
|
update.lastSyncError = status.error;
|
||||||
|
|||||||
+8
-4
@@ -142,8 +142,8 @@ function parseJsonFeed(content, feedUrl, maxItems) {
|
|||||||
text: item.content_text,
|
text: item.content_text,
|
||||||
},
|
},
|
||||||
summary: decodeEntities(item.summary) || truncateText(item.content_text, 300),
|
summary: decodeEntities(item.summary) || truncateText(item.content_text, 300),
|
||||||
published: item.date_published ? new Date(item.date_published) : new Date(),
|
published: item.date_published ? new Date(item.date_published).toISOString() : new Date().toISOString(),
|
||||||
updated: item.date_modified ? new Date(item.date_modified) : undefined,
|
updated: item.date_modified ? new Date(item.date_modified).toISOString() : undefined,
|
||||||
author: item.author || (item.authors?.[0]),
|
author: item.author || (item.authors?.[0]),
|
||||||
photo: item.image ? [item.image] : undefined,
|
photo: item.image ? [item.image] : undefined,
|
||||||
categories: item.tags || [],
|
categories: item.tags || [],
|
||||||
@@ -168,6 +168,10 @@ function parseJsonFeed(content, feedUrl, maxItems) {
|
|||||||
function normalizeItem(item, feedUrl) {
|
function normalizeItem(item, feedUrl) {
|
||||||
const description = item.description || item.summary || "";
|
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 {
|
return {
|
||||||
uid: generateUid(feedUrl, item.guid || item.link),
|
uid: generateUid(feedUrl, item.guid || item.link),
|
||||||
url: item.link || item.origlink,
|
url: item.link || item.origlink,
|
||||||
@@ -177,8 +181,8 @@ function normalizeItem(item, feedUrl) {
|
|||||||
text: stripHtml(description),
|
text: stripHtml(description),
|
||||||
},
|
},
|
||||||
summary: truncateText(stripHtml(item.summary || description), 300),
|
summary: truncateText(stripHtml(item.summary || description), 300),
|
||||||
published: item.pubdate || item.date || new Date(),
|
published: published ? (published instanceof Date ? published.toISOString() : new Date(published).toISOString()) : new Date().toISOString(),
|
||||||
updated: item.date,
|
updated: updated ? (updated instanceof Date ? updated.toISOString() : new Date(updated).toISOString()) : undefined,
|
||||||
author: item.author ? { name: item.author } : undefined,
|
author: item.author ? { name: item.author } : undefined,
|
||||||
photo: extractPhotos(item),
|
photo: extractPhotos(item),
|
||||||
categories: item.categories || [],
|
categories: item.categories || [],
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ export async function syncMicrosubSource(application, source) {
|
|||||||
$set: {
|
$set: {
|
||||||
status: "deleted",
|
status: "deleted",
|
||||||
hidden: true,
|
hidden: true,
|
||||||
deletedAt: new Date(),
|
deletedAt: new Date().toISOString(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -227,8 +227,8 @@ export async function handleMicrosubWebhook(application, data) {
|
|||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
status: "inactive",
|
status: "inactive",
|
||||||
unsubscribedAt: new Date(),
|
unsubscribedAt: new Date().toISOString(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ export async function runFullSync(application, options = {}) {
|
|||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
key: "syncStats",
|
key: "syncStats",
|
||||||
lastFullSync: new Date(),
|
lastFullSync: new Date().toISOString(),
|
||||||
duration,
|
duration,
|
||||||
sources: {
|
sources: {
|
||||||
total: enabledSources.length,
|
total: enabledSources.length,
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rmdes/indiekit-endpoint-blogroll",
|
"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.",
|
"description": "Blogroll endpoint for Indiekit. Aggregates blog feeds from OPML, JSON feeds, or manual entry.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"indiekit",
|
"indiekit",
|
||||||
|
|||||||
Reference in New Issue
Block a user