or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-workbox-streams

A library that makes it easier to work with Streams in the browser.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/workbox-streams@7.3.x

To install, run

npx @tessl/cli install tessl/npm-workbox-streams@7.3.0

index.mddocs/

Workbox Streams

Workbox Streams provides utilities for working with ReadableStreams in service workers and web applications. It offers functions to concatenate multiple stream sources into a single ReadableStream, create HTTP responses from concatenated streams, detect browser support for streaming APIs, and implement streaming strategies for Workbox routing.

Package Information

  • Package Name: workbox-streams
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install workbox-streams

Core Imports

import {
  concatenate,
  concatenateToResponse,
  isSupported,
  strategy,
  type StreamSource,
  type StreamsHandlerCallback
} from "workbox-streams";

For CommonJS:

const {
  concatenate,
  concatenateToResponse,
  isSupported,
  strategy
} = require("workbox-streams");

Basic Usage

import {
  concatenate,
  concatenateToResponse,
  isSupported,
  strategy
} from "workbox-streams";

// Check browser support for streaming
if (isSupported()) {
  // Concatenate multiple stream sources
  const sourcePromises = [
    fetch('/api/header'),
    fetch('/api/content'),
    fetch('/api/footer')
  ];

  const {done, stream} = concatenate(sourcePromises);
  
  // Or create a Response directly
  const {done: responseDone, response} = concatenateToResponse(
    sourcePromises,
    {'content-type': 'text/html'}
  );
  
  // Use in service worker
  self.addEventListener('fetch', (event) => {
    event.waitUntil(responseDone);
    event.respondWith(response);
  });
}

Architecture

Workbox Streams is built around streaming and fallback patterns:

  • Stream Concatenation: Core functionality for combining multiple stream sources sequentially
  • Browser Compatibility: Automatic detection and fallback for browsers without streaming support
  • Workbox Integration: Strategy functions designed for use with Workbox routing
  • Response Creation: Utilities to convert streams into standard Response objects
  • Promise Tracking: Support for service worker waitUntil() patterns

Capabilities

Stream Concatenation

Combines multiple stream sources into a single ReadableStream with sequential data flow.

/**
 * Takes multiple source Promises and returns a ReadableStream with sequential data
 * @param sourcePromises - Array of Promises resolving to StreamSource objects
 * @returns Object with completion Promise and ReadableStream
 */
function concatenate(sourcePromises: Promise<StreamSource>[]): {
  done: Promise<void>;
  stream: ReadableStream;
};

Usage Example:

import { concatenate } from "workbox-streams";

const sourcePromises = [
  Promise.resolve(new Response('Hello ')),
  Promise.resolve(new Response('World!')),
  fetch('/api/data')
];

const {done, stream} = concatenate(sourcePromises);

// Use the stream
const response = new Response(stream, {
  headers: {'content-type': 'text/plain'}
});

// Wait for completion
await done;

Response Stream Concatenation

Creates an HTTP Response with body consisting of concatenated stream data.

/**
 * Takes multiple source Promises and returns a Response with concatenated data
 * @param sourcePromises - Array of Promises resolving to StreamSource objects
 * @param headersInit - Optional headers for the response (if no 'Content-Type', defaults to 'text/html')
 * @returns Object with completion Promise and Response
 */
function concatenateToResponse(
  sourcePromises: Promise<StreamSource>[],
  headersInit?: HeadersInit
): {
  done: Promise<void>;
  response: Response;
};

Usage Example:

import { concatenateToResponse } from "workbox-streams";

const sourcePromises = [
  fetch('/template/header'),
  fetch('/content/body'),
  fetch('/template/footer')
];

// With headers
const {done, response} = concatenateToResponse(
  sourcePromises,
  {
    'content-type': 'text/html',
    'cache-control': 'max-age=3600'
  }
);

// Without headers (defaults to 'text/html')
const {done: done2, response: response2} = concatenateToResponse(sourcePromises);

// Use in service worker
self.addEventListener('fetch', (event) => {
  if (event.request.url.endsWith('/composite-page')) {
    event.waitUntil(done);
    event.respondWith(response);
  }
});

Browser Support Detection

Determines whether the current browser supports streaming features.

/**
 * Checks if browser supports ReadableStream construction for streaming responses
 * @returns true if streaming is supported, false otherwise
 */
