get-stream
Advanced tools
| export {getStreamAsArray} from './array.js'; | ||
| export {getStreamAsArrayBuffer} from './array-buffer.js'; | ||
| export {getStreamAsBuffer} from './buffer.js'; | ||
| export {getStreamAsString as default} from './string.js'; | ||
| export {MaxBufferError} from './contents.js'; |
| import {isReadableStream} from 'is-stream'; | ||
| import {ponyfill} from './web-stream.js'; | ||
| export const getAsyncIterable = stream => { | ||
| if (isReadableStream(stream, {checkOpen: false}) && nodeImports.on !== undefined) { | ||
| return getStreamIterable(stream); | ||
| } | ||
| if (typeof stream?.[Symbol.asyncIterator] === 'function') { | ||
| return stream; | ||
| } | ||
| // `ReadableStream[Symbol.asyncIterator]` support is missing in multiple browsers, so we ponyfill it | ||
| if (toString.call(stream) === '[object ReadableStream]') { | ||
| return ponyfill.asyncIterator.call(stream); | ||
| } | ||
| throw new TypeError('The first argument must be a Readable, a ReadableStream, or an async iterable.'); | ||
| }; | ||
| const {toString} = Object.prototype; | ||
| // The default iterable for Node.js streams does not allow for multiple readers at once, so we re-implement it | ||
| const getStreamIterable = async function * (stream) { | ||
| const controller = new AbortController(); | ||
| const state = {}; | ||
| handleStreamEnd(stream, controller, state); | ||
| try { | ||
| for await (const [chunk] of nodeImports.on(stream, 'data', {signal: controller.signal})) { | ||
| yield chunk; | ||
| } | ||
| } catch (error) { | ||
| // Stream failure, for example due to `stream.destroy(error)` | ||
| if (state.error !== undefined) { | ||
| throw state.error; | ||
| // `error` event directly emitted on stream | ||
| } else if (!controller.signal.aborted) { | ||
| throw error; | ||
| // Otherwise, stream completed successfully | ||
| } | ||
| // The `finally` block also runs when the caller throws, for example due to the `maxBuffer` option | ||
| } finally { | ||
| stream.destroy(); | ||
| } | ||
| }; | ||
| const handleStreamEnd = async (stream, controller, state) => { | ||
| try { | ||
| await nodeImports.finished(stream, {cleanup: true, readable: true, writable: false, error: false}); | ||
| } catch (error) { | ||
| state.error = error; | ||
| } finally { | ||
| controller.abort(); | ||
| } | ||
| }; | ||
| // Loaded by the Node entrypoint, but not by the browser one. | ||
| // This prevents using dynamic imports. | ||
| export const nodeImports = {}; |
| export const ponyfill = {}; | ||
| const {prototype} = ReadableStream; | ||
| // Use this library as a ponyfill instead of a polyfill. | ||
| // I.e. avoid modifying global variables. | ||
| // We can remove this once https://github.com/Sec-ant/readable-stream/issues/2 is fixed | ||
| if (prototype[Symbol.asyncIterator] === undefined && prototype.values === undefined) { | ||
| await import('@sec-ant/readable-stream'); | ||
| ponyfill.asyncIterator = prototype[Symbol.asyncIterator]; | ||
| delete prototype[Symbol.asyncIterator]; | ||
| delete prototype.values; | ||
| } |
+12
-5
| { | ||
| "name": "get-stream", | ||
| "version": "8.0.1", | ||
| "version": "9.0.0", | ||
| "description": "Get a stream as a string, Buffer, ArrayBuffer or array", | ||
@@ -16,6 +16,8 @@ "license": "MIT", | ||
| "types": "./source/index.d.ts", | ||
| "browser": "./source/exports.js", | ||
| "default": "./source/index.js" | ||
| }, | ||
| "sideEffects": false, | ||
| "engines": { | ||
| "node": ">=16" | ||
| "node": ">=18" | ||
| }, | ||
@@ -46,10 +48,15 @@ "scripts": { | ||
| ], | ||
| "dependencies": { | ||
| "@sec-ant/readable-stream": "^0.3.2", | ||
| "is-stream": "^4.0.1" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/node": "^20.5.0", | ||
| "@types/node": "^20.8.9", | ||
| "ava": "^5.3.1", | ||
| "precise-now": "^2.0.0", | ||
| "onetime": "^7.0.0", | ||
| "precise-now": "^3.0.0", | ||
| "stream-json": "^1.8.0", | ||
| "tsd": "^0.28.1", | ||
| "tsd": "^0.29.0", | ||
| "xo": "^0.56.0" | ||
| } | ||
| } |
+13
-1
@@ -7,3 +7,3 @@ # get-stream | ||
| - Works in any JavaScript environment ([Node.js](#nodejs-streams), [browsers](#web-streams), etc.). | ||
| - Works in any JavaScript environment ([Node.js](#nodejs-streams), [browsers](#browser-support), etc.). | ||
| - Supports [text streams](#getstreamstream-options), [binary streams](#getstreamasbufferstream-options) and [object streams](#getstreamasarraystream-options). | ||
@@ -64,2 +64,4 @@ - Supports [async iterables](#async-iterables). | ||
| 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. | ||
| ### Async iterables | ||
@@ -147,2 +149,12 @@ | ||
| ## Browser support | ||
| For this module to work in browsers, a bundler must be used that either: | ||
| - Supports the [`exports.browser`](https://nodejs.org/api/packages.html#community-conditions-definitions) field in `package.json` | ||
| - Strips or ignores `node:*` imports | ||
| Most bundlers (such as [Webpack](https://webpack.js.org/guides/package-exports/#target-environment)) support either of these. | ||
| Additionally, browsers support [web streams](#web-streams) and [async iterables](#async-iterables), but not [Node.js streams](#nodejs-streams). | ||
| ## Tips | ||
@@ -149,0 +161,0 @@ |
@@ -0,5 +1,5 @@ | ||
| import {getAsyncIterable} from './stream.js'; | ||
| export const getStreamContents = async (stream, {init, convertChunk, getSize, truncateChunk, addChunk, getFinalChunk, finalize}, {maxBuffer = Number.POSITIVE_INFINITY} = {}) => { | ||
| if (!isAsyncIterable(stream)) { | ||
| throw new Error('The first argument must be a Readable, a ReadableStream, or an async iterable.'); | ||
| } | ||
| const asyncIterable = getAsyncIterable(stream); | ||
@@ -10,3 +10,3 @@ const state = init(); | ||
| try { | ||
| for await (const chunk of stream) { | ||
| for await (const chunk of asyncIterable) { | ||
| const chunkType = getChunkType(chunk); | ||
@@ -20,4 +20,5 @@ const convertedChunk = convertChunk[chunkType](chunk, state); | ||
| } catch (error) { | ||
| error.bufferedData = finalize(state); | ||
| throw error; | ||
| const normalizedError = typeof error === 'object' && error !== null ? error : new Error(error); | ||
| normalizedError.bufferedData = finalize(state); | ||
| throw normalizedError; | ||
| } | ||
@@ -56,4 +57,2 @@ }; | ||
| const isAsyncIterable = stream => typeof stream === 'object' && stream !== null && typeof stream[Symbol.asyncIterator] === 'function'; | ||
| const getChunkType = chunk => { | ||
@@ -60,0 +59,0 @@ const typeOfChunk = typeof chunk; |
+13
-5
@@ -1,5 +0,13 @@ | ||
| export {getStreamAsArray} from './array.js'; | ||
| export {getStreamAsArrayBuffer} from './array-buffer.js'; | ||
| export {getStreamAsBuffer} from './buffer.js'; | ||
| export {getStreamAsString as default} from './string.js'; | ||
| export {MaxBufferError} from './contents.js'; | ||
| import {on} from 'node:events'; | ||
| import {finished} from 'node:stream/promises'; | ||
| import {nodeImports} from './stream.js'; | ||
| Object.assign(nodeImports, {on, finished}); | ||
| export { | ||
| default, | ||
| getStreamAsArray, | ||
| getStreamAsArrayBuffer, | ||
| getStreamAsBuffer, | ||
| MaxBufferError, | ||
| } from './exports.js'; |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
28696
14.09%14
27.27%396
22.22%304
4.11%3
-25%2
Infinity%7
16.67%+ Added
+ Added
+ Added