#!/usr/bin/env node // scripts/inspect-org-custom-fields.mjs // // Dumps the CustomField metadata for the "Food_Co_op_Organizing" custom // group (attached to Organization contacts) so we can wire the right // machine names + types into config/form.ts. // // USAGE // node --env-file=.env.local scripts/inspect-org-custom-fields.mjs const GROUP = "Food_Co_op_Organizing"; async function civi(entity, action, params) { const { CIVI_BASE_URL, CIVI_API_KEY, CIVI_SITE_KEY, CIVI_HTTP_AUTH_USER, CIVI_HTTP_AUTH_PASS, } = process.env; if (!CIVI_BASE_URL || !CIVI_API_KEY || !CIVI_SITE_KEY) { throw new Error("Missing CIVI_BASE_URL / CIVI_API_KEY / CIVI_SITE_KEY."); } const url = `${CIVI_BASE_URL}/civicrm/ajax/api4/${entity}/${action}`; const headers = { "Content-Type": "application/x-www-form-urlencoded", "X-Civi-Auth": `Bearer ${CIVI_API_KEY}`, "X-Civi-Key": CIVI_SITE_KEY, }; if (CIVI_HTTP_AUTH_USER && CIVI_HTTP_AUTH_PASS) { headers["Authorization"] = "Basic " + Buffer.from(`${CIVI_HTTP_AUTH_USER}:${CIVI_HTTP_AUTH_PASS}`).toString("base64"); } const res = await fetch(url, { method: "POST", headers, body: new URLSearchParams({ params: JSON.stringify(params) }), }); if (!res.ok) { throw new Error(`${entity}.${action} HTTP ${res.status}: ${await res.text()}`); } return res.json(); } const result = await civi("CustomField", "get", { select: [ "name", "label", "data_type", "html_type", "is_active", "option_group_id", "custom_group_id.name", "custom_group_id.extends", ], where: [["custom_group_id.name", "=", GROUP]], orderBy: { weight: "ASC" }, limit: 0, }); const rows = result.values ?? []; console.log(`Custom group: ${GROUP}`); if (rows.length) { console.log(`Extends: ${rows[0]["custom_group_id.extends"]}`); } console.log(`Found ${rows.length} fields:\n`); for (const f of rows) { console.log( `- name=${f.name} label="${f.label}" data_type=${f.data_type} html_type=${f.html_type} option_group_id=${f.option_group_id ?? "-"} active=${f.is_active}`, ); }