26 lines
1.4 KiB
TypeScript
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}`);
|
|
}
|