feat(hk): explain background updates with protected content links and retry details
CI / check (push) Failing after 1m34s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped

This commit is contained in:
Simo committed 2026-09-13 19:41:25 +02:00
1 parent dd7613850e
commit c5c9941768
42 files changed
+1542 -145

No files matched your search

+18 -2
View File
@@ -7,6 +7,7 @@ const state = vi.hoisted(() => ({
articles: [] as Array<{
id: string;
userId: number | null;
title?: string;
status: string;
publishAt: Date;
}>,
@@ -146,8 +147,13 @@ it("uses the same UTC cutoff and publication timestamps regardless of the MySQL
);
expect(statements).toHaveLength(2);
for (const statement of statements) {
expect(format(statement.sql, statement.params, false, "+02:00")).toBe(
format(statement.sql, statement.params, false, "-07:00"),
const values = statement.params.map((value) => {
if (typeof value !== "string")
throw new Error("Expected explicit SQL string parameters");
return value;
});
expect(format(statement.sql, values, false, "+02:00")).toBe(
format(statement.sql, values, false, "-07:00"),
);
}
expect(statements[0].params).toEqual(["2030-06-01 08:09:10.123"]);
@@ -158,3 +164,13 @@ it("uses the same UTC cutoff and publication timestamps regardless of the MySQL
"2030-06-01 08:09:10.123",
]);
});
it("records the article title and exact identifier for the operation screen", async () => {
state.articles[0].title = "Scheduled community news";
await publishDueArticles(now);
expect(JSON.parse(String(state.operations[0][5]))).toEqual({
articleId: "1",
articleTitle: "Scheduled community news",
published: true,
});
});
+3 -2
View File
@@ -13,12 +13,13 @@ export async function publishDueArticles(now = new Date()): Promise<number> {
const utcNow = now.toISOString().slice(0, -1).replace("T", " ");
const published = await db.transaction(async (tx) => {
const [rows] = await tx.execute(
sql`SELECT CAST(id AS CHAR) AS id,user_id AS userId,publish_at AS publishAt FROM website_articles WHERE status='scheduled' AND publish_at<=${utcNow} ORDER BY publish_at,id LIMIT 100 FOR UPDATE`,
sql`SELECT CAST(id AS CHAR) AS id,user_id AS userId,title,publish_at AS publishAt FROM website_articles WHERE status='scheduled' AND publish_at<=${utcNow} ORDER BY publish_at,id LIMIT 100 FOR UPDATE`,
);
let published = 0;
for (const article of rows as unknown as Array<{
id: string;
userId: number | null;
title: string | null;
publishAt: Date | string;
}>) {
const [result] = await tx.execute(
@@ -33,7 +34,7 @@ export async function publishDueArticles(now = new Date()): Promise<number> {
});
// Legacy articles without an author remain attributed to system (0).
await tx.execute(
sql`INSERT INTO cms_operations (id,actor_id,kind,request_key,request_hash,result_json) VALUES (${operationId},${article.userId ?? 0},${"news.schedule.publish"},${randomUUID()},${hash},${JSON.stringify({ articleId: article.id, published: true })})`,
sql`INSERT INTO cms_operations (id,actor_id,kind,request_key,request_hash,result_json) VALUES (${operationId},${article.userId ?? 0},${"news.schedule.publish"},${randomUUID()},${hash},${JSON.stringify({ articleId: article.id, articleTitle: article.title, published: true })})`,
);
await enqueueEffect(tx, operationId, "news.refresh");
published++;