server-sent-events — server-sent events install server-sent-events, community, server-sent events install, ide skills, real-time server-to-client streaming, Claude Code, Cursor, Windsurf

v1.0.0
GitHub

About this Skill

Ideal for Real-Time Update Agents requiring unidirectional server-to-client communication for progress updates and live data feeds. Server-sent events is a technology for real-time server-to-client streaming, allowing for progress updates, live feeds, and notifications over HTTP.

Features

Enables real-time server-to-client streaming for progress updates and live data feeds
Supports unidirectional communication, ideal for server-to-client only use cases
Provides an alternative to WebSockets for simpler, stateless communication
Offers a more efficient solution than Polling for real-time updates
Allows for limited connections, suitable for applications with moderate traffic
Enables live feeds and notifications over HTTP

# Core Topics

vuthuonghai-steve vuthuonghai-steve
[0]
[0]
Updated: 3/8/2026

Agent Capability Analysis

The server-sent-events skill by vuthuonghai-steve is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance. Optimized for server-sent events install, real-time server-to-client streaming.

Ideal Agent Persona

Ideal for Real-Time Update Agents requiring unidirectional server-to-client communication for progress updates and live data feeds.

Core Value

Empowers agents to establish real-time server-sent event streams for progress updates, notifications, and live data feeds using SSE, enabling efficient unidirectional communication and leveraging HTTP protocol for simplicity.

Capabilities Granted for server-sent-events

Streaming live updates to clients
Sending progress notifications for long-running tasks
Broadcasting real-time data feeds

! Prerequisites & Limits

  • Unidirectional communication only
  • Limited connections
  • Not suitable for bidirectional communication or complex stateful interactions
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

server-sent-events

Install server-sent-events, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command setup.

SKILL.md
Readonly

Server-Sent Events (SSE)

Real-time server-to-client streaming for progress updates, notifications, and live data feeds.

When to Use SSE vs Alternatives

TechnologyUse WhenLimitations
SSEServer → Client only, progress updates, live feedsUnidirectional, limited connections
WebSocketsBidirectional chat, gaming, collaborationMore complex, stateful
PollingSimple updates, wide compatibilityInefficient, latency
HTTP StreamingLarge file downloadsNo structured events

Choose SSE for: Progress bars, status updates, notifications, log streaming, live dashboards.


Next.js App Router Implementation

Server-Side (Route Handler)

typescript
1// app/api/progress/route.ts 2import { NextRequest } from 'next/server' 3 4interface SSEMessage { 5 progress: number 6 message: string 7 status: 'progress' | 'complete' | 'error' 8} 9 10export async function POST(req: NextRequest) { 11 const body = await req.json() 12 13 // SSE Response Headers 14 const headers = { 15 'Content-Type': 'text/event-stream', 16 'Cache-Control': 'no-cache', 17 'Connection': 'keep-alive', 18 } 19 20 // Create transform stream for SSE 21 const stream = new TransformStream() 22 const writer = stream.writable.getWriter() 23 const encoder = new TextEncoder() 24 25 // Helper to send SSE messages 26 async function sendSSE(data: SSEMessage) { 27 await writer.write(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)) 28 } 29 30 // Execute work with progress updates (async, don't await) 31 ;(async () => { 32 try { 33 await sendSSE({ progress: 0, message: 'Starting...', status: 'progress' }) 34 35 // Simulate work with progress updates 36 for (let i = 1; i <= 10; i++) { 37 await doSomeWork(i) 38 await sendSSE({ 39 progress: i * 10, 40 message: `Processing step ${i} of 10...`, 41 status: 'progress' 42 }) 43 } 44 45 await sendSSE({ progress: 100, message: 'Complete!', status: 'complete' }) 46 } catch (error) { 47 const message = error instanceof Error ? error.message : 'Unknown error' 48 await sendSSE({ progress: 0, message, status: 'error' }) 49 } finally { 50 await writer.close() 51 } 52 })() 53 54 return new Response(stream.readable, { headers }) 55}

Client-Side Consumption