function isSupported(): boolean;

Usage Example:

import { isSupported, concatenateToResponse } from "workbox-streams";

function createCompositeResponse(sources: Promise<StreamSource>[], headers: HeadersInit) {
  if (isSupported()) {
    // Use streaming concatenation
    return concatenateToResponse(sources, headers);
  } else {
    // Fallback to waiting for all sources
    return Promise.all(sources).then(resolvedSources => {
      // Manual concatenation fallback
      return new Response(/* combined content */, {headers});
    });
  }
}

Workbox Strategy Integration

Creates a strategy function compatible with Workbox routing that handles streaming with automatic fallback.

/**
 * Creates a Workbox-compatible strategy for streaming responses with fallback
 * @param sourceFunctions - Array of handler functions returning StreamSource objects
 * @param headersInit - Optional headers for responses (if no 'Content-Type', defaults to 'text/html')
 * @returns RouteHandlerCallback compatible with Workbox routing
 */
function strategy(
  sourceFunctions: StreamsHandlerCallback[],
  headersInit?: HeadersInit
): RouteHandlerCallback;

Usage Example:

import { strategy } from "workbox-streams";
import { registerRoute } from "workbox-routing";

// Define source functions
const sourceFunctions = [
  // Header source
  ({url, request}) => fetch('/api/header'),
  // Dynamic content based on URL
  ({url, request}) => fetch(`/api/content${url.pathname}`),
  // Footer source
  ({url, request}) => fetch('/api/footer')
];

// Create streaming strategy with headers
const streamingStrategy = strategy(sourceFunctions, {
  'content-type': 'text/html',
  'cache-control': 'no-cache'
});

// Or without headers (defaults to 'text/html')
const basicStrategy = strategy(sourceFunctions);

// Register with Workbox routing
registerRoute(
  ({url}) => url.pathname.startsWith('/dynamic/'),
  streamingStrategy
);

Types

StreamSource

Union type representing valid stream sources.

/**
 * Valid source types for streaming operations
 */
type StreamSource = Response | ReadableStream | BodyInit;

Where BodyInit includes: Blob | BufferSource | FormData | URLSearchParams | string

StreamsHandlerCallback

Interface for handler functions used in streaming strategies.

/**
 * Handler function interface for streaming strategies
 */
interface StreamsHandlerCallback {
  (options: RouteHandlerCallbackOptions): Promise<StreamSource> | StreamSource;
}

/**
 * Generic object interface for key-value mapping (from workbox-core)
 */
interface MapLikeObject {
  [key: string]: any;
}

/**
 * Options passed to handler callbacks (from workbox-core)
 */
interface RouteHandlerCallbackOptions {
  event: ExtendableEvent;
  request: Request;
  url: URL;
  params?: string[] | MapLikeObject;
}

/**
 * Route handler callback interface (from workbox-core)
 */
interface RouteHandlerCallback {
  (options: RouteHandlerCallbackOptions): Promise<Response>;
}

Error Handling

Stream Processing Errors

When stream processing fails, errors are propagated through the Promise chain:

import { concatenate } from "workbox-streams";

const {done, stream} = concatenate([
  fetch('/api/source1'),
  fetch('/api/source2')
]);

// Handle errors in the completion promise
done.catch(error => {
  console.error('Stream concatenation failed:', error);
});

// Errors also propagate through the stream
const response = new Response(stream);
response.text().catch(error => {
  console.error('Stream reading failed:', error);
});

Opaque Response Handling

Workbox Streams throws a WorkboxError when attempting to stream opaque responses:

// This will throw WorkboxError: 'opaque-streams-source'
const opaqueResponse = await fetch('https://external-api.com/data', {
  mode: 'no-cors' // Creates opaque response
});

const {stream} = concatenate([Promise.resolve(opaqueResponse)]);
// Error: Cannot read from opaque response

Browser Compatibility

  • Full Support: Browsers with ReadableStream constructor (Chrome 43+, Firefox 65+, Safari 10.1+)
  • Fallback Mode: Automatic fallback to blob-based concatenation for older browsers
  • Service Worker Context: Designed for service worker environments but works in main thread
  • Streaming Benefits: Only available in supporting browsers; fallback mode waits for all sources to complete