Files
sunrise/server/threads/reply.ts
T

26 lines
1.4 KiB
TypeScript

import { readFile, writeFile, rename } from 'node:fs/promises';
import { randomUUID } from 'node:crypto';
import { publishReply } from './publisher.ts';
/** A separate exclusive claim prevents concurrent or ambiguous reply retries. */
export async function replyToPublished(recordPath: string, getToken: () => Promise<string>,
publish: typeof publishReply = publishReply) {
const record = JSON.parse(await readFile(recordPath, 'utf8'));
if (record.status !== 'published' || !record.postId || !record.imagesDeletedAt || !record.replyText) return;
const replyPath = `${recordPath}.reply.json`;
try {
const existing = JSON.parse(await readFile(replyPath, 'utf8'));
if (existing.status !== 'published') console.warn(`Reply outcome unknown; inspect ${replyPath} before retrying`);
return;
} catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
const token = await getToken();
const replyId = await publish(token, record.postId, record.replyText, record.replyUrl, async containerId => {
await writeFile(replyPath, JSON.stringify({ status: 'publishing', postId: record.postId, containerId }, null, 2),
{ flag: 'wx', mode: 0o600 });
});
const temporary = `${replyPath}.${randomUUID()}.tmp`;
await writeFile(temporary, JSON.stringify({ status: 'published', postId: record.postId, replyId }, null, 2), { mode: 0o600 });
await rename(temporary, replyPath);
console.log(`Threads reply published: ${replyId}`);
}