/** * Smoke test for the quote-item insights backfill. * * What it does * ──────────── * 1. Captures the existing `ai_item_insights` blob (so we can restore). * 2. Calls `populateQuoteItemInsights` on the target id, write=true. * 3. Re-reads the row and prints the new blob. * 4. Restores the original blob (best-effort) so the test is non-destructive. * * Run with: * npx tsx scripts/smoke/populate-quote-item-insights.ts * * Requires .env.local with NEXT_PUBLIC_POCKETBASE_URL, PB_ADMIN_EMAIL, * PB_ADMIN_PASSWORD. */ import "./_env"; // MUST be first import { populateQuoteItemInsights } from "../../src/lib/server/quote-items-insights-service"; import { getAdminPocketBase } from "../../src/lib/server/pocketbase-admin"; // Edit this id to point at a different item. const TARGET_ITEM_ID = process.env.TARGET_ITEM_ID || "6zvr769y6210qe0"; async function main() { console.log(`=== Populate insights for quote_item ${TARGET_ITEM_ID} ===\n`); const pb = await getAdminPocketBase(); // 1. Capture original blob for restore. const original = await pb.collection("quote_items").getOne<{ id: string; sku: string; description: string; ai_item_insights: unknown; }>(TARGET_ITEM_ID, { fields: "id,sku,description,ai_item_insights" }); console.log(`Target: ${original.description}`); console.log(`SKU: "${original.sku}"`); console.log( `Existing ai_item_insights (truncated):`, JSON.stringify(original.ai_item_insights).slice(0, 200), ); console.log(); // 2. Run the populate. const t0 = Date.now(); const result = await populateQuoteItemInsights(TARGET_ITEM_ID, { write: true }); const elapsed = Date.now() - t0; console.log(`\nDone in ${elapsed}ms.`); console.log(`match_kind: ${result.match_kind}`); console.log(`found_data: ${result.found_data}`); console.log(); console.log(`summary: ${result.insights.summary}`); console.log(); // 3. Re-read to confirm persistence. const reread = await pb.collection("quote_items").getOne<{ ai_item_insights: { summary?: string; generated_at?: string }; updated: string; }>(TARGET_ITEM_ID, { fields: "ai_item_insights,updated" }); console.log( `Persisted? ${JSON.stringify(reread.ai_item_insights?.summary) === JSON.stringify(result.insights.summary) ? "YES" : "NO"}`, ); console.log(`Updated at: ${reread.updated}`); console.log(); // 4. Pretty-print the blob so the operator can sanity-check it. console.log("=== Persisted blob ==="); console.log(JSON.stringify(reread.ai_item_insights, null, 2)); // 5. Restore the original blob UNLESS the operator asked us to keep // the populated version. Set KEEP_POPULATED=1 to leave the new // blob in place — that's the default for the user's request to // "try and fill one in". Unset to run safely as a smoke. if (!process.env.KEEP_POPULATED) { try { await pb.collection("quote_items").update(TARGET_ITEM_ID, { ai_item_insights: original.ai_item_insights ?? null, }); console.log("\n[cleanup] Original blob restored (KEEP_POPULATED not set)."); } catch (err) { console.warn( "\n[cleanup] Failed to restore original blob:", err instanceof Error ? err.message : String(err), ); } } else { console.log("\n[kept] KEEP_POPULATED=1 — populated blob stays in PB."); } } main().catch((err) => { console.error("\nFAILED:", err); process.exit(1); });