or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

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

0

# Workbox Streams

1

2

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.

3

4

## Package Information

5

6

- **Package Name**: workbox-streams

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install workbox-streams`

10

11

## Core Imports

12

13

```typescript

14

import {

15

concatenate,

16

concatenateToResponse,

17

isSupported,

18

strategy,

19

type StreamSource,

20

type StreamsHandlerCallback

21

} from "workbox-streams";

22

```

23

24

For CommonJS:

25

26

```javascript

27

const {

28

concatenate,

29

concatenateToResponse,

30

isSupported,

31

strategy

32

} = require("workbox-streams");

33

```

34

35

## Basic Usage

36

37

```typescript

38

import {

39

concatenate,

40

concatenateToResponse,

41

isSupported,

42

strategy

43

} from "workbox-streams";

44

45

// Check browser support for streaming

46

if (isSupported()) {

47

// Concatenate multiple stream sources

48

const sourcePromises = [

49

fetch('/api/header'),

50

fetch('/api/content'),

51

fetch('/api/footer')

52

];

53

54

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

55

56

// Or create a Response directly

57

const {done: responseDone, response} = concatenateToResponse(

58

sourcePromises,

59

{'content-type': 'text/html'}

60

);

61

62

// Use in service worker

63

self.addEventListener('fetch', (event) => {

64

event.waitUntil(responseDone);

65

event.respondWith(response);

66

});

67

}

68

```

69

70

## Architecture

71

72

Workbox Streams is built around streaming and fallback patterns:

73

74

- **Stream Concatenation**: Core functionality for combining multiple stream sources sequentially

75

- **Browser Compatibility**: Automatic detection and fallback for browsers without streaming support

76

- **Workbox Integration**: Strategy functions designed for use with Workbox routing

77

- **Response Creation**: Utilities to convert streams into standard Response objects

78

- **Promise Tracking**: Support for service worker waitUntil() patterns

79

80

## Capabilities

81

82

### Stream Concatenation

83

84

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

85

86

```typescript { .api }

87

/**

88

* Takes multiple source Promises and returns a ReadableStream with sequential data

89

* @param sourcePromises - Array of Promises resolving to StreamSource objects

90

* @returns Object with completion Promise and ReadableStream

91

*/

92

function concatenate(sourcePromises: Promise<StreamSource>[]): {

93

done: Promise<void>;

94

stream: ReadableStream;

95

};

96

```

97

98

**Usage Example:**

99

100

```typescript

101

import { concatenate } from "workbox-streams";

102

103

const sourcePromises = [

104

Promise.resolve(new Response('Hello ')),

105

Promise.resolve(new Response('World!')),

106

fetch('/api/data')

107

];

108

109

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

110

111

// Use the stream

112

const response = new Response(stream, {

113

headers: {'content-type': 'text/plain'}

114

});

115

116

// Wait for completion

117

await done;

118

```

119

120

### Response Stream Concatenation

121

122

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

123

124

```typescript { .api }

125

/**

126

* Takes multiple source Promises and returns a Response with concatenated data

127

* @param sourcePromises - Array of Promises resolving to StreamSource objects

128

* @param headersInit - Optional headers for the response (if no 'Content-Type', defaults to 'text/html')

129

* @returns Object with completion Promise and Response

130

*/

131

function concatenateToResponse(

132

sourcePromises: Promise<StreamSource>[],

133

headersInit?: HeadersInit

134

): {

135

done: Promise<void>;

136

response: Response;

137

};

138

```

139

140

**Usage Example:**

141

142

```typescript

143

import { concatenateToResponse } from "workbox-streams";

144

145

const sourcePromises = [

146

fetch('/template/header'),

147

fetch('/content/body'),

148

fetch('/template/footer')

149

];

150

151

// With headers

152

const {done, response} = concatenateToResponse(

153

sourcePromises,

154

{

155

'content-type': 'text/html',

156

'cache-control': 'max-age=3600'

157

}

158

);

159

160

// Without headers (defaults to 'text/html')

161

const {done: done2, response: response2} = concatenateToResponse(sourcePromises);

162

163

// Use in service worker

164

self.addEventListener('fetch', (event) => {

165

if (event.request.url.endsWith('/composite-page')) {

166

event.waitUntil(done);

167

event.respondWith(response);

168

}

169

});

170

```

171

172

### Browser Support Detection

173

174

Determines whether the current browser supports streaming features.

175

176

```typescript { .api }

177

/**

178

* Checks if browser supports ReadableStream construction for streaming responses

179

* @returns true if streaming is supported, false otherwise

180

*/

181

function isSupported(): boolean;

182

```

183

184

**Usage Example:**

185

186

```typescript

187

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

