// Post Lifecycle Tracker // Streams post events from the Bluesky network, focusing on the interesting // ones: edits and deletes. Creates are counted silently and shown in a // periodic stats line. Use --all to print every create too. // Demonstrates: parsePost, parsePostUpdate, parsePostDelete, toBskyUrl. // // Usage: npx tsx examples/post-lifecycle.ts [options] // Options: // --all Print creates, updates, and deletes // --creates-only Print only creates // --updates-only Print only updates // --deletes-only Print only deletes import { startStreamWithReconnect, parsePost, parsePostUpdate, parsePostDelete, toBskyUrl, formatTruncated, } from "../lib/index.js"; import type { PostData, PostUpdateData, PostDeleteData } from "../lib/index.js"; // --- Config --- const args = new Set(process.argv.slice(2)); const printCreates = args.has("--all") || args.has("--creates-only"); const printUpdates = !args.has("--creates-only") && !args.has("--deletes-only"); const printDeletes = !args.has("--creates-only") && !args.has("--updates-only"); const STATS_INTERVAL_MS = 10_000; // --- Counters --- let creates = 0; let updates = 0; let deletes = 0; const stats = () => `[C:${creates} U:${updates} D:${deletes}]`; // --- Formatters --- const formatCreate = (post: PostData): string => { const text = formatTruncated(post.text, 100); const url = toBskyUrl(post.did, post.rkey); return [ `+ CREATE ${stats()}`, ` ${text}`, ` ${url}`, ].join("\n"); }; const formatUpdate = (post: PostUpdateData): string => { const text = formatTruncated(post.text, 100); const url = toBskyUrl(post.did, post.rkey); return [ `~ UPDATE ${stats()}`, ` ${text}`, ` cid: ${post.cid}`, ` ${url}`, ].join("\n"); }; const formatDelete = (post: PostDeleteData): string => { return [ `- DELETE ${stats()}`, ` ${post.uri}`, ` did: ${post.did}`, ].join("\n"); }; // --- Stats timer --- let lastStats = { creates: 0, updates: 0, deletes: 0 }; const printStats = () => { const dc = creates - lastStats.creates; const du = updates - lastStats.updates; const dd = deletes - lastStats.deletes; const elapsed = STATS_INTERVAL_MS / 1000; console.log( ` --- ${stats()} | last ${elapsed}s: +${dc} creates, ~${du} updates, -${dd} deletes (${(dc / elapsed).toFixed(0)} posts/sec) ---\n` ); lastStats = { creates, updates, deletes }; }; // --- Stream --- startStreamWithReconnect({ config: { wantedCollections: ["app.bsky.feed.post"] }, onEvent: (event) => { const created = parsePost(event); if (created) { creates++; if (printCreates) console.log(formatCreate(created) + "\n"); return; } const updated = parsePostUpdate(event); if (updated) { updates++; if (printUpdates) console.log(formatUpdate(updated) + "\n"); return; } const deleted = parsePostDelete(event); if (deleted) { deletes++; if (printDeletes) console.log(formatDelete(deleted) + "\n"); } }, onOpen: () => { const showing = [ printCreates && "creates", printUpdates && "updates", printDeletes && "deletes", ].filter(Boolean).join(", "); console.log(`Connected. Printing: ${showing}. Stats every ${STATS_INTERVAL_MS / 1000}s.\n`); }, }); setInterval(printStats, STATS_INTERVAL_MS);