#!/usr/bin/env node import process from "node:process"; import { PrismaClient } from "../../server/node_modules/@prisma/client/index.js"; function parseThresholds() { const arg = process.argv.find((item) => item.startsWith("--thresholds=")); const raw = arg ? arg.slice("--thresholds=".length) : "2,5,10"; return raw .split(",") .map((item) => Number(item.trim())) .filter((item) => Number.isFinite(item) && item > 0) .sort((a, b) => a - b); } function minutesAgo(minutes) { return new Date(Date.now() - minutes * 60_000); } async function main() { if (!process.env.DATABASE_URL) { console.log("[pending-ocr][SKIP] missing DATABASE_URL"); return; } const thresholds = parseThresholds(); const prisma = new PrismaClient(); try { const summary = []; for (const minutes of thresholds) { const where = { status: "pending_ocr", created_at: { lte: minutesAgo(minutes) }, }; const count = await prisma.invoicePool.count({ where }); const rows = await prisma.invoicePool.findMany({ where, orderBy: { created_at: "asc" }, take: 50, select: { id: true, created_at: true, updated_at: true, ocr_attempts: true, ocr_last_requested_at: true, ocr_last_error: true, ocr_locked_at: true, ocr_lock_owner: true, }, }); summary.push({ thresholdMinutes: minutes, count, sampleLimit: 50, items: rows.map((item) => ({ id: item.id, createdAt: item.created_at?.toISOString?.() ?? null, updatedAt: item.updated_at?.toISOString?.() ?? null, attempts: item.ocr_attempts ?? 0, lastRequestedAt: item.ocr_last_requested_at?.toISOString?.() ?? null, lastError: item.ocr_last_error ?? null, lockedAt: item.ocr_locked_at?.toISOString?.() ?? null, lockOwner: item.ocr_lock_owner ?? null, })), }); } console.log(JSON.stringify({ ok: true, thresholds: summary }, null, 2)); } finally { await prisma.$disconnect(); } } main().catch((error) => { console.error(`[pending-ocr][FAIL] ${error instanceof Error ? error.message : String(error)}`); process.exit(1); });