import { writeFileSync } from "node:fs"; import { resolve } from "node:path"; import type { FieldDescription, JsonValue } from "@arco/clarizen-lib"; import type { EntityChoice } from "../metadata/picker.js"; import { formatFilterSummary, type EntityFilter } from "../query/filter.js"; import type { EntityRecord } from "../query/fetch-all.js"; import type { BulkUpdateResult } from "../update/bulk-field.js"; export interface RunLogEntry { id: string; displayName?: string; status: "updated" | "error"; message?: string; errorCode?: string; } export interface RunLog { executedAt: string; durationMs: number; userId: string; operation: { typeName: string; typeLabel?: string; filter: string; fieldName: string; fieldLabel?: string; fieldType?: string; value: JsonValue; }; summary: { total: number; updated: number; errors: number; }; results: RunLogEntry[]; } export interface BuildRunLogParams { startedAt: number; userId: string; entityChoice: EntityChoice; entityFilter: EntityFilter; field: FieldDescription; fieldName: string; parsedValue: JsonValue; records: EntityRecord[]; result: BulkUpdateResult; } function logTimestamp(): string { return new Date().toISOString().replace(/[:.]/g, "-"); } export function buildRunLog(params: BuildRunLogParams): RunLog { const { startedAt, userId, entityChoice, entityFilter, field, fieldName, parsedValue, records, result, } = params; const errorsById = new Map( result.errors.map((e) => [String(e.id), e] as const), ); const results: RunLogEntry[] = records.map((record) => { const id = String(record.id); const error = errorsById.get(id); if (error) { return { id, displayName: record.displayName, status: "error", message: error.message, errorCode: error.errorCode, }; } return { id, displayName: record.displayName, status: "updated", }; }); return { executedAt: new Date().toISOString(), durationMs: Date.now() - startedAt, userId, operation: { typeName: entityChoice.typeName, typeLabel: entityChoice.label, filter: formatFilterSummary(entityFilter), fieldName, fieldLabel: field.label, fieldType: field.type, value: parsedValue, }, summary: { total: records.length, updated: result.updated, errors: result.errors.length, }, results, }; } export function writeRunLog(log: RunLog, cwd = process.cwd()): string { const filePath = resolve(cwd, `run-log-${logTimestamp()}.json`); writeFileSync(filePath, JSON.stringify(log, null, 2), "utf-8"); return filePath; }