← back to Govarbitrage

scripts/import-govdeals-free.ts

51 lines

// FREE daily GovDeals refresh — hits GovDeals' own backend API directly ($0,
// no Apify, no browser). Replaces the paid Apify path.
//
// Usage: npx tsx scripts/import-govdeals-free.ts [limit]   (default 120)

import { fetchGovdealsFree } from "../src/importers/govdeals-free";
import { ingestMany } from "../src/importers/ingest";
import { prisma } from "../src/lib/db";

// Liquidity Services marketplaces, all on the same free API. GovDeals gets the
// most; the industrial siblings a smaller slice.
const MARKETS: { biz: string; limit: number }[] = [
  { biz: "GD", limit: Number(process.argv[2] || 120) },
  { biz: "GI", limit: 60 },
  { biz: "NI", limit: 60 },
];

async function main() {
  let created = 0, updated = 0, failed = 0, fetched = 0, marketErrors = 0;
  for (const { biz, limit } of MARKETS) {
    console.log(`[${new Date().toISOString()}] Fetching ${limit} newest ${biz} listings (FREE maestro API)…`);
    // Isolate each market: one market's transient failure must not abort the
    // siblings in the same run.
    try {
      const rows = await fetchGovdealsFree({ limit, businessId: biz });
      fetched += rows.length;
      const results = await ingestMany(rows, { useAI: false });
      created += results.filter((r) => r.ok && r.created).length;
      updated += results.filter((r) => r.ok && !r.created).length;
      failed += results.filter((r) => !r.ok).length;
    } catch (e) {
      marketErrors++;
      console.error(`  ✗ market ${biz} failed:`, e instanceof Error ? e.message : e);
    }
  }
  console.log(`Done: fetched ${fetched}, ${created} created, ${updated} updated, ${failed} failed, ${marketErrors} market(s) errored. Cost: $0 (free API).`);
  // Fail the run (non-zero exit) so a scheduler sees red when nothing was
  // fetched or every market errored — not a false "success".
  if (fetched === 0 || marketErrors === MARKETS.length) {
    console.error(`[import-govdeals-free] RUN FAILED: fetched ${fetched}, ${marketErrors}/${MARKETS.length} markets errored.`);
    process.exitCode = 1;
  }
  await prisma.$disconnect();
}

main().catch(async (e) => {
  console.error("[import-govdeals-free] ERROR:", e.message);
  await prisma.$disconnect();
  process.exit(1);
});