188

189

function createCompositeResponse(sources: Promise<StreamSource>[], headers: HeadersInit) {

190

if (isSupported()) {

191

// Use streaming concatenation

192

return concatenateToResponse(sources, headers);

193

} else {

194

// Fallback to waiting for all sources

195

return Promise.all(sources).then(resolvedSources => {

196

// Manual concatenation fallback

197

return new Response(/* combined content */, {headers});

198

});

199

}

200

}

201

```

202

203

### Workbox Strategy Integration

204

205

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

206

207

```typescript { .api }

208

/**

209

* Creates a Workbox-compatible strategy for streaming responses with fallback

210

* @param sourceFunctions - Array of handler functions returning StreamSource objects

211

* @param headersInit - Optional headers for responses (if no 'Content-Type', defaults to 'text/html')

212

* @returns RouteHandlerCallback compatible with Workbox routing

213

*/

214

function strategy(

215

sourceFunctions: StreamsHandlerCallback[],

216

headersInit?: HeadersInit

217

): RouteHandlerCallback;

218

```

219

220

**Usage Example:**

221

222

```typescript

223

import { strategy } from "workbox-streams";

224

import { registerRoute } from "workbox-routing";

225

226

// Define source functions

227

const sourceFunctions = [

228

// Header source

229

({url, request}) => fetch('/api/header'),

230

// Dynamic content based on URL

231

({url, request}) => fetch(`/api/content${url.pathname}`),

232

// Footer source

233

({url, request}) => fetch('/api/footer')

234

];

235

236

// Create streaming strategy with headers

237

const streamingStrategy = strategy(sourceFunctions, {

238

'content-type': 'text/html',

239

'cache-control': 'no-cache'

240

});

241

242

// Or without headers (defaults to 'text/html')

243

const basicStrategy = strategy(sourceFunctions);

244

245

// Register with Workbox routing

246

registerRoute(

247

({url}) => url.pathname.startsWith('/dynamic/'),

248

streamingStrategy

249

);

250

```

251

252

## Types

253

254

### StreamSource

255

256

Union type representing valid stream sources.

257

258

```typescript { .api }

259

/**

260

* Valid source types for streaming operations

261

*/

262

type StreamSource = Response | ReadableStream | BodyInit;

263

```

264

265

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

266

267

### StreamsHandlerCallback

268

269

Interface for handler functions used in streaming strategies.

270

271

```typescript { .api }

272

/**

273

* Handler function interface for streaming strategies

274

*/

275

interface StreamsHandlerCallback {

276

(options: RouteHandlerCallbackOptions): Promise<StreamSource> | StreamSource;

277

}

278

279

/**

280

* Generic object interface for key-value mapping (from workbox-core)

281

*/

282

interface MapLikeObject {

283

[key: string]: any;

284

}

285

286

/**

287

* Options passed to handler callbacks (from workbox-core)

288

*/

289

interface RouteHandlerCallbackOptions {

290

event: ExtendableEvent;

291

request: Request;

292

url: URL;

293

params?: string[] | MapLikeObject;

294

}

295

296

/**

297

* Route handler callback interface (from workbox-core)

298

*/

299

interface RouteHandlerCallback {

300

(options: RouteHandlerCallbackOptions): Promise<Response>;

301

}

302

```

303

304

## Error Handling

305

306

### Stream Processing Errors

307

308

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

309

310

```typescript

311

import { concatenate } from "workbox-streams";

312

313

const {done, stream} = concatenate([

314

fetch('/api/source1'),

315

fetch('/api/source2')

316

]);

317

318

// Handle errors in the completion promise

319

done.catch(error => {

320

console.error('Stream concatenation failed:', error);

321

});

322

323

// Errors also propagate through the stream

324

const response = new Response(stream);

325

response.text().catch(error => {

326

console.error('Stream reading failed:', error);

327

});

328

```

329

330

### Opaque Response Handling

331

332

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

333

334

```typescript

335

// This will throw WorkboxError: 'opaque-streams-source'

336

const opaqueResponse = await fetch('https://external-api.com/data', {

337

mode: 'no-cors' // Creates opaque response

338

});

339

340

const {stream} = concatenate([Promise.resolve(opaqueResponse)]);

341

// Error: Cannot read from opaque response

342

```

343

344

## Browser Compatibility

345

346

- **Full Support**: Browsers with ReadableStream constructor (Chrome 43+, Firefox 65+, Safari 10.1+)

347

- **Fallback Mode**: Automatic fallback to blob-based concatenation for older browsers

348

- **Service Worker Context**: Designed for service worker environments but works in main thread

349

- **Streaming Benefits**: Only available in supporting browsers; fallback mode waits for all sources to complete