import { randomUUID } from "node:crypto"; const transactionPaidEvents = new Map(); const transactionPaidIndex = new Map(); const transactionPaidSubscribers = new Set(); function nowIso() { return new Date().toISOString(); } function cloneInternalEvent(event) { return { ...event, payload_json: { ...event.payload_json } }; } export function subscribeTransactionPaid(handler) { transactionPaidSubscribers.add(handler); return () => transactionPaidSubscribers.delete(handler); } export function emitTransactionPaid(payload) { const existingId = transactionPaidIndex.get(payload.transaction_id); if (existingId) { const events = transactionPaidEvents.get(payload.transaction_id) || []; const existing = events.find((event) => event.id === existingId); if (existing) { return cloneInternalEvent(existing); } } const event = { id: randomUUID(), event_type: "transaction.paid", transaction_id: payload.transaction_id, payload_json: payload, created_at: nowIso() }; const bucket = transactionPaidEvents.get(payload.transaction_id) || []; bucket.push(event); transactionPaidEvents.set(payload.transaction_id, bucket); transactionPaidIndex.set(payload.transaction_id, event.id); const frozen = cloneInternalEvent(event); for (const listener of Array.from(transactionPaidSubscribers)) { listener(frozen); } return frozen; } export function getTransactionPaidEvents(transactionId) { if (transactionId) { return (transactionPaidEvents.get(transactionId) || []).map(cloneInternalEvent); } return Array.from(transactionPaidEvents.values()).flatMap((bucket) => bucket.map(cloneInternalEvent)); } export function getTransactionPaidEventByTransactionId(transactionId) { const events = transactionPaidEvents.get(transactionId) || []; return events.length > 0 ? cloneInternalEvent(events[events.length - 1]) : null; }