Files
markdownblog/src/app/api/posts/webhook/route.ts

62 lines
2.1 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
// Prevent static generation of this route
export const dynamic = 'force-dynamic';
export const runtime = 'nodejs';
// Store connected clients for webhook notifications
const webhookClients = new Set<{ id: string; controller: ReadableStreamDefaultController }>();
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const clientId = searchParams.get('clientId') || Math.random().toString(36).substr(2, 9);
const stream = new ReadableStream({
start(controller) {
// Add this client to the set
webhookClients.add({ id: clientId, controller });
// Send initial connection message
controller.enqueue(`data: ${JSON.stringify({ type: 'connected', clientId, message: 'Webhook connection established' })}\n\n`);
// Clean up when client disconnects
request.signal.addEventListener('abort', () => {
webhookClients.delete({ id: clientId, controller });
});
}
});
return new NextResponse(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Cache-Control'
}
});
}
// Webhook endpoint that can be called when files change
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { type = 'update', slug } = body;
// Notify all connected clients
const message = JSON.stringify({ type, slug, timestamp: new Date().toISOString() });
webhookClients.forEach(({ controller }) => {
try {
controller.enqueue(`data: ${message}\n\n`);
} catch (error) {
// Remove disconnected clients
webhookClients.delete({ id: '', controller });
}
});
return NextResponse.json({ success: true, clientsNotified: webhookClients.size });
} catch (error) {
console.error('Webhook error:', error);
return NextResponse.json({ error: 'Invalid webhook payload' }, { status: 400 });
}
}