/** * Discover users from relays and backfill their records from PDS. * * Usage: * npx tsx sync.ts # local D1 * npx tsx sync.ts --remote # prod D1 */ import { Contrail } from "@atmo-dev/contrail"; import { config } from "./config"; import { getPlatformProxy } from "wrangler"; function elapsed(start: number): string { const ms = Date.now() - start; if (ms < 1000) return `${ms}ms`; if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`; const mins = Math.floor(ms / 60_000); const secs = ((ms % 60_000) / 1000).toFixed(0); return `${mins}m ${secs}s`; } async function main() { const remote = process.argv.includes("--remote"); const syncStart = Date.now(); console.log(`=== Sync (${remote ? "remote/prod" : "local"} D1) ===\n`); const { env, dispose } = await getPlatformProxy<{ DB: D1Database }>({ environment: remote ? "production" : undefined, }); const contrail = new Contrail({ ...config, db: env.DB }); try { await contrail.init(); console.log("--- Discovery ---"); const discoveryStart = Date.now(); const discovered = await contrail.discover(); console.log(` Done: ${discovered.length} users in ${elapsed(discoveryStart)}\n`); console.log("--- Backfill ---"); const backfillStart = Date.now(); const total = await contrail.backfill({ concurrency: 100, onProgress: ({ records, usersComplete, usersTotal, usersFailed }) => { const secs = (Date.now() - backfillStart) / 1000; const rate = secs > 0 ? Math.round(records / secs) : 0; const failStr = usersFailed > 0 ? ` | ${usersFailed} failed` : ""; process.stdout.write( `\r ${records} records | ${usersComplete}/${usersTotal} users | ${rate}/s | ${elapsed(backfillStart)}${failStr} ` ); }, }); process.stdout.write("\n"); console.log(` Done: ${total} records in ${elapsed(backfillStart)}\n`); console.log(`=== Finished in ${elapsed(syncStart)} ===`); console.log(` Discovered: ${discovered.length} users`); console.log(` Backfilled: ${total} records`); } finally { await dispose(); } } main().catch((err) => { console.error(err); process.exit(1); });