JSPM

  • Created
  • Published
  • Downloads 392
  • Score
    100M100P100Q116931F
  • License Apache-2.0

Support for text/event-stream in Fetcher

Package Exports

  • @ahoo-wang/fetcher-eventstream

Readme

@ahoo-wang/fetcher-eventstream

npm version Build Status codecov License npm downloads

Support for text/event-stream in Fetcher, enabling Server-Sent Events (SSE) functionality.

Features

  • Event Stream Conversion: Converts text/event-stream responses to async generators of ServerSentEvent objects
  • Interceptor Integration: Automatically adds eventStream() method to responses with text/event-stream content type
  • SSE Parsing: Parses Server-Sent Events according to the specification, including data, event, id, and retry fields
  • Streaming Support: Handles chunked data and multi-line events correctly
  • TypeScript Support: Complete TypeScript type definitions

Installation

Using pnpm:

pnpm add @ahoo-wang/fetcher-eventstream

Using npm:

npm install @ahoo-wang/fetcher-eventstream

Using yarn:

yarn add @ahoo-wang/fetcher-eventstream

Usage

Basic Usage with Interceptor

import { Fetcher } from '@ahoo-wang/fetcher';
import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';

const fetcher = new Fetcher({
  baseURL: 'https://api.example.com',
});

// Add the event stream interceptor
fetcher.interceptors.response.use(new EventStreamInterceptor());

// Using the eventStream method on responses with text/event-stream content type
const response = await fetcher.get('/events');
if (response.eventStream) {
  for await (const event of response.eventStream()) {
    console.log('Received event:', event);
  }
}

Manual Conversion

import { EventStreamConverter } from '@ahoo-wang/fetcher-eventstream';

// Convert a Response object manually
const response = await fetch('/events');
const eventStream = EventStreamConverter.toEventStream(response);

// Read events from the stream
const reader = eventStream.getReader();
try {
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    console.log('Received event:', value);
  }
} finally {
  reader.releaseLock();
}

Async Iterator Usage

import { Fetcher } from '@ahoo-wang/fetcher';
import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';

const fetcher = new Fetcher({
  baseURL: 'https://api.example.com',
  interceptors: {
    response: [new EventStreamInterceptor()],
  },
});

// Using async iteration
const response = await fetcher.get('/events');
if (response.eventStream) {
  for await (const event of response.eventStream()) {
    switch (event.event) {
      case 'message':
        console.log('Message:', event.data);
        break;
      case 'notification':
        console.log('Notification:', event.data);
        break;
      default:
        console.log('Unknown event:', event);
    }
  }
}

API Reference

EventStreamConverter

A utility class for converting text/event-stream responses to readable streams.

toEventStream(response: Response): ServerEventStream

Converts a Response object with a text/event-stream body to a readable stream of ServerSentEvent objects.

Parameters:

  • response: The HTTP response with text/event-stream content type

Returns:

  • ServerEventStream: A readable stream of ServerSentEvent objects

EventStreamInterceptor

A response interceptor that automatically adds an eventStream() method to responses with text/event-stream content type.

intercept(response: Response): Response

Intercepts a response and adds the eventStream() method if the content type is text/event-stream.

Parameters:

  • response: The HTTP response to intercept

Returns:

  • Response: The intercepted response with added eventStream() method

ServerSentEvent

Interface defining the structure of a Server-Sent Event.

interface ServerSentEvent {
  data: string; // Event data (required)
  event?: string; // Event type (optional, defaults to 'message')
  id?: string; // Event ID (optional)
  retry?: number; // Retry timeout in milliseconds (optional)
}

ServerSentEventStream

Type alias for a readable stream of ServerSentEvent objects.

type ServerSentEventStream = ReadableStream<ServerSentEvent>;

Server-Sent Events Specification Compliance

This package fully implements the Server-Sent Events specification:

  • Data field: Supports multi-line data fields
  • Event field: Custom event types
  • ID field: Last event ID tracking
  • Retry field: Automatic reconnection timeout
  • Comment lines: Lines starting with : are ignored
  • Event dispatching: Proper event dispatching with default event type 'message'

Examples

Real-time Notifications

import { Fetcher } from '@ahoo-wang/fetcher';
import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';

const fetcher = new Fetcher({
  baseURL: 'https://api.example.com',
});
fetcher.interceptors.response.use(new EventStreamInterceptor());

// Listen for real-time notifications
const response = await fetcher.get('/notifications');
if (response.eventStream) {
  for await (const event of response.eventStream()) {
    switch (event.event) {
      case 'message':
        showNotification('Message', event.data);
        break;
      case 'alert':
        showAlert('Alert', event.data);
        break;
      case 'update':
        handleUpdate(JSON.parse(event.data));
        break;
    }
  }
}

Progress Updates

import { Fetcher } from '@ahoo-wang/fetcher';
import { EventStreamInterceptor } from '@ahoo-wang/fetcher-eventstream';

const fetcher = new Fetcher({
  baseURL: 'https://api.example.com',
});
fetcher.interceptors.response.use(new EventStreamInterceptor());

// Track long-running task progress
const response = await fetcher.get('/tasks/123/progress');
if (response.eventStream) {
  for await (const event of response.eventStream()) {
    if (event.event === 'progress') {
      const progress = JSON.parse(event.data);
      updateProgressBar(progress.percentage);
    } else if (event.event === 'complete') {
      showCompletionMessage(event.data);
      break;
    }
  }
}

Testing

To run tests for this package:

pnpm test

The test suite includes:

  • Event stream conversion tests
  • Interceptor functionality tests
  • Edge case handling (malformed events, chunked data, etc.)
  • Performance tests for large event streams

License

This project is licensed under the Apache-2.0 License.