localgreenchain/pages/api/transparency/events.ts
Claude 0fcc2763fe
Add comprehensive transparency system for LocalGreenChain
This commit introduces a complete transparency infrastructure including:

Core Transparency Modules:
- AuditLog: Immutable, cryptographically-linked audit trail for all actions
- EventStream: Real-time SSE streaming and webhook support
- TransparencyDashboard: Aggregated metrics and system health monitoring
- DigitalSignatures: Cryptographic verification for handoffs and certificates

API Endpoints:
- /api/transparency/dashboard - Full platform metrics
- /api/transparency/audit - Query and log audit entries
- /api/transparency/events - SSE stream and event history
- /api/transparency/webhooks - Webhook management
- /api/transparency/signatures - Digital signature operations
- /api/transparency/certificate/[plantId] - Plant authenticity certificates
- /api/transparency/export - Multi-format data export
- /api/transparency/report - Compliance reporting
- /api/transparency/health - System health checks

Features:
- Immutable audit logging with chain integrity verification
- Real-time event streaming via Server-Sent Events
- Webhook support with HMAC signature verification
- Digital signatures for transport handoffs and ownership transfers
- Certificate of Authenticity generation for plants
- Multi-format data export (JSON, CSV, summary)
- Public transparency portal at /transparency
- System health monitoring for all components

Documentation:
- Comprehensive TRANSPARENCY.md guide with API examples
2025-11-23 03:29:56 +00:00

130 lines
3.4 KiB
TypeScript

/**
* Event Stream API
* GET /api/transparency/events - Get recent events or SSE stream
* POST /api/transparency/events - Emit a custom event
*
* Provides real-time event streaming for transparency.
*/
import type { NextApiRequest, NextApiResponse } from 'next';
import { getEventStream, TransparencyEventType, EventPriority } from '../../../lib/transparency';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const eventStream = getEventStream();
if (req.method === 'GET') {
const { stream, types, limit = '50', start, end } = req.query;
// Server-Sent Events mode
if (stream === 'true') {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const connectionId = `sse_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
// Send initial connection event
res.write(`event: connected\ndata: ${JSON.stringify({ connectionId })}\n\n`);
// Register SSE callback
eventStream.registerSSE(connectionId, (event) => {
try {
res.write(eventStream.formatSSE(event));
} catch {
// Connection closed
eventStream.unregisterSSE(connectionId);
}
});
// Handle client disconnect
req.on('close', () => {
eventStream.unregisterSSE(connectionId);
});
// Keep connection alive
const keepAlive = setInterval(() => {
try {
res.write(': keepalive\n\n');
} catch {
clearInterval(keepAlive);
eventStream.unregisterSSE(connectionId);
}
}, 30000);
return;
}
// Regular GET - return recent events
try {
const typeList = types ? (types as string).split(',') as TransparencyEventType[] : undefined;
let events;
if (start && end) {
events = eventStream.getByTimeRange(
start as string,
end as string,
{
types: typeList,
limit: parseInt(limit as string, 10)
}
);
} else {
events = eventStream.getRecent(parseInt(limit as string, 10), typeList);
}
return res.status(200).json({
success: true,
data: {
events,
count: events.length,
availableTypes: eventStream.getAvailableEventTypes()
}
});
} catch (error) {
console.error('[API] Events error:', error);
return res.status(500).json({
success: false,
error: 'Failed to fetch events'
});
}
}
if (req.method === 'POST') {
try {
const { type, source, data, priority, metadata } = req.body;
if (!type || !source || !data) {
return res.status(400).json({
success: false,
error: 'Missing required fields: type, source, data'
});
}
const event = eventStream.emit(
type as TransparencyEventType,
source,
data,
{
priority: priority as EventPriority,
metadata
}
);
return res.status(201).json({
success: true,
data: event
});
} catch (error) {
console.error('[API] Event emit error:', error);
return res.status(500).json({
success: false,
error: 'Failed to emit event'
});
}
}
return res.status(405).json({ error: 'Method not allowed' });
}