typescript
1// React component 2'use client' 3 4import { useState } from 'react' 5 6interface ProgressState { 7 progress: number 8 message: string 9 status: 'idle' | 'progress' | 'complete' | 'error' 10} 11 12export function ProgressTracker() { 13 const [state, setState] = useState<ProgressState>({ 14 progress: 0, 15 message: '', 16 status: 'idle' 17 }) 18 19 async function startProcess() { 20 setState({ progress: 0, message: 'Connecting...', status: 'progress' }) 21 22 const response = await fetch('/api/progress', { 23 method: 'POST', 24 headers: { 'Content-Type': 'application/json' }, 25 body: JSON.stringify({ /* request data */ }) 26 }) 27 28 if (!response.body) { 29 setState({ progress: 0, message: 'No response body', status: 'error' }) 30 return 31 } 32 33 const reader = response.body.getReader() 34 const decoder = new TextDecoder() 35 let buffer = '' 36 37 while (true) { 38 const { done, value } = await reader.read() 39 if (done) break 40 41 buffer += decoder.decode(value, { stream: true }) 42 43 // Parse SSE messages from buffer 44 const lines = buffer.split('\n\n') 45 buffer = lines.pop() || '' // Keep incomplete message in buffer 46 47 for (const line of lines) { 48 if (line.startsWith('data: ')) { 49 const data = JSON.parse(line.slice(6)) 50 setState({ 51 progress: data.progress, 52 message: data.message, 53 status: data.status 54 }) 55 } 56 } 57 } 58 } 59 60 return ( 61 <div> 62 <button onClick={startProcess} disabled={state.status === 'progress'}> 63 Start Process 64 </button> 65 <progress value={state.progress} max={100} /> 66 <p>{state.message}</p> 67 </div> 68 ) 69}

SSE Message Format

Standard Format

data: {"key": "value"}\n\n

Rules:

  • Each message ends with \n\n (double newline)
  • Data line starts with data:
  • Multiple data lines allowed per message
  • Optional event:, id:, retry: fields

Named Events

typescript
1// Server 2async function sendNamedEvent(event: string, data: object) { 3 await writer.write(encoder.encode( 4 `event: ${event}\ndata: ${JSON.stringify(data)}\n\n` 5 )) 6} 7 8// Send different event types 9await sendNamedEvent('progress', { percent: 50 }) 10await sendNamedEvent('log', { message: 'Processing...' }) 11await sendNamedEvent('complete', { result: 'success' })
typescript
1// Client with EventSource (for GET endpoints) 2const source = new EventSource('/api/events') 3 4source.addEventListener('progress', (e) => { 5 const data = JSON.parse(e.data) 6 console.log('Progress:', data.percent) 7}) 8 9source.addEventListener('complete', (e) => { 10 const data = JSON.parse(e.data) 11 console.log('Done:', data.result) 12 source.close() 13})

Vercel Considerations

Critical: Background Task Termination

<EXTREMELY-IMPORTANT> On Vercel, SSE works differently than traditional servers. The function stays alive while the stream is open, but you must manage the lifecycle carefully. </EXTREMELY-IMPORTANT>
typescript
1// CORRECT: Stream keeps function alive until closed 2;(async () => { 3 try { 4 // Do all work here 5 for (const item of items) { 6 await processItem(item) 7 await sendSSE({ progress: calculateProgress(item) }) 8 } 9 await sendSSE({ status: 'complete' }) 10 } finally { 11 await writer.close() // MUST close to end function 12 } 13})() 14 15return new Response(stream.readable, { headers })

Timeout Limits

PlanMax Duration
Hobby10 seconds
Pro60 seconds
Enterprise900 seconds

For long operations, consider:

  • Breaking into smaller chunks
  • Using background jobs (Vercel Cron, external queue)
  • Providing estimated time warnings

Progress Patterns

Percentage-Based

