import { writeFile } from "node:fs/promises";
import { call, download, waitRun } from "./retriever.mjs";
const batchId = "crm-enrich-2026-09-15"; // stable id you choose
const crmAccounts = [
{ name: "Acme", domain: "acme.example" },
{ name: "Beta", domain: "beta.example" },
];
// 1. Workspace and import (once per batch: store the ids)
const ws = await call("/v1/workspaces", { method: "POST", body: { name: `Enrichment ${batchId}` } });
const table = await call(`/v1/workspaces/${ws.id}/tables`, {
method: "POST",
body: {
name: "CRM accounts",
columns: [
{ key: "name", name: "Company" },
{ key: "domain", name: "Domain" },
],
// send only fields declared as columns
rows: crmAccounts.map(({ name, domain }) => ({ name, domain })),
},
});
// 2. Targeted run. Idempotency key depends on the batch, not an id generated on each run.
const run = await call("/v1/runs", {
method: "POST",
headers: { "Idempotency-Key": `${batchId}:run` },
body: {
workspace_id: ws.id,
prompt: `For each company in table ${table.id}, find the CEO name and LinkedIn profile URL. Publish one row per company.`,
output: {
type: "tables",
tables: [{
key: "contacts",
row_schema: {
type: "object",
required: ["domain", "ceo_name", "ceo_linkedin_url"],
properties: {
domain: { type: "string" },
ceo_name: { type: ["string", "null"] },
ceo_linkedin_url: { type: ["string", "null"] },
},
},
}],
},
},
});
const done = await waitRun(run.id);
if (done.status !== "completed") throw new Error(done.error?.message ?? done.status);
// 3. CSV export of the frozen table
const exp = await call(`/v1/runs/${run.id}/exports`, { method: "POST", body: { table_key: "contacts", format: "csv" } });
await writeFile("contacts.csv", await download(exp.links.self));