1 | # get-stream
|
2 |
|
3 | > Get a stream as a string, Buffer, ArrayBuffer or array
|
4 |
|
5 | ## Features
|
6 |
|
7 | - Works in any JavaScript environment ([Node.js](#nodejs-streams), [browsers](#browser-support), etc.).
|
8 | - Supports [text streams](#getstreamstream-options), [binary streams](#getstreamasbufferstream-options) and [object streams](#getstreamasarraystream-options).
|
9 | - Supports [async iterables](#async-iterables).
|
10 | - Can set a [maximum stream size](#maxbuffer).
|
11 | - Returns [partially read data](#errors) when the stream errors.
|
12 | - [Fast](#benchmarks).
|
13 |
|
14 | ## Install
|
15 |
|
16 | ```sh
|
17 | npm install get-stream
|
18 | ```
|
19 |
|
20 | ## Usage
|
21 |
|
22 | ### Node.js streams
|
23 |
|
24 | ```js
|
25 | import fs from 'node:fs';
|
26 | import getStream from 'get-stream';
|
27 |
|
28 | const stream = fs.createReadStream('unicorn.txt');
|
29 |
|
30 | console.log(await getStream(stream));
|
31 | /*
|
32 | ,,))))))));,
|
33 | __)))))))))))))),
|
34 | \|/ -\(((((''''((((((((.
|
35 | -*-==//////(('' . `)))))),
|
36 | /|\ ))| o ;-. '((((( ,(,
|
37 | ( `| / ) ;))))' ,_))^;(~
|
38 | | | | ,))((((_ _____------~~~-. %,;(;(>';'~
|
39 | o_); ; )))(((` ~---~ `:: \ %%~~)(v;(`('~
|
40 | ; ''''```` `: `:::|\,__,%% );`'; ~
|
41 | | _ ) / `:|`----' `-'
|
42 | ______/\/~ | / /
|
43 | /~;;.____/;;' / ___--,-( `;;;/
|
44 | / // _;______;'------~~~~~ /;;/\ /
|
45 | // | | / ; \;;,\
|
46 | (<_ | ; /',/-----' _>
|
47 | \_| ||_ //~;~~~~~~~~~
|
48 | `\_| (,~~
|
49 | \~\
|
50 | ~~
|
51 | */
|
52 | ```
|
53 |
|
54 | ### Web streams
|
55 |
|
56 | ```js
|
57 | import getStream from 'get-stream';
|
58 |
|
59 | const {body: readableStream} = await fetch('https://example.com');
|
60 | console.log(await getStream(readableStream));
|
61 | ```
|
62 |
|
63 | This works in any browser, even [the ones](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream#browser_compatibility) not supporting `ReadableStream.values()` yet.
|
64 |
|
65 | ### Async iterables
|
66 |
|
67 | ```js
|
68 | import {opendir} from 'node:fs/promises';
|
69 | import {getStreamAsArray} from 'get-stream';
|
70 |
|
71 | const asyncIterable = await opendir(directory);
|
72 | console.log(await getStreamAsArray(asyncIterable));
|
73 | ```
|
74 |
|
75 | ## API
|
76 |
|
77 | The following methods read the stream's contents and return it as a promise.
|
78 |
|
79 | ### getStream(stream, options?)
|
80 |
|
81 | `stream`: [`stream.Readable`](https://nodejs.org/api/stream.html#class-streamreadable), [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream), or [`AsyncIterable<string | Buffer | ArrayBuffer | DataView | TypedArray>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols)\
|
82 | `options`: [`Options`](#options)
|
83 |
|
84 | Get the given `stream` as a string.
|
85 |
|
86 | ### getStreamAsBuffer(stream, options?)
|
87 |
|
88 | Get the given `stream` as a Node.js [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer).
|
89 |
|
90 | ```js
|
91 | import {getStreamAsBuffer} from 'get-stream';
|
92 |
|
93 | const stream = fs.createReadStream('unicorn.png');
|
94 | console.log(await getStreamAsBuffer(stream));
|
95 | ```
|
96 |
|
97 | ### getStreamAsArrayBuffer(stream, options?)
|
98 |
|
99 | Get the given `stream` as an [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer).
|
100 |
|
101 | ```js
|
102 | import {getStreamAsArrayBuffer} from 'get-stream';
|
103 |
|
104 | const {body: readableStream} = await fetch('https://example.com');
|
105 | console.log(await getStreamAsArrayBuffer(readableStream));
|
106 | ```
|
107 |
|
108 | ### getStreamAsArray(stream, options?)
|
109 |
|
110 | Get the given `stream` as an array. Unlike [other methods](#api), this supports [streams of objects](https://nodejs.org/api/stream.html#object-mode).
|
111 |
|
112 | ```js
|
113 | import {getStreamAsArray} from 'get-stream';
|
114 |
|
115 | const {body: readableStream} = await fetch('https://example.com');
|
116 | console.log(await getStreamAsArray(readableStream));
|
117 | ```
|
118 |
|
119 | #### options
|
120 |
|
121 | Type: `object`
|
122 |
|
123 | ##### maxBuffer
|
124 |
|
125 | Type: `number`\
|
126 | Default: `Infinity`
|
127 |
|
128 | Maximum length of the stream. If exceeded, the promise will be rejected with a `MaxBufferError`.
|
129 |
|
130 | Depending on the [method](#api), the length is measured with [`string.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length), [`buffer.length`](https://nodejs.org/api/buffer.html#buflength), [`arrayBuffer.byteLength`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/byteLength) or [`array.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length).
|
131 |
|
132 | ## Errors
|
133 |
|
134 | If the stream errors, the returned promise will be rejected with the `error`. Any contents already read from the stream will be set to `error.bufferedData`, which is a `string`, a `Buffer`, an `ArrayBuffer` or an array depending on the [method used](#api).
|
135 |
|
136 | ```js
|
137 | import getStream from 'get-stream';
|
138 |
|
139 | try {
|
140 | await getStream(streamThatErrorsAtTheEnd('unicorn'));
|
141 | } catch (error) {
|
142 | console.log(error.bufferedData);
|
143 | //=> 'unicorn'
|
144 | }
|
145 | ```
|
146 |
|
147 | ## Browser support
|
148 |
|
149 | For this module to work in browsers, a bundler must be used that either:
|
150 | - Supports the [`exports.browser`](https://nodejs.org/api/packages.html#community-conditions-definitions) field in `package.json`
|
151 | - Strips or ignores `node:*` imports
|
152 |
|
153 | Most bundlers (such as [Webpack](https://webpack.js.org/guides/package-exports/#target-environment)) support either of these.
|
154 |
|
155 | Additionally, browsers support [web streams](#web-streams) and [async iterables](#async-iterables), but not [Node.js streams](#nodejs-streams).
|
156 |
|
157 | ## Tips
|
158 |
|
159 | ### Alternatives
|
160 |
|
161 | If you do not need the [`maxBuffer`](#maxbuffer) option, [`error.bufferedData`](#errors), nor browser support, you can use the following methods instead of this package.
|
162 |
|
163 | #### [`streamConsumers.text()`](https://nodejs.org/api/webstreams.html#streamconsumerstextstream)
|
164 |
|
165 | ```js
|
166 | import fs from 'node:fs';
|
167 | import {text} from 'node:stream/consumers';
|
168 |
|
169 | const stream = fs.createReadStream('unicorn.txt', {encoding: 'utf8'});
|
170 | console.log(await text(stream))
|
171 | ```
|
172 |
|
173 | #### [`streamConsumers.buffer()`](https://nodejs.org/api/webstreams.html#streamconsumersbufferstream)
|
174 |
|
175 | ```js
|
176 | import {buffer} from 'node:stream/consumers';
|
177 |
|
178 | console.log(await buffer(stream))
|
179 | ```
|
180 |
|
181 | #### [`streamConsumers.arrayBuffer()`](https://nodejs.org/api/webstreams.html#streamconsumersarraybufferstream)
|
182 |
|
183 | ```js
|
184 | import {arrayBuffer} from 'node:stream/consumers';
|
185 |
|
186 | console.log(await arrayBuffer(stream))
|
187 | ```
|
188 |
|
189 | #### [`readable.toArray()`](https://nodejs.org/api/stream.html#readabletoarrayoptions)
|
190 |
|
191 | ```js
|
192 | console.log(await stream.toArray())
|
193 | ```
|
194 |
|
195 | #### [`Array.fromAsync()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync)
|
196 |
|
197 | If your [environment supports it](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync#browser_compatibility):
|
198 |
|
199 | ```js
|
200 | console.log(await Array.fromAsync(stream))
|
201 | ```
|
202 |
|
203 | ### Non-UTF-8 encoding
|
204 |
|
205 | When all of the following conditions apply:
|
206 | - [`getStream()`](#getstreamstream-options) is used (as opposed to [`getStreamAsBuffer()`](#getstreamasbufferstream-options) or [`getStreamAsArrayBuffer()`](#getstreamasarraybufferstream-options))
|
207 | - The stream is binary (not text)
|
208 | - The stream's encoding is not UTF-8 (for example, it is UTF-16, hexadecimal, or Base64)
|
209 |
|
210 | Then the stream must be decoded using a transform stream like [`TextDecoderStream`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoderStream) or [`b64`](https://github.com/hapijs/b64).
|
211 |
|
212 | ```js
|
213 | import getStream from 'get-stream';
|
214 |
|
215 | const textDecoderStream = new TextDecoderStream('utf-16le');
|
216 | const {body: readableStream} = await fetch('https://example.com');
|
217 | console.log(await getStream(readableStream.pipeThrough(textDecoderStream)));
|
218 | ```
|
219 |
|
220 | ### Blobs
|
221 |
|
222 | [`getStreamAsArrayBuffer()`](#getstreamasarraybufferstream-options) can be used to create [Blobs](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
|
223 |
|
224 | ```js
|
225 | import {getStreamAsArrayBuffer} from 'get-stream';
|
226 |
|
227 | const stream = fs.createReadStream('unicorn.txt');
|
228 | console.log(new Blob([await getStreamAsArrayBuffer(stream)]));
|
229 | ```
|
230 |
|
231 | ### JSON streaming
|
232 |
|
233 | [`getStreamAsArray()`](#getstreamasarraystream-options) can be combined with JSON streaming utilities to parse JSON incrementally.
|
234 |
|
235 | ```js
|
236 | import fs from 'node:fs';
|
237 | import {compose as composeStreams} from 'node:stream';
|
238 | import {getStreamAsArray} from 'get-stream';
|
239 | import streamJson from 'stream-json';
|
240 | import streamJsonArray from 'stream-json/streamers/StreamArray.js';
|
241 |
|
242 | const stream = fs.createReadStream('big-array-of-objects.json');
|
243 | console.log(await getStreamAsArray(
|
244 | composeStreams(stream, streamJson.parser(), streamJsonArray.streamArray()),
|
245 | ));
|
246 | ```
|
247 |
|
248 | ## Benchmarks
|
249 |
|
250 | ### Node.js stream (100 MB, binary)
|
251 |
|
252 | - `getStream()`: 142ms
|
253 | - `text()`: 139ms
|
254 | - `getStreamAsBuffer()`: 106ms
|
255 | - `buffer()`: 83ms
|
256 | - `getStreamAsArrayBuffer()`: 105ms
|
257 | - `arrayBuffer()`: 81ms
|
258 | - `getStreamAsArray()`: 24ms
|
259 | - `stream.toArray()`: 21ms
|
260 |
|
261 | ### Node.js stream (100 MB, text)
|
262 |
|
263 | - `getStream()`: 90ms
|
264 | - `text()`: 89ms
|
265 | - `getStreamAsBuffer()`: 127ms
|
266 | - `buffer()`: 192ms
|
267 | - `getStreamAsArrayBuffer()`: 129ms
|
268 | - `arrayBuffer()`: 195ms
|
269 | - `getStreamAsArray()`: 89ms
|
270 | - `stream.toArray()`: 90ms
|
271 |
|
272 | ### Web ReadableStream (100 MB, binary)
|
273 |
|
274 | - `getStream()`: 223ms
|
275 | - `text()`: 221ms
|
276 | - `getStreamAsBuffer()`: 182ms
|
277 | - `buffer()`: 153ms
|
278 | - `getStreamAsArrayBuffer()`: 171ms
|
279 | - `arrayBuffer()`: 155ms
|
280 | - `getStreamAsArray()`: 83ms
|
281 |
|
282 | ### Web ReadableStream (100 MB, text)
|
283 |
|
284 | - `getStream()`: 141ms
|
285 | - `text()`: 139ms
|
286 | - `getStreamAsBuffer()`: 91ms
|
287 | - `buffer()`: 80ms
|
288 | - `getStreamAsArrayBuffer()`: 89ms
|
289 | - `arrayBuffer()`: 81ms
|
290 | - `getStreamAsArray()`: 21ms
|
291 |
|
292 | [Benchmarks' source file](benchmarks/index.js).
|
293 |
|
294 | ## FAQ
|
295 |
|
296 | ### How is this different from [`concat-stream`](https://github.com/maxogden/concat-stream)?
|
297 |
|
298 | This module accepts a stream instead of being one and returns a promise instead of using a callback. The API is simpler and it only supports returning a string, `Buffer`, an `ArrayBuffer` or an array. It doesn't have a fragile type inference. You explicitly choose what you want. And it doesn't depend on the huge `readable-stream` package.
|
299 |
|
300 | ## Related
|
301 |
|
302 | - [get-stdin](https://github.com/sindresorhus/get-stdin) - Get stdin as a string or buffer
|
303 | - [into-stream](https://github.com/sindresorhus/into-stream) - The opposite of this package
|