typescript
1interface PercentageProgress { 2 progress: number // 0-100 3 message: string 4 status: 'progress' | 'complete' | 'error' 5} 6 7// Calculate progress for known item count 8const total = items.length 9for (let i = 0; i < items.length; i++) { 10 await processItem(items[i]) 11 await sendSSE({ 12 progress: Math.floor(((i + 1) / total) * 100), 13 message: `Processing ${i + 1} of ${total}...`, 14 status: 'progress' 15 }) 16}

Phase-Based

typescript
1interface PhaseProgress { 2 phase: string 3 phaseProgress: number 4 overallProgress: number 5 message: string 6} 7 8const phases = [ 9 { name: 'validate', weight: 10 }, 10 { name: 'process', weight: 70 }, 11 { name: 'finalize', weight: 20 }, 12] 13 14// Track progress across phases 15let overallProgress = 0 16for (const phase of phases) { 17 await sendSSE({ 18 phase: phase.name, 19 phaseProgress: 0, 20 overallProgress, 21 message: `Starting ${phase.name}...` 22 }) 23 24 // Do phase work... 25 26 overallProgress += phase.weight 27}

Indeterminate with Logs

typescript
1interface LogProgress { 2 type: 'log' | 'warning' | 'error' | 'complete' 3 message: string 4 timestamp: string 5} 6 7// For operations where progress can't be calculated 8await sendSSE({ 9 type: 'log', 10 message: 'Connecting to external service...', 11 timestamp: new Date().toISOString() 12})

Error Handling

Server-Side

typescript
1;(async () => { 2 try { 3 await riskyOperation() 4 await sendSSE({ status: 'complete', message: 'Done!' }) 5 } catch (error) { 6 // Always send error to client before closing 7 await sendSSE({ 8 status: 'error', 9 message: error instanceof Error ? error.message : 'Unknown error', 10 progress: 0 11 }) 12 } finally { 13 // ALWAYS close the stream 14 await writer.close() 15 } 16})()

Client-Side

typescript
1async function consumeSSE(url: string, body: object) { 2 try { 3 const response = await fetch(url, { 4 method: 'POST', 5 body: JSON.stringify(body) 6 }) 7 8 if (!response.ok) { 9 throw new Error(`HTTP ${response.status}`) 10 } 11 12 // Process stream... 13 } catch (error) { 14 // Handle network errors, aborts, etc. 15 if (error.name === 'AbortError') { 16 console.log('Request cancelled') 17 } else { 18 console.error('SSE failed:', error) 19 } 20 } 21}

Cancellation

typescript
1// Client with AbortController 2const controller = new AbortController() 3 4const response = await fetch('/api/progress', { 5 method: 'POST', 6 body: JSON.stringify(data), 7 signal: controller.signal 8}) 9 10// Cancel button handler 11function handleCancel() { 12 controller.abort() 13}

Real-World Example: Batch Processing

typescript
1// app/api/batch/route.ts 2export async function POST(req: NextRequest) { 3 const { items } = await req.json() 4 5 const stream = new TransformStream() 6 const writer = stream.writable.getWriter() 7 const encoder = new TextEncoder() 8 9 const sendSSE = async (data: object) => { 10 await writer.write(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)) 11 } 12 13 ;(async () => { 14 const results = { success: 0, failed: 0, errors: [] as string[] } 15 16 try { 17 await sendSSE({ 18 status: 'progress', 19 progress: 0, 20 message: `Processing ${items.length} items...` 21 }) 22 23 for (let i = 0; i < items.length; i++) { 24 try { 25 await processItem(items[i]) 26 results.success++ 27 } catch (err) { 28 results.failed++ 29 results.errors.push(`Item ${i}: ${err.message}`) 30 } 31 32 await sendSSE({ 33 status: 'progress', 34 progress: Math.floor(((i + 1) / items.length) * 100), 35 message: `Processed ${i + 1} of ${items.length}`, 36 results: { ...results } 37 }) 38 } 39 40 await sendSSE({ 41 status: 'complete', 42 progress: 100, 43 message: `Complete: ${results.success} succeeded, ${results.failed} failed`, 44 results 45 }) 46 } catch (error) { 47 await sendSSE({ 48 status: 'error', 49 message: error instanceof Error ? error.message : 'Batch failed', 50 results 51 }) 52 } finally { 53 await writer.close() 54 } 55 })() 56 57 return new Response(stream.readable, { 58 headers: { 59 'Content-Type': 'text/event-stream', 60 'Cache-Control': 'no-cache', 61 'Connection': 'keep-alive', 62 } 63 }) 64}

Quick Reference

typescript
1// Minimal SSE endpoint 2export async function POST(req: NextRequest) { 3 const stream = new TransformStream() 4 const writer = stream.writable.getWriter() 5 const encoder = new TextEncoder() 6 7 ;(async () => { 8 await writer.write(encoder.encode(`data: {"message":"Hello"}\n\n`)) 9 await writer.close() 10 })() 11 12 return new Response(stream.readable, { 13 headers: { 'Content-Type': 'text/event-stream' } 14 }) 15}
typescript
1// Minimal client consumption 2const res = await fetch('/api/sse', { method: 'POST' }) 3const reader = res.body!.getReader() 4const decoder = new TextDecoder() 5 6while (true) { 7 const { done, value } = await reader.read() 8 if (done) break 9 console.log(decoder.decode(value)) 10}

Resources

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is server-sent-events?

Ideal for Real-Time Update Agents requiring unidirectional server-to-client communication for progress updates and live data feeds. Server-sent events is a technology for real-time server-to-client streaming, allowing for progress updates, live feeds, and notifications over HTTP.

How do I install server-sent-events?

Run the command: npx killer-skills add vuthuonghai-steve/KLTN. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for server-sent-events?

Key use cases include: Streaming live updates to clients, Sending progress notifications for long-running tasks, Broadcasting real-time data feeds.

Which IDEs are compatible with server-sent-events?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for server-sent-events?

Unidirectional communication only. Limited connections. Not suitable for bidirectional communication or complex stateful interactions.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add vuthuonghai-steve/KLTN. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use server-sent-events immediately in the current project.

Related Skills

Looking for an alternative to server-sent-events or another community skill for your workflow? Explore these related open-source skills.

View All

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI