/** * Push structured timeline events to vibn-frontend (Postgres via ingest API). * Complements PATCH output lines — enables SSE replay without polling every line. */ import { randomUUID } from 'crypto'; export interface IngestEventInput { type: string; payload?: Record; ts?: string; } export async function ingestSessionEvents( vibnApiUrl: string, projectId: string, sessionId: string, events: IngestEventInput[] ): Promise { if (events.length === 0) return; const secret = process.env.AGENT_RUNNER_SECRET ?? ''; const base = vibnApiUrl.replace(/\/$/, ''); const url = `${base}/api/projects/${projectId}/agent/sessions/${sessionId}/events`; try { const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-agent-runner-secret': secret, }, body: JSON.stringify({ events: events.map((e) => ({ clientEventId: randomUUID(), ts: e.ts ?? new Date().toISOString(), type: e.type, payload: e.payload ?? {}, })), }), }); if (!res.ok) { const t = await res.text(); console.warn('[ingest-events]', res.status, t.slice(0, 240)); } } catch (err) { console.warn('[ingest-events]', err instanceof Error ? err.message : err); } }