diff --git a/node/_stream.d.ts b/node/_stream.d.ts index 778dd7525fe1..12fc72efead6 100644 --- a/node/_stream.d.ts +++ b/node/_stream.d.ts @@ -3,6 +3,7 @@ // Forked from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/4f538975138678878fed5b2555c0672aa578ab7d/types/node/stream.d.ts +import { Buffer } from "./_buffer.d.ts"; import { Abortable, EventEmitter } from "./_events.d.ts"; import { Buffered, @@ -1477,5 +1478,5 @@ interface Pipe { } // These have to be at the bottom of the file to work correctly, for some reason -export { _uint8ArrayToBuffer } from "./internal/streams/_utils.ts"; -export { isUint8Array as _isUint8Array } from "./internal/util/types.ts"; +export function _uint8ArrayToBuffer(chunk: Uint8Array): Buffer; +export function _isUint8Array(value: unknown): value is Uint8Array; diff --git a/node/_stream.mjs b/node/_stream.mjs index 3842648e6548..cee07eb6c571 100644 --- a/node/_stream.mjs +++ b/node/_stream.mjs @@ -1,78 +1,492 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. +// deno-fmt-ignore-file +// deno-lint-ignore-file +import { nextTick } from "./_next_tick.ts"; +import { stdio } from "./_process/stdio.mjs"; -import { _uint8ArrayToBuffer } from "./internal/streams/_utils.ts"; -import { addAbortSignal } from "./internal/streams/add-abort-signal.mjs"; -import { destroyer } from "./internal/streams/destroy.mjs"; -import { isDisturbed } from "./internal/streams/utils.mjs"; -import { isUint8Array } from "./internal/util/types.ts"; -import { pipeline } from "./internal/streams/pipeline.mjs"; -import { promisify } from "./internal/util.mjs"; -import { Stream } from "./internal/streams/legacy.mjs"; -import compose from "./internal/streams/compose.mjs"; -import Duplex from "./internal/streams/duplex.mjs"; -import eos from "./internal/streams/end-of-stream.mjs"; -import PassThrough from "./internal/streams/passthrough.mjs"; -import promises from "./stream/promises.mjs"; -import Readable from "./internal/streams/readable.mjs"; -import Transform from "./internal/streams/transform.mjs"; -import Writable from "./internal/streams/writable.mjs"; - -const { custom: customPromisify } = promisify; - -Stream.isDisturbed = isDisturbed; -Stream.Readable = Readable; -Stream.Writable = Writable; -Stream.Duplex = Duplex; -Stream.Transform = Transform; -Stream.PassThrough = PassThrough; -Stream.pipeline = pipeline; -Stream.addAbortSignal = addAbortSignal; -Stream.finished = eos; -Stream.destroy = destroyer; -Stream.compose = compose; - -Object.defineProperty(Stream, "promises", { - configurable: true, - enumerable: true, - get() { - return promises; - }, -}); - -Object.defineProperty(pipeline, customPromisify, { - enumerable: true, - get() { - return promises.pipeline; - }, -}); - -Object.defineProperty(eos, customPromisify, { - enumerable: true, - get() { - return promises.finished; - }, -}); - -// Backwards-compat with node 0.4.x -Stream.Stream = Stream; -Stream._isUint8Array = isUint8Array; -Stream._uint8ArrayToBuffer = _uint8ArrayToBuffer; - -export default Stream; -export { - _uint8ArrayToBuffer, - addAbortSignal, - compose, - destroyer as destroy, - Duplex, - eos as finished, - isDisturbed, - isUint8Array as _isUint8Array, - PassThrough, - pipeline, - Readable, - Stream, - Transform, - Writable, +/* esm.sh - esbuild bundle(readable-stream@4.1.0) es2022 production */ +const __Process$ = { nextTick, stdio };import { Buffer as __Buffer$ } from "./buffer.ts";import __string_decoder$ from "./string_decoder.ts";import __events$ from "./events.ts";import __buffer$ from "./buffer.ts";var ri=Object.create;var Lt=Object.defineProperty;var ii=Object.getOwnPropertyDescriptor;var oi=Object.getOwnPropertyNames;var li=Object.getPrototypeOf,fi=Object.prototype.hasOwnProperty;var $=(e=>typeof require!="undefined"?require:typeof Proxy!="undefined"?new Proxy(e,{get:(t,n)=>(typeof require!="undefined"?require:t)[n]}):e)(function(e){if(typeof require!="undefined")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var _=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var ai=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of oi(t))!fi.call(e,i)&&i!==n&&Lt(e,i,{get:()=>t[i],enumerable:!(r=ii(t,i))||r.enumerable});return e};var si=(e,t,n)=>(n=e!=null?ri(li(e)):{},ai(t||!e||!e.__esModule?Lt(n,"default",{value:e,enumerable:!0}):n,e));var T=_((Ia,Pt)=>{"use strict";Pt.exports={ArrayIsArray(e){return Array.isArray(e)},ArrayPrototypeIncludes(e,t){return e.includes(t)},ArrayPrototypeIndexOf(e,t){return e.indexOf(t)},ArrayPrototypeJoin(e,t){return e.join(t)},ArrayPrototypeMap(e,t){return e.map(t)},ArrayPrototypePop(e,t){return e.pop(t)},ArrayPrototypePush(e,t){return e.push(t)},ArrayPrototypeSlice(e,t,n){return e.slice(t,n)},Error,FunctionPrototypeCall(e,t,...n){return e.call(t,...n)},FunctionPrototypeSymbolHasInstance(e,t){return Function.prototype[Symbol.hasInstance].call(e,t)},MathFloor:Math.floor,Number,NumberIsInteger:Number.isInteger,NumberIsNaN:Number.isNaN,NumberMAX_SAFE_INTEGER:Number.MAX_SAFE_INTEGER,NumberMIN_SAFE_INTEGER:Number.MIN_SAFE_INTEGER,NumberParseInt:Number.parseInt,ObjectDefineProperties(e,t){return Object.defineProperties(e,t)},ObjectDefineProperty(e,t,n){return Object.defineProperty(e,t,n)},ObjectGetOwnPropertyDescriptor(e,t){return Object.getOwnPropertyDescriptor(e,t)},ObjectKeys(e){return Object.keys(e)},ObjectSetPrototypeOf(e,t){return Object.setPrototypeOf(e,t)},Promise,PromisePrototypeCatch(e,t){return e.catch(t)},PromisePrototypeThen(e,t,n){return e.then(t,n)},PromiseReject(e){return Promise.reject(e)},ReflectApply:Reflect.apply,RegExpPrototypeTest(e,t){return e.test(t)},SafeSet:Set,String,StringPrototypeSlice(e,t,n){return e.slice(t,n)},StringPrototypeToLowerCase(e){return e.toLowerCase()},StringPrototypeToUpperCase(e){return e.toUpperCase()},StringPrototypeTrim(e){return e.trim()},Symbol,SymbolAsyncIterator:Symbol.asyncIterator,SymbolHasInstance:Symbol.hasInstance,SymbolIterator:Symbol.iterator,TypedArrayPrototypeSet(e,t,n){return e.set(t,n)},Uint8Array}});var W=_((Na,Ue)=>{"use strict";var ui=__buffer$,di=Object.getPrototypeOf(async function(){}).constructor,qt=globalThis.Blob||ui.Blob,ci=typeof qt<"u"?function(t){return t instanceof qt}:function(t){return!1},Be=class extends Error{constructor(t){if(!Array.isArray(t))throw new TypeError(`Expected input to be an Array, got ${typeof t}`);let n="";for(let r=0;r{e=r,t=i}),resolve:e,reject:t}},promisify(e){return new Promise((t,n)=>{e((r,...i)=>r?n(r):t(...i))})},debuglog(){return function(){}},format(e,...t){return e.replace(/%([sdifj])/g,function(...[n,r]){let i=t.shift();return r==="f"?i.toFixed(6):r==="j"?JSON.stringify(i):r==="s"&&typeof i=="object"?`${i.constructor!==Object?i.constructor.name:""} {}`.trim():i.toString()})},inspect(e){switch(typeof e){case"string":if(e.includes("'"))if(e.includes('"')){if(!e.includes("`")&&!e.includes("${"))return`\`${e}\``}else return`"${e}"`;return`'${e}'`;case"number":return isNaN(e)?"NaN":Object.is(e,-0)?String(e):e;case"bigint":return`${String(e)}n`;case"boolean":case"undefined":return String(e);case"object":return"{}"}},types:{isAsyncFunction(e){return e instanceof di},isArrayBufferView(e){return ArrayBuffer.isView(e)}},isBlob:ci};Ue.exports.promisify.custom=Symbol.for("nodejs.util.promisify.custom")});var D=_((Ma,Ct)=>{"use strict";var{format:hi,inspect:ye,AggregateError:bi}=W(),pi=globalThis.AggregateError||bi,wi=Symbol("kIsNodeError"),yi=["string","function","number","object","Function","Object","boolean","bigint","symbol"],gi=/^([A-Z][a-z0-9]*)+$/,_i="__node_internal_",ge={};function z(e,t){if(!e)throw new ge.ERR_INTERNAL_ASSERTION(t)}function kt(e){let t="",n=e.length,r=e[0]==="-"?1:0;for(;n>=r+4;n-=3)t=`_${e.slice(n-3,n)}${t}`;return`${e.slice(0,n)}${t}`}function Si(e,t,n){if(typeof t=="function")return z(t.length<=n.length,`Code: ${e}; The provided arguments length (${n.length}) does not match the required ones (${t.length}).`),t(...n);let r=(t.match(/%[dfijoOs]/g)||[]).length;return z(r===n.length,`Code: ${e}; The provided arguments length (${n.length}) does not match the required ones (${r}).`),n.length===0?t:hi(t,...n)}function N(e,t,n){n||(n=Error);class r extends n{constructor(...o){super(Si(e,t,o))}toString(){return`${this.name} [${e}]: ${this.message}`}}Object.defineProperties(r.prototype,{name:{value:n.name,writable:!0,enumerable:!1,configurable:!0},toString:{value(){return`${this.name} [${e}]: ${this.message}`},writable:!0,enumerable:!1,configurable:!0}}),r.prototype.code=e,r.prototype[wi]=!0,ge[e]=r}function Wt(e){let t=_i+e.name;return Object.defineProperty(e,"name",{value:t}),e}function Ei(e,t){if(e&&t&&e!==t){if(Array.isArray(t.errors))return t.errors.push(e),t;let n=new pi([t,e],t.message);return n.code=t.code,n}return e||t}var Ge=class extends Error{constructor(t="The operation was aborted",n=void 0){if(n!==void 0&&typeof n!="object")throw new ge.ERR_INVALID_ARG_TYPE("options","Object",n);super(t,n),this.code="ABORT_ERR",this.name="AbortError"}};N("ERR_ASSERTION","%s",Error);N("ERR_INVALID_ARG_TYPE",(e,t,n)=>{z(typeof e=="string","'name' must be a string"),Array.isArray(t)||(t=[t]);let r="The ";e.endsWith(" argument")?r+=`${e} `:r+=`"${e}" ${e.includes(".")?"property":"argument"} `,r+="must be ";let i=[],o=[],l=[];for(let a of t)z(typeof a=="string","All expected entries have to be of type string"),yi.includes(a)?i.push(a.toLowerCase()):gi.test(a)?o.push(a):(z(a!=="object",'The value "object" should be written as "Object"'),l.push(a));if(o.length>0){let a=i.indexOf("object");a!==-1&&(i.splice(i,a,1),o.push("Object"))}if(i.length>0){switch(i.length){case 1:r+=`of type ${i[0]}`;break;case 2:r+=`one of type ${i[0]} or ${i[1]}`;break;default:{let a=i.pop();r+=`one of type ${i.join(", ")}, or ${a}`}}(o.length>0||l.length>0)&&(r+=" or ")}if(o.length>0){switch(o.length){case 1:r+=`an instance of ${o[0]}`;break;case 2:r+=`an instance of ${o[0]} or ${o[1]}`;break;default:{let a=o.pop();r+=`an instance of ${o.join(", ")}, or ${a}`}}l.length>0&&(r+=" or ")}switch(l.length){case 0:break;case 1:l[0].toLowerCase()!==l[0]&&(r+="an "),r+=`${l[0]}`;break;case 2:r+=`one of ${l[0]} or ${l[1]}`;break;default:{let a=l.pop();r+=`one of ${l.join(", ")}, or ${a}`}}if(n==null)r+=`. Received ${n}`;else if(typeof n=="function"&&n.name)r+=`. Received function ${n.name}`;else if(typeof n=="object"){var s;(s=n.constructor)!==null&&s!==void 0&&s.name?r+=`. Received an instance of ${n.constructor.name}`:r+=`. Received ${ye(n,{depth:-1})}`}else{let a=ye(n,{colors:!1});a.length>25&&(a=`${a.slice(0,25)}...`),r+=`. Received type ${typeof n} (${a})`}return r},TypeError);N("ERR_INVALID_ARG_VALUE",(e,t,n="is invalid")=>{let r=ye(t);return r.length>128&&(r=r.slice(0,128)+"..."),`The ${e.includes(".")?"property":"argument"} '${e}' ${n}. Received ${r}`},TypeError);N("ERR_INVALID_RETURN_VALUE",(e,t,n)=>{var r;let i=n!=null&&(r=n.constructor)!==null&&r!==void 0&&r.name?`instance of ${n.constructor.name}`:`type ${typeof n}`;return`Expected ${e} to be returned from the "${t}" function but got ${i}.`},TypeError);N("ERR_MISSING_ARGS",(...e)=>{z(e.length>0,"At least one arg needs to be specified");let t,n=e.length;switch(e=(Array.isArray(e)?e:[e]).map(r=>`"${r}"`).join(" or "),n){case 1:t+=`The ${e[0]} argument`;break;case 2:t+=`The ${e[0]} and ${e[1]} arguments`;break;default:{let r=e.pop();t+=`The ${e.join(", ")}, and ${r} arguments`}break}return`${t} must be specified`},TypeError);N("ERR_OUT_OF_RANGE",(e,t,n)=>{z(t,'Missing "range" argument');let r;return Number.isInteger(n)&&Math.abs(n)>2**32?r=kt(String(n)):typeof n=="bigint"?(r=String(n),(n>2n**32n||n<-(2n**32n))&&(r=kt(r)),r+="n"):r=ye(n),`The value of "${e}" is out of range. It must be ${t}. Received ${r}`},RangeError);N("ERR_MULTIPLE_CALLBACK","Callback called multiple times",Error);N("ERR_METHOD_NOT_IMPLEMENTED","The %s method is not implemented",Error);N("ERR_STREAM_ALREADY_FINISHED","Cannot call %s after a stream was finished",Error);N("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable",Error);N("ERR_STREAM_DESTROYED","Cannot call %s after a stream was destroyed",Error);N("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError);N("ERR_STREAM_PREMATURE_CLOSE","Premature close",Error);N("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF",Error);N("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event",Error);N("ERR_STREAM_WRITE_AFTER_END","write after end",Error);N("ERR_UNKNOWN_ENCODING","Unknown encoding: %s",TypeError);Ct.exports={AbortError:Ge,aggregateTwoErrors:Wt(Ei),hideStackFrames:Wt,codes:ge}});var ue=_((Da,Ht)=>{"use strict";var{ArrayIsArray:$t,ArrayPrototypeIncludes:Ri,ArrayPrototypeJoin:Ai,ArrayPrototypeMap:mi,NumberIsInteger:He,NumberMAX_SAFE_INTEGER:Ti,NumberMIN_SAFE_INTEGER:Ii,NumberParseInt:Ni,RegExpPrototypeTest:Mi,String:Di,StringPrototypeToUpperCase:xi,StringPrototypeTrim:Oi}=T(),{hideStackFrames:q,codes:{ERR_SOCKET_BAD_PORT:Li,ERR_INVALID_ARG_TYPE:O,ERR_INVALID_ARG_VALUE:_e,ERR_OUT_OF_RANGE:H,ERR_UNKNOWN_SIGNAL:jt}}=D(),{normalizeEncoding:Pi}=W(),{isAsyncFunction:qi,isArrayBufferView:ki}=W().types,vt={};function Ft(e){return e===(e|0)}function Bt(e){return e===e>>>0}var Wi=/^[0-7]+$/,Ci="must be a 32-bit unsigned integer or an octal string";function ji(e,t,n){if(typeof e>"u"&&(e=n),typeof e=="string"){if(!Mi(Wi,e))throw new _e(t,e,Ci);e=Ni(e,8)}return Ut(e,t,0,2**32-1),e}var vi=q((e,t,n=Ii,r=Ti)=>{if(typeof e!="number")throw new O(t,"number",e);if(!He(e))throw new H(t,"an integer",e);if(er)throw new H(t,`>= ${n} && <= ${r}`,e)}),Ut=q((e,t,n=-2147483648,r=2147483647)=>{if(typeof e!="number")throw new O(t,"number",e);if(!Ft(e))throw He(e)?new H(t,`>= ${n} && <= ${r}`,e):new H(t,"an integer",e);if(er)throw new H(t,`>= ${n} && <= ${r}`,e)}),$i=q((e,t,n)=>{if(typeof e!="number")throw new O(t,"number",e);if(!Bt(e)){if(!He(e))throw new H(t,"an integer",e);let r=n?1:0;throw new H(t,`>= ${r} && < 4294967296`,e)}if(n&&e===0)throw new H(t,">= 1 && < 4294967296",e)});function Gt(e,t){if(typeof e!="string")throw new O(t,"string",e)}function Fi(e,t){if(typeof e!="number")throw new O(t,"number",e)}var Bi=q((e,t,n)=>{if(!Ri(n,e)){let r=Ai(mi(n,o=>typeof o=="string"?`'${o}'`:Di(o)),", "),i="must be one of: "+r;throw new _e(t,e,i)}});function Ui(e,t){if(typeof e!="boolean")throw new O(t,"boolean",e)}var Gi=q((e,t,n)=>{let r=n==null,i=r?!1:n.allowArray,o=r?!1:n.allowFunction;if(!(r?!1:n.nullable)&&e===null||!i&&$t(e)||typeof e!="object"&&(!o||typeof e!="function"))throw new O(t,"Object",e)}),Hi=q((e,t,n=0)=>{if(!$t(e))throw new O(t,"Array",e);if(e.length{if(!ki(e))throw new O(t,["Buffer","TypedArray","DataView"],e)});function Ki(e,t){let n=Pi(t),r=e.length;if(n==="hex"&&r%2!==0)throw new _e("encoding",t,`is invalid for data of length ${r}`)}function zi(e,t="Port",n=!0){if(typeof e!="number"&&typeof e!="string"||typeof e=="string"&&Oi(e).length===0||+e!==+e>>>0||e>65535||e===0&&!n)throw new Li(t,e,n);return e|0}var Xi=q((e,t)=>{if(e!==void 0&&(e===null||typeof e!="object"||!("aborted"in e)))throw new O(t,"AbortSignal",e)}),Ji=q((e,t)=>{if(typeof e!="function")throw new O(t,"Function",e)}),Qi=q((e,t)=>{if(typeof e!="function"||qi(e))throw new O(t,"Function",e)}),Zi=q((e,t)=>{if(e!==void 0)throw new O(t,"undefined",e)});Ht.exports={isInt32:Ft,isUint32:Bt,parseFileMode:ji,validateArray:Hi,validateBoolean:Ui,validateBuffer:Yi,validateEncoding:Ki,validateFunction:Ji,validateInt32:Ut,validateInteger:vi,validateNumber:Fi,validateObject:Gi,validateOneOf:Bi,validatePlainFunction:Qi,validatePort:zi,validateSignalName:Vi,validateString:Gt,validateUint32:$i,validateUndefined:Zi,validateAbortSignal:Xi}});var V=_((xa,rn)=>{"use strict";var{Symbol:Se,SymbolAsyncIterator:Vt,SymbolIterator:Yt}=T(),Kt=Se("kDestroyed"),zt=Se("kIsErrored"),Ve=Se("kIsReadable"),Xt=Se("kIsDisturbed");function Ee(e,t=!1){var n;return!!(e&&typeof e.pipe=="function"&&typeof e.on=="function"&&(!t||typeof e.pause=="function"&&typeof e.resume=="function")&&(!e._writableState||((n=e._readableState)===null||n===void 0?void 0:n.readable)!==!1)&&(!e._writableState||e._readableState))}function Re(e){var t;return!!(e&&typeof e.write=="function"&&typeof e.on=="function"&&(!e._readableState||((t=e._writableState)===null||t===void 0?void 0:t.writable)!==!1))}function eo(e){return!!(e&&typeof e.pipe=="function"&&e._readableState&&typeof e.on=="function"&&typeof e.write=="function")}function X(e){return e&&(e._readableState||e._writableState||typeof e.write=="function"&&typeof e.on=="function"||typeof e.pipe=="function"&&typeof e.on=="function")}function to(e,t){return e==null?!1:t===!0?typeof e[Vt]=="function":t===!1?typeof e[Yt]=="function":typeof e[Vt]=="function"||typeof e[Yt]=="function"}function Ae(e){if(!X(e))return null;let t=e._writableState,n=e._readableState,r=t||n;return!!(e.destroyed||e[Kt]||r!=null&&r.destroyed)}function Jt(e){if(!Re(e))return null;if(e.writableEnded===!0)return!0;let t=e._writableState;return t!=null&&t.errored?!1:typeof t?.ended!="boolean"?null:t.ended}function no(e,t){if(!Re(e))return null;if(e.writableFinished===!0)return!0;let n=e._writableState;return n!=null&&n.errored?!1:typeof n?.finished!="boolean"?null:!!(n.finished||t===!1&&n.ended===!0&&n.length===0)}function ro(e){if(!Ee(e))return null;if(e.readableEnded===!0)return!0;let t=e._readableState;return!t||t.errored?!1:typeof t?.ended!="boolean"?null:t.ended}function Qt(e,t){if(!Ee(e))return null;let n=e._readableState;return n!=null&&n.errored?!1:typeof n?.endEmitted!="boolean"?null:!!(n.endEmitted||t===!1&&n.ended===!0&&n.length===0)}function Zt(e){return e&&e[Ve]!=null?e[Ve]:typeof e?.readable!="boolean"?null:Ae(e)?!1:Ee(e)&&e.readable&&!Qt(e)}function en(e){return typeof e?.writable!="boolean"?null:Ae(e)?!1:Re(e)&&e.writable&&!Jt(e)}function io(e,t){return X(e)?Ae(e)?!0:!(t?.readable!==!1&&Zt(e)||t?.writable!==!1&&en(e)):null}function oo(e){var t,n;return X(e)?e.writableErrored?e.writableErrored:(t=(n=e._writableState)===null||n===void 0?void 0:n.errored)!==null&&t!==void 0?t:null:null}function lo(e){var t,n;return X(e)?e.readableErrored?e.readableErrored:(t=(n=e._readableState)===null||n===void 0?void 0:n.errored)!==null&&t!==void 0?t:null:null}function fo(e){if(!X(e))return null;if(typeof e.closed=="boolean")return e.closed;let t=e._writableState,n=e._readableState;return typeof t?.closed=="boolean"||typeof n?.closed=="boolean"?t?.closed||n?.closed:typeof e._closed=="boolean"&&tn(e)?e._closed:null}function tn(e){return typeof e._closed=="boolean"&&typeof e._defaultKeepAlive=="boolean"&&typeof e._removedConnection=="boolean"&&typeof e._removedContLen=="boolean"}function nn(e){return typeof e._sent100=="boolean"&&tn(e)}function ao(e){var t;return typeof e._consuming=="boolean"&&typeof e._dumped=="boolean"&&((t=e.req)===null||t===void 0?void 0:t.upgradeOrConnect)===void 0}function so(e){if(!X(e))return null;let t=e._writableState,n=e._readableState,r=t||n;return!r&&nn(e)||!!(r&&r.autoDestroy&&r.emitClose&&r.closed===!1)}function uo(e){var t;return!!(e&&((t=e[Xt])!==null&&t!==void 0?t:e.readableDidRead||e.readableAborted))}function co(e){var t,n,r,i,o,l,s,a,f,c;return!!(e&&((t=(n=(r=(i=(o=(l=e[zt])!==null&&l!==void 0?l:e.readableErrored)!==null&&o!==void 0?o:e.writableErrored)!==null&&i!==void 0?i:(s=e._readableState)===null||s===void 0?void 0:s.errorEmitted)!==null&&r!==void 0?r:(a=e._writableState)===null||a===void 0?void 0:a.errorEmitted)!==null&&n!==void 0?n:(f=e._readableState)===null||f===void 0?void 0:f.errored)!==null&&t!==void 0?t:(c=e._writableState)===null||c===void 0?void 0:c.errored))}rn.exports={kDestroyed:Kt,isDisturbed:uo,kIsDisturbed:Xt,isErrored:co,kIsErrored:zt,isReadable:Zt,kIsReadable:Ve,isClosed:fo,isDestroyed:Ae,isDuplexNodeStream:eo,isFinished:io,isIterable:to,isReadableNodeStream:Ee,isReadableEnded:ro,isReadableFinished:Qt,isReadableErrored:lo,isNodeStream:X,isWritable:en,isWritableNodeStream:Re,isWritableEnded:Jt,isWritableFinished:no,isWritableErrored:oo,isServerRequest:ao,isServerResponse:nn,willEmitClose:so}});var Y=_((Oa,Ke)=>{"use strict";var{AbortError:ho,codes:bo}=D(),{ERR_INVALID_ARG_TYPE:po,ERR_STREAM_PREMATURE_CLOSE:on}=bo,{once:ln}=W(),{validateAbortSignal:wo,validateFunction:yo,validateObject:go}=ue(),{Promise:_o}=T(),{isClosed:So,isReadable:fn,isReadableNodeStream:Ye,isReadableFinished:an,isReadableErrored:Eo,isWritable:sn,isWritableNodeStream:un,isWritableFinished:dn,isWritableErrored:Ro,isNodeStream:Ao,willEmitClose:mo}=V();function To(e){return e.setHeader&&typeof e.abort=="function"}var Io=()=>{};function cn(e,t,n){var r,i;arguments.length===2?(n=t,t={}):t==null?t={}:go(t,"options"),yo(n,"callback"),wo(t.signal,"options.signal"),n=ln(n);let o=(r=t.readable)!==null&&r!==void 0?r:Ye(e),l=(i=t.writable)!==null&&i!==void 0?i:un(e);if(!Ao(e))throw new po("stream","Stream",e);let s=e._writableState,a=e._readableState,f=()=>{e.writable||p()},c=mo(e)&&Ye(e)===o&&un(e)===l,u=dn(e,!1),p=()=>{u=!0,e.destroyed&&(c=!1),!(c&&(!e.readable||o))&&(!o||d)&&n.call(e)},d=an(e,!1),b=()=>{d=!0,e.destroyed&&(c=!1),!(c&&(!e.writable||l))&&(!l||u)&&n.call(e)},M=R=>{n.call(e,R)},g=So(e),h=()=>{g=!0;let R=Ro(e)||Eo(e);if(R&&typeof R!="boolean")return n.call(e,R);if(o&&!d&&Ye(e,!0)&&!an(e,!1))return n.call(e,new on);if(l&&!u&&!dn(e,!1))return n.call(e,new on);n.call(e)},S=()=>{e.req.on("finish",p)};To(e)?(e.on("complete",p),c||e.on("abort",h),e.req?S():e.on("request",S)):l&&!s&&(e.on("end",f),e.on("close",f)),!c&&typeof e.aborted=="boolean"&&e.on("aborted",h),e.on("end",b),e.on("finish",p),t.error!==!1&&e.on("error",M),e.on("close",h),g?__Process$.nextTick(h):s!=null&&s.errorEmitted||a!=null&&a.errorEmitted?c||__Process$.nextTick(h):(!o&&(!c||fn(e))&&(u||sn(e)===!1)||!l&&(!c||sn(e))&&(d||fn(e)===!1)||a&&e.req&&e.aborted)&&__Process$.nextTick(h);let x=()=>{n=Io,e.removeListener("aborted",h),e.removeListener("complete",p),e.removeListener("abort",h),e.removeListener("request",S),e.req&&e.req.removeListener("finish",p),e.removeListener("end",f),e.removeListener("close",f),e.removeListener("finish",p),e.removeListener("end",b),e.removeListener("error",M),e.removeListener("close",h)};if(t.signal&&!g){let R=()=>{let G=n;x(),G.call(e,new ho(void 0,{cause:t.signal.reason}))};if(t.signal.aborted)__Process$.nextTick(R);else{let G=n;n=ln((...L)=>{t.signal.removeEventListener("abort",R),G.apply(e,L)}),t.signal.addEventListener("abort",R)}}return x}function No(e,t){return new _o((n,r)=>{cn(e,t,i=>{i?r(i):n()})})}Ke.exports=cn;Ke.exports.finished=No});var Sn=_((La,Je)=>{"use strict";var wn=globalThis.AbortController,{codes:{ERR_INVALID_ARG_TYPE:de,ERR_MISSING_ARGS:Mo,ERR_OUT_OF_RANGE:Do},AbortError:C}=D(),{validateAbortSignal:te,validateInteger:xo,validateObject:ne}=ue(),Oo=T().Symbol("kWeak"),{finished:Lo}=Y(),{ArrayPrototypePush:Po,MathFloor:qo,Number:ko,NumberIsNaN:Wo,Promise:hn,PromiseReject:bn,PromisePrototypeCatch:Co,Symbol:yn}=T(),me=yn("kEmpty"),pn=yn("kEof");function Te(e,t){if(typeof e!="function")throw new de("fn",["Function","AsyncFunction"],e);t!=null&&ne(t,"options"),t?.signal!=null&&te(t.signal,"options.signal");let n=1;return t?.concurrency!=null&&(n=qo(t.concurrency)),xo(n,"concurrency",1),async function*(){var i,o;let l=new wn,s=this,a=[],f=l.signal,c={signal:f},u=()=>l.abort();t!=null&&(i=t.signal)!==null&&i!==void 0&&i.aborted&&u(),t==null||(o=t.signal)===null||o===void 0||o.addEventListener("abort",u);let p,d,b=!1;function M(){b=!0}async function g(){try{for await(let x of s){var h;if(b)return;if(f.aborted)throw new C;try{x=e(x,c)}catch(R){x=bn(R)}x!==me&&(typeof((h=x)===null||h===void 0?void 0:h.catch)=="function"&&x.catch(M),a.push(x),p&&(p(),p=null),!b&&a.length&&a.length>=n&&await new hn(R=>{d=R}))}a.push(pn)}catch(x){let R=bn(x);Co(R,M),a.push(R)}finally{var S;b=!0,p&&(p(),p=null),t==null||(S=t.signal)===null||S===void 0||S.removeEventListener("abort",u)}}g();try{for(;;){for(;a.length>0;){let h=await a[0];if(h===pn)return;if(f.aborted)throw new C;h!==me&&(yield h),a.shift(),d&&(d(),d=null)}await new hn(h=>{p=h})}}finally{l.abort(),b=!0,d&&(d(),d=null)}}.call(this)}function jo(e=void 0){return e!=null&&ne(e,"options"),e?.signal!=null&&te(e.signal,"options.signal"),async function*(){let n=0;for await(let i of this){var r;if(e!=null&&(r=e.signal)!==null&&r!==void 0&&r.aborted)throw new C({cause:e.signal.reason});yield[n++,i]}}.call(this)}async function gn(e,t=void 0){for await(let n of Xe.call(this,e,t))return!0;return!1}async function vo(e,t=void 0){if(typeof e!="function")throw new de("fn",["Function","AsyncFunction"],e);return!await gn.call(this,async(...n)=>!await e(...n),t)}async function $o(e,t){for await(let n of Xe.call(this,e,t))return n}async function Fo(e,t){if(typeof e!="function")throw new de("fn",["Function","AsyncFunction"],e);async function n(r,i){return await e(r,i),me}for await(let r of Te.call(this,n,t));}function Xe(e,t){if(typeof e!="function")throw new de("fn",["Function","AsyncFunction"],e);async function n(r,i){return await e(r,i)?r:me}return Te.call(this,n,t)}var ze=class extends Mo{constructor(){super("reduce"),this.message="Reduce of an empty stream requires an initial value"}};async function Bo(e,t,n){var r;if(typeof e!="function")throw new de("reducer",["Function","AsyncFunction"],e);n!=null&&ne(n,"options"),n?.signal!=null&&te(n.signal,"options.signal");let i=arguments.length>1;if(n!=null&&(r=n.signal)!==null&&r!==void 0&&r.aborted){let f=new C(void 0,{cause:n.signal.reason});throw this.once("error",()=>{}),await Lo(this.destroy(f)),f}let o=new wn,l=o.signal;if(n!=null&&n.signal){let f={once:!0,[Oo]:this};n.signal.addEventListener("abort",()=>o.abort(),f)}let s=!1;try{for await(let f of this){var a;if(s=!0,n!=null&&(a=n.signal)!==null&&a!==void 0&&a.aborted)throw new C;i?t=await e(t,f,{signal:l}):(t=f,i=!0)}if(!s&&!i)throw new ze}finally{o.abort()}return t}async function Uo(e){e!=null&&ne(e,"options"),e?.signal!=null&&te(e.signal,"options.signal");let t=[];for await(let r of this){var n;if(e!=null&&(n=e.signal)!==null&&n!==void 0&&n.aborted)throw new C(void 0,{cause:e.signal.reason});Po(t,r)}return t}function Go(e,t){let n=Te.call(this,e,t);return async function*(){for await(let i of n)yield*i}.call(this)}function _n(e){if(e=ko(e),Wo(e))return 0;if(e<0)throw new Do("number",">= 0",e);return e}function Ho(e,t=void 0){return t!=null&&ne(t,"options"),t?.signal!=null&&te(t.signal,"options.signal"),e=_n(e),async function*(){var r;if(t!=null&&(r=t.signal)!==null&&r!==void 0&&r.aborted)throw new C;for await(let o of this){var i;if(t!=null&&(i=t.signal)!==null&&i!==void 0&&i.aborted)throw new C;e--<=0&&(yield o)}}.call(this)}function Vo(e,t=void 0){return t!=null&&ne(t,"options"),t?.signal!=null&&te(t.signal,"options.signal"),e=_n(e),async function*(){var r;if(t!=null&&(r=t.signal)!==null&&r!==void 0&&r.aborted)throw new C;for await(let o of this){var i;if(t!=null&&(i=t.signal)!==null&&i!==void 0&&i.aborted)throw new C;if(e-- >0)yield o;else return}}.call(this)}Je.exports.streamReturningOperators={asIndexedPairs:jo,drop:Ho,filter:Xe,flatMap:Go,map:Te,take:Vo};Je.exports.promiseReturningOperators={every:vo,forEach:Fo,reduce:Bo,toArray:Uo,some:gn,find:$o}});var J=_((Pa,Mn)=>{"use strict";var{aggregateTwoErrors:Yo,codes:{ERR_MULTIPLE_CALLBACK:Ko},AbortError:zo}=D(),{Symbol:An}=T(),{kDestroyed:Xo,isDestroyed:Jo,isFinished:Qo,isServerRequest:Zo}=V(),mn=An("kDestroy"),Qe=An("kConstruct");function Tn(e,t,n){e&&(e.stack,t&&!t.errored&&(t.errored=e),n&&!n.errored&&(n.errored=e))}function el(e,t){let n=this._readableState,r=this._writableState,i=r||n;return r&&r.destroyed||n&&n.destroyed?(typeof t=="function"&&t(),this):(Tn(e,r,n),r&&(r.destroyed=!0),n&&(n.destroyed=!0),i.constructed?En(this,e,t):this.once(mn,function(o){En(this,Yo(o,e),t)}),this)}function En(e,t,n){let r=!1;function i(o){if(r)return;r=!0;let l=e._readableState,s=e._writableState;Tn(o,s,l),s&&(s.closed=!0),l&&(l.closed=!0),typeof n=="function"&&n(o),o?__Process$.nextTick(tl,e,o):__Process$.nextTick(In,e)}try{e._destroy(t||null,i)}catch(o){i(o)}}function tl(e,t){Ze(e,t),In(e)}function In(e){let t=e._readableState,n=e._writableState;n&&(n.closeEmitted=!0),t&&(t.closeEmitted=!0),(n&&n.emitClose||t&&t.emitClose)&&e.emit("close")}function Ze(e,t){let n=e._readableState,r=e._writableState;r&&r.errorEmitted||n&&n.errorEmitted||(r&&(r.errorEmitted=!0),n&&(n.errorEmitted=!0),e.emit("error",t))}function nl(){let e=this._readableState,t=this._writableState;e&&(e.constructed=!0,e.closed=!1,e.closeEmitted=!1,e.destroyed=!1,e.errored=null,e.errorEmitted=!1,e.reading=!1,e.ended=e.readable===!1,e.endEmitted=e.readable===!1),t&&(t.constructed=!0,t.destroyed=!1,t.closed=!1,t.closeEmitted=!1,t.errored=null,t.errorEmitted=!1,t.finalCalled=!1,t.prefinished=!1,t.ended=t.writable===!1,t.ending=t.writable===!1,t.finished=t.writable===!1)}function et(e,t,n){let r=e._readableState,i=e._writableState;if(i&&i.destroyed||r&&r.destroyed)return this;r&&r.autoDestroy||i&&i.autoDestroy?e.destroy(t):t&&(t.stack,i&&!i.errored&&(i.errored=t),r&&!r.errored&&(r.errored=t),n?__Process$.nextTick(Ze,e,t):Ze(e,t))}function rl(e,t){if(typeof e._construct!="function")return;let n=e._readableState,r=e._writableState;n&&(n.constructed=!1),r&&(r.constructed=!1),e.once(Qe,t),!(e.listenerCount(Qe)>1)&&__Process$.nextTick(il,e)}function il(e){let t=!1;function n(r){if(t){et(e,r??new Ko);return}t=!0;let i=e._readableState,o=e._writableState,l=o||i;i&&(i.constructed=!0),o&&(o.constructed=!0),l.destroyed?e.emit(mn,r):r?et(e,r,!0):__Process$.nextTick(ol,e)}try{e._construct(n)}catch(r){n(r)}}function ol(e){e.emit(Qe)}function Rn(e){return e&&e.setHeader&&typeof e.abort=="function"}function Nn(e){e.emit("close")}function ll(e,t){e.emit("error",t),__Process$.nextTick(Nn,e)}function fl(e,t){!e||Jo(e)||(!t&&!Qo(e)&&(t=new zo),Zo(e)?(e.socket=null,e.destroy(t)):Rn(e)?e.abort():Rn(e.req)?e.req.abort():typeof e.destroy=="function"?e.destroy(t):typeof e.close=="function"?e.close():t?__Process$.nextTick(ll,e):__Process$.nextTick(Nn,e),e.destroyed||(e[Xo]=!0))}Mn.exports={construct:rl,destroyer:fl,destroy:el,undestroy:nl,errorOrDestroy:et}});var Me=_((qa,xn)=>{"use strict";var{ArrayIsArray:al,ObjectSetPrototypeOf:Dn}=T(),{EventEmitter:Ie}=__events$;function Ne(e){Ie.call(this,e)}Dn(Ne.prototype,Ie.prototype);Dn(Ne,Ie);Ne.prototype.pipe=function(e,t){let n=this;function r(c){e.writable&&e.write(c)===!1&&n.pause&&n.pause()}n.on("data",r);function i(){n.readable&&n.resume&&n.resume()}e.on("drain",i),!e._isStdio&&(!t||t.end!==!1)&&(n.on("end",l),n.on("close",s));let o=!1;function l(){o||(o=!0,e.end())}function s(){o||(o=!0,typeof e.destroy=="function"&&e.destroy())}function a(c){f(),Ie.listenerCount(this,"error")===0&&this.emit("error",c)}tt(n,"error",a),tt(e,"error",a);function f(){n.removeListener("data",r),e.removeListener("drain",i),n.removeListener("end",l),n.removeListener("close",s),n.removeListener("error",a),e.removeListener("error",a),n.removeListener("end",f),n.removeListener("close",f),e.removeListener("close",f)}return n.on("end",f),n.on("close",f),e.on("close",f),e.emit("pipe",n),e};function tt(e,t,n){if(typeof e.prependListener=="function")return e.prependListener(t,n);!e._events||!e._events[t]?e.on(t,n):al(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]}xn.exports={Stream:Ne,prependListener:tt}});var xe=_((ka,De)=>{"use strict";var{AbortError:sl,codes:ul}=D(),dl=Y(),{ERR_INVALID_ARG_TYPE:On}=ul,cl=(e,t)=>{if(typeof e!="object"||!("aborted"in e))throw new On(t,"AbortSignal",e)};function hl(e){return!!(e&&typeof e.pipe=="function")}De.exports.addAbortSignal=function(t,n){if(cl(t,"signal"),!hl(n))throw new On("stream","stream.Stream",n);return De.exports.addAbortSignalNoValidate(t,n)};De.exports.addAbortSignalNoValidate=function(e,t){if(typeof e!="object"||!("aborted"in e))return t;let n=()=>{t.destroy(new sl(void 0,{cause:e.reason}))};return e.aborted?n():(e.addEventListener("abort",n),dl(t,()=>e.removeEventListener("abort",n))),t}});var qn=_((Ca,Pn)=>{"use strict";var{StringPrototypeSlice:Ln,SymbolIterator:bl,TypedArrayPrototypeSet:Oe,Uint8Array:pl}=T(),{inspect:wl}=W();Pn.exports=class{constructor(){this.head=null,this.tail=null,this.length=0}push(t){let n={data:t,next:null};this.length>0?this.tail.next=n:this.head=n,this.tail=n,++this.length}unshift(t){let n={data:t,next:this.head};this.length===0&&(this.tail=n),this.head=n,++this.length}shift(){if(this.length===0)return;let t=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,t}clear(){this.head=this.tail=null,this.length=0}join(t){if(this.length===0)return"";let n=this.head,r=""+n.data;for(;(n=n.next)!==null;)r+=t+n.data;return r}concat(t){if(this.length===0)return __Buffer$.alloc(0);let n=__Buffer$.allocUnsafe(t>>>0),r=this.head,i=0;for(;r;)Oe(n,r.data,i),i+=r.data.length,r=r.next;return n}consume(t,n){let r=this.head.data;if(to.length)n+=o,t-=o.length;else{t===o.length?(n+=o,++i,r.next?this.head=r.next:this.head=this.tail=null):(n+=Ln(o,0,t),this.head=r,r.data=Ln(o,t));break}++i}while((r=r.next)!==null);return this.length-=i,n}_getBuffer(t){let n=__Buffer$.allocUnsafe(t),r=t,i=this.head,o=0;do{let l=i.data;if(t>l.length)Oe(n,l,r-t),t-=l.length;else{t===l.length?(Oe(n,l,r-t),++o,i.next?this.head=i.next:this.head=this.tail=null):(Oe(n,new pl(l.buffer,l.byteOffset,t),r-t),this.head=i,i.data=l.slice(t));break}++o}while((i=i.next)!==null);return this.length-=o,n}[Symbol.for("nodejs.util.inspect.custom")](t,n){return wl(this,{...n,depth:0,customInspect:!1})}}});var nt=_((ja,Wn)=>{"use strict";var{MathFloor:yl,NumberIsInteger:gl}=T(),{ERR_INVALID_ARG_VALUE:_l}=D().codes;function Sl(e,t,n){return e.highWaterMark!=null?e.highWaterMark:t?e[n]:null}function kn(e){return e?16:16*1024}function El(e,t,n,r){let i=Sl(t,r,n);if(i!=null){if(!gl(i)||i<0){let o=r?`options.${n}`:"options.highWaterMark";throw new _l(o,i)}return yl(i)}return kn(e.objectMode)}Wn.exports={getHighWaterMark:El,getDefaultHighWaterMark:kn}});var rt=_((va,vn)=>{"use strict";var{PromisePrototypeThen:Rl,SymbolAsyncIterator:Cn,SymbolIterator:jn}=T(),{ERR_INVALID_ARG_TYPE:Al,ERR_STREAM_NULL_VALUES:ml}=D().codes;function Tl(e,t,n){let r;if(typeof t=="string"||t instanceof __Buffer$)return new e({objectMode:!0,...n,read(){this.push(t),this.push(null)}});let i;if(t&&t[Cn])i=!0,r=t[Cn]();else if(t&&t[jn])i=!1,r=t[jn]();else throw new Al("iterable",["Iterable"],t);let o=new e({objectMode:!0,highWaterMark:1,...n}),l=!1;o._read=function(){l||(l=!0,a())},o._destroy=function(f,c){Rl(s(f),()=>__Process$.nextTick(c,f),u=>__Process$.nextTick(c,u||f))};async function s(f){let c=f!=null,u=typeof r.throw=="function";if(c&&u){let{value:p,done:d}=await r.throw(f);if(await p,d)return}if(typeof r.return=="function"){let{value:p}=await r.return();await p}}async function a(){for(;;){try{let{value:f,done:c}=i?await r.next():r.next();if(c)o.push(null);else{let u=f&&typeof f.then=="function"?await f:f;if(u===null)throw l=!1,new ml;if(o.push(u))continue;l=!1}}catch(f){o.destroy(f)}break}}return o}vn.exports=Tl});var ce=_(($a,Qn)=>{"use strict";var{ArrayPrototypeIndexOf:Il,NumberIsInteger:Nl,NumberIsNaN:Ml,NumberParseInt:Dl,ObjectDefineProperties:Bn,ObjectKeys:xl,ObjectSetPrototypeOf:Un,Promise:Ol,SafeSet:Ll,SymbolAsyncIterator:Pl,Symbol:ql}=T();Qn.exports=w;w.ReadableState=at;var{EventEmitter:kl}=__events$,{Stream:K,prependListener:Wl}=Me(),{addAbortSignal:Cl}=xe(),jl=Y(),y=W().debuglog("stream",e=>{y=e}),vl=qn(),ie=J(),{getHighWaterMark:$l,getDefaultHighWaterMark:Fl}=nt(),{aggregateTwoErrors:$n,codes:{ERR_INVALID_ARG_TYPE:Bl,ERR_METHOD_NOT_IMPLEMENTED:Ul,ERR_OUT_OF_RANGE:Gl,ERR_STREAM_PUSH_AFTER_EOF:Hl,ERR_STREAM_UNSHIFT_AFTER_END_EVENT:Vl}}=D(),{validateObject:Yl}=ue(),Q=ql("kPaused"),{StringDecoder:Gn}=__string_decoder$,Kl=rt();Un(w.prototype,K.prototype);Un(w,K);var it=()=>{},{errorOrDestroy:re}=ie;function at(e,t,n){typeof n!="boolean"&&(n=t instanceof j()),this.objectMode=!!(e&&e.objectMode),n&&(this.objectMode=this.objectMode||!!(e&&e.readableObjectMode)),this.highWaterMark=e?$l(this,e,"readableHighWaterMark",n):Fl(!1),this.buffer=new vl,this.length=0,this.pipes=[],this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.constructed=!0,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this[Q]=null,this.errorEmitted=!1,this.emitClose=!e||e.emitClose!==!1,this.autoDestroy=!e||e.autoDestroy!==!1,this.destroyed=!1,this.errored=null,this.closed=!1,this.closeEmitted=!1,this.defaultEncoding=e&&e.defaultEncoding||"utf8",this.awaitDrainWriters=null,this.multiAwaitDrain=!1,this.readingMore=!1,this.dataEmitted=!1,this.decoder=null,this.encoding=null,e&&e.encoding&&(this.decoder=new Gn(e.encoding),this.encoding=e.encoding)}function w(e){if(!(this instanceof w))return new w(e);let t=this instanceof j();this._readableState=new at(e,this,t),e&&(typeof e.read=="function"&&(this._read=e.read),typeof e.destroy=="function"&&(this._destroy=e.destroy),typeof e.construct=="function"&&(this._construct=e.construct),e.signal&&!t&&Cl(e.signal,this)),K.call(this,e),ie.construct(this,()=>{this._readableState.needReadable&&Le(this,this._readableState)})}w.prototype.destroy=ie.destroy;w.prototype._undestroy=ie.undestroy;w.prototype._destroy=function(e,t){t(e)};w.prototype[kl.captureRejectionSymbol]=function(e){this.destroy(e)};w.prototype.push=function(e,t){return Hn(this,e,t,!1)};w.prototype.unshift=function(e,t){return Hn(this,e,t,!0)};function Hn(e,t,n,r){y("readableAddChunk",t);let i=e._readableState,o;if(i.objectMode||(typeof t=="string"?(n=n||i.defaultEncoding,i.encoding!==n&&(r&&i.encoding?t=__Buffer$.from(t,n).toString(i.encoding):(t=__Buffer$.from(t,n),n=""))):t instanceof __Buffer$?n="":K._isUint8Array(t)?(t=K._uint8ArrayToBuffer(t),n=""):t!=null&&(o=new Bl("chunk",["string","Buffer","Uint8Array"],t))),o)re(e,o);else if(t===null)i.reading=!1,Jl(e,i);else if(i.objectMode||t&&t.length>0)if(r)if(i.endEmitted)re(e,new Vl);else{if(i.destroyed||i.errored)return!1;ot(e,i,t,!0)}else if(i.ended)re(e,new Hl);else{if(i.destroyed||i.errored)return!1;i.reading=!1,i.decoder&&!n?(t=i.decoder.write(t),i.objectMode||t.length!==0?ot(e,i,t,!1):Le(e,i)):ot(e,i,t,!1)}else r||(i.reading=!1,Le(e,i));return!i.ended&&(i.length0?(t.multiAwaitDrain?t.awaitDrainWriters.clear():t.awaitDrainWriters=null,t.dataEmitted=!0,e.emit("data",n)):(t.length+=t.objectMode?1:n.length,r?t.buffer.unshift(n):t.buffer.push(n),t.needReadable&&Pe(e)),Le(e,t)}w.prototype.isPaused=function(){let e=this._readableState;return e[Q]===!0||e.flowing===!1};w.prototype.setEncoding=function(e){let t=new Gn(e);this._readableState.decoder=t,this._readableState.encoding=this._readableState.decoder.encoding;let n=this._readableState.buffer,r="";for(let i of n)r+=t.write(i);return n.clear(),r!==""&&n.push(r),this._readableState.length=r.length,this};var zl=1073741824;function Xl(e){if(e>zl)throw new Gl("size","<= 1GiB",e);return e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++,e}function Fn(e,t){return e<=0||t.length===0&&t.ended?0:t.objectMode?1:Ml(e)?t.flowing&&t.length?t.buffer.first().length:t.length:e<=t.length?e:t.ended?t.length:0}w.prototype.read=function(e){y("read",e),e===void 0?e=NaN:Nl(e)||(e=Dl(e,10));let t=this._readableState,n=e;if(e>t.highWaterMark&&(t.highWaterMark=Xl(e)),e!==0&&(t.emittedReadable=!1),e===0&&t.needReadable&&((t.highWaterMark!==0?t.length>=t.highWaterMark:t.length>0)||t.ended))return y("read: emitReadable",t.length,t.ended),t.length===0&&t.ended?lt(this):Pe(this),null;if(e=Fn(e,t),e===0&&t.ended)return t.length===0&<(this),null;let r=t.needReadable;if(y("need readable",r),(t.length===0||t.length-e0?i=Xn(e,t):i=null,i===null?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.multiAwaitDrain?t.awaitDrainWriters.clear():t.awaitDrainWriters=null),t.length===0&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&<(this)),i!==null&&!t.errorEmitted&&!t.closeEmitted&&(t.dataEmitted=!0,this.emit("data",i)),i};function Jl(e,t){if(y("onEofChunk"),!t.ended){if(t.decoder){let n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,t.sync?Pe(e):(t.needReadable=!1,t.emittedReadable=!0,Vn(e))}}function Pe(e){let t=e._readableState;y("emitReadable",t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(y("emitReadable",t.flowing),t.emittedReadable=!0,__Process$.nextTick(Vn,e))}function Vn(e){let t=e._readableState;y("emitReadable_",t.destroyed,t.length,t.ended),!t.destroyed&&!t.errored&&(t.length||t.ended)&&(e.emit("readable"),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,Kn(e)}function Le(e,t){!t.readingMore&&t.constructed&&(t.readingMore=!0,__Process$.nextTick(Ql,e,t))}function Ql(e,t){for(;!t.reading&&!t.ended&&(t.length1&&r.pipes.includes(e)&&(y("false write response, pause",r.awaitDrainWriters.size),r.awaitDrainWriters.add(e)),n.pause()),a||(a=Zl(n,e),e.on("drain",a))}n.on("data",p);function p(h){y("ondata");let S=e.write(h);y("dest.write",S),S===!1&&u()}function d(h){if(y("onerror",h),g(),e.removeListener("error",d),e.listenerCount("error")===0){let S=e._writableState||e._readableState;S&&!S.errorEmitted?re(e,h):e.emit("error",h)}}Wl(e,"error",d);function b(){e.removeListener("finish",M),g()}e.once("close",b);function M(){y("onfinish"),e.removeListener("close",b),g()}e.once("finish",M);function g(){y("unpipe"),n.unpipe(e)}return e.emit("pipe",n),e.writableNeedDrain===!0?r.flowing&&u():r.flowing||(y("pipe resume"),n.resume()),e};function Zl(e,t){return function(){let r=e._readableState;r.awaitDrainWriters===t?(y("pipeOnDrain",1),r.awaitDrainWriters=null):r.multiAwaitDrain&&(y("pipeOnDrain",r.awaitDrainWriters.size),r.awaitDrainWriters.delete(t)),(!r.awaitDrainWriters||r.awaitDrainWriters.size===0)&&e.listenerCount("data")&&e.resume()}}w.prototype.unpipe=function(e){let t=this._readableState,n={hasUnpiped:!1};if(t.pipes.length===0)return this;if(!e){let i=t.pipes;t.pipes=[],this.pause();for(let o=0;o0,r.flowing!==!1&&this.resume()):e==="readable"&&!r.endEmitted&&!r.readableListening&&(r.readableListening=r.needReadable=!0,r.flowing=!1,r.emittedReadable=!1,y("on readable",r.length,r.reading),r.length?Pe(this):r.reading||__Process$.nextTick(ef,this)),n};w.prototype.addListener=w.prototype.on;w.prototype.removeListener=function(e,t){let n=K.prototype.removeListener.call(this,e,t);return e==="readable"&&__Process$.nextTick(Yn,this),n};w.prototype.off=w.prototype.removeListener;w.prototype.removeAllListeners=function(e){let t=K.prototype.removeAllListeners.apply(this,arguments);return(e==="readable"||e===void 0)&&__Process$.nextTick(Yn,this),t};function Yn(e){let t=e._readableState;t.readableListening=e.listenerCount("readable")>0,t.resumeScheduled&&t[Q]===!1?t.flowing=!0:e.listenerCount("data")>0?e.resume():t.readableListening||(t.flowing=null)}function ef(e){y("readable nexttick read 0"),e.read(0)}w.prototype.resume=function(){let e=this._readableState;return e.flowing||(y("resume"),e.flowing=!e.readableListening,tf(this,e)),e[Q]=!1,this};function tf(e,t){t.resumeScheduled||(t.resumeScheduled=!0,__Process$.nextTick(nf,e,t))}function nf(e,t){y("resume",t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit("resume"),Kn(e),t.flowing&&!t.reading&&e.read(0)}w.prototype.pause=function(){return y("call pause flowing=%j",this._readableState.flowing),this._readableState.flowing!==!1&&(y("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState[Q]=!0,this};function Kn(e){let t=e._readableState;for(y("flow",t.flowing);t.flowing&&e.read()!==null;);}w.prototype.wrap=function(e){let t=!1;e.on("data",r=>{!this.push(r)&&e.pause&&(t=!0,e.pause())}),e.on("end",()=>{this.push(null)}),e.on("error",r=>{re(this,r)}),e.on("close",()=>{this.destroy()}),e.on("destroy",()=>{this.destroy()}),this._read=()=>{t&&e.resume&&(t=!1,e.resume())};let n=xl(e);for(let r=1;r{i=l?$n(i,l):null,n(),n=it});try{for(;;){let l=e.destroyed?null:e.read();if(l!==null)yield l;else{if(i)throw i;if(i===null)return;await new Ol(r)}}}catch(l){throw i=$n(i,l),i}finally{(i||t?.destroyOnReturn!==!1)&&(i===void 0||e._readableState.autoDestroy)?ie.destroyer(e,null):(e.off("readable",r),o())}}Bn(w.prototype,{readable:{get(){let e=this._readableState;return!!e&&e.readable!==!1&&!e.destroyed&&!e.errorEmitted&&!e.endEmitted},set(e){this._readableState&&(this._readableState.readable=!!e)}},readableDidRead:{enumerable:!1,get:function(){return this._readableState.dataEmitted}},readableAborted:{enumerable:!1,get:function(){return!!(this._readableState.readable!==!1&&(this._readableState.destroyed||this._readableState.errored)&&!this._readableState.endEmitted)}},readableHighWaterMark:{enumerable:!1,get:function(){return this._readableState.highWaterMark}},readableBuffer:{enumerable:!1,get:function(){return this._readableState&&this._readableState.buffer}},readableFlowing:{enumerable:!1,get:function(){return this._readableState.flowing},set:function(e){this._readableState&&(this._readableState.flowing=e)}},readableLength:{enumerable:!1,get(){return this._readableState.length}},readableObjectMode:{enumerable:!1,get(){return this._readableState?this._readableState.objectMode:!1}},readableEncoding:{enumerable:!1,get(){return this._readableState?this._readableState.encoding:null}},errored:{enumerable:!1,get(){return this._readableState?this._readableState.errored:null}},closed:{get(){return this._readableState?this._readableState.closed:!1}},destroyed:{enumerable:!1,get(){return this._readableState?this._readableState.destroyed:!1},set(e){!this._readableState||(this._readableState.destroyed=e)}},readableEnded:{enumerable:!1,get(){return this._readableState?this._readableState.endEmitted:!1}}});Bn(at.prototype,{pipesCount:{get(){return this.pipes.length}},paused:{get(){return this[Q]!==!1},set(e){this[Q]=!!e}}});w._fromList=Xn;function Xn(e,t){if(t.length===0)return null;let n;return t.objectMode?n=t.buffer.shift():!e||e>=t.length?(t.decoder?n=t.buffer.join(""):t.buffer.length===1?n=t.buffer.first():n=t.buffer.concat(t.length),t.buffer.clear()):n=t.buffer.consume(e,t.decoder),n}function lt(e){let t=e._readableState;y("endReadable",t.endEmitted),t.endEmitted||(t.ended=!0,__Process$.nextTick(of,t,e))}function of(e,t){if(y("endReadableNT",e.endEmitted,e.length),!e.errored&&!e.closeEmitted&&!e.endEmitted&&e.length===0){if(e.endEmitted=!0,t.emit("end"),t.writable&&t.allowHalfOpen===!1)__Process$.nextTick(lf,t);else if(e.autoDestroy){let n=t._writableState;(!n||n.autoDestroy&&(n.finished||n.writable===!1))&&t.destroy()}}}function lf(e){e.writable&&!e.writableEnded&&!e.destroyed&&e.end()}w.from=function(e,t){return Kl(w,e,t)};var ft;function Jn(){return ft===void 0&&(ft={}),ft}w.fromWeb=function(e,t){return Jn().newStreamReadableFromReadableStream(e,t)};w.toWeb=function(e){return Jn().newReadableStreamFromStreamReadable(e)};w.wrap=function(e,t){var n,r;return new w({objectMode:(n=(r=e.readableObjectMode)!==null&&r!==void 0?r:e.objectMode)!==null&&n!==void 0?n:!0,...t,destroy(i,o){ie.destroyer(e,i),o(i)}}).wrap(e)}});var pt=_((Fa,ur)=>{"use strict";var{ArrayPrototypeSlice:tr,Error:ff,FunctionPrototypeSymbolHasInstance:nr,ObjectDefineProperty:rr,ObjectDefineProperties:af,ObjectSetPrototypeOf:ir,StringPrototypeToLowerCase:sf,Symbol:uf,SymbolHasInstance:df}=T();ur.exports=E;E.WritableState=pe;var{EventEmitter:cf}=__events$,he=Me().Stream,We=J(),{addAbortSignal:hf}=xe(),{getHighWaterMark:bf,getDefaultHighWaterMark:pf}=nt(),{ERR_INVALID_ARG_TYPE:wf,ERR_METHOD_NOT_IMPLEMENTED:yf,ERR_MULTIPLE_CALLBACK:or,ERR_STREAM_CANNOT_PIPE:gf,ERR_STREAM_DESTROYED:be,ERR_STREAM_ALREADY_FINISHED:_f,ERR_STREAM_NULL_VALUES:Sf,ERR_STREAM_WRITE_AFTER_END:Ef,ERR_UNKNOWN_ENCODING:lr}=D().codes,{errorOrDestroy:oe}=We;ir(E.prototype,he.prototype);ir(E,he);function dt(){}var le=uf("kOnFinished");function pe(e,t,n){typeof n!="boolean"&&(n=t instanceof j()),this.objectMode=!!(e&&e.objectMode),n&&(this.objectMode=this.objectMode||!!(e&&e.writableObjectMode)),this.highWaterMark=e?bf(this,e,"writableHighWaterMark",n):pf(!1),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;let r=!!(e&&e.decodeStrings===!1);this.decodeStrings=!r,this.defaultEncoding=e&&e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=Af.bind(void 0,t),this.writecb=null,this.writelen=0,this.afterWriteTickInfo=null,ke(this),this.pendingcb=0,this.constructed=!0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=!e||e.emitClose!==!1,this.autoDestroy=!e||e.autoDestroy!==!1,this.errored=null,this.closed=!1,this.closeEmitted=!1,this[le]=[]}function ke(e){e.buffered=[],e.bufferedIndex=0,e.allBuffers=!0,e.allNoop=!0}pe.prototype.getBuffer=function(){return tr(this.buffered,this.bufferedIndex)};rr(pe.prototype,"bufferedRequestCount",{get(){return this.buffered.length-this.bufferedIndex}});function E(e){let t=this instanceof j();if(!t&&!nr(E,this))return new E(e);this._writableState=new pe(e,this,t),e&&(typeof e.write=="function"&&(this._write=e.write),typeof e.writev=="function"&&(this._writev=e.writev),typeof e.destroy=="function"&&(this._destroy=e.destroy),typeof e.final=="function"&&(this._final=e.final),typeof e.construct=="function"&&(this._construct=e.construct),e.signal&&hf(e.signal,this)),he.call(this,e),We.construct(this,()=>{let n=this._writableState;n.writing||ht(this,n),bt(this,n)})}rr(E,df,{value:function(e){return nr(this,e)?!0:this!==E?!1:e&&e._writableState instanceof pe}});E.prototype.pipe=function(){oe(this,new gf)};function fr(e,t,n,r){let i=e._writableState;if(typeof n=="function")r=n,n=i.defaultEncoding;else{if(!n)n=i.defaultEncoding;else if(n!=="buffer"&&!__Buffer$.isEncoding(n))throw new lr(n);typeof r!="function"&&(r=dt)}if(t===null)throw new Sf;if(!i.objectMode)if(typeof t=="string")i.decodeStrings!==!1&&(t=__Buffer$.from(t,n),n="buffer");else if(t instanceof __Buffer$)n="buffer";else if(he._isUint8Array(t))t=he._uint8ArrayToBuffer(t),n="buffer";else throw new wf("chunk",["string","Buffer","Uint8Array"],t);let o;return i.ending?o=new Ef:i.destroyed&&(o=new be("write")),o?(__Process$.nextTick(r,o),oe(e,o,!0),o):(i.pendingcb++,Rf(e,i,t,n,r))}E.prototype.write=function(e,t,n){return fr(this,e,t,n)===!0};E.prototype.cork=function(){this._writableState.corked++};E.prototype.uncork=function(){let e=this._writableState;e.corked&&(e.corked--,e.writing||ht(this,e))};E.prototype.setDefaultEncoding=function(t){if(typeof t=="string"&&(t=sf(t)),!__Buffer$.isEncoding(t))throw new lr(t);return this._writableState.defaultEncoding=t,this};function Rf(e,t,n,r,i){let o=t.objectMode?1:n.length;t.length+=o;let l=t.lengthn.bufferedIndex&&ht(e,n),r?n.afterWriteTickInfo!==null&&n.afterWriteTickInfo.cb===i?n.afterWriteTickInfo.count++:(n.afterWriteTickInfo={count:1,cb:i,stream:e,state:n},__Process$.nextTick(mf,n.afterWriteTickInfo)):ar(e,n,1,i))}function mf({stream:e,state:t,count:n,cb:r}){return t.afterWriteTickInfo=null,ar(e,t,n,r)}function ar(e,t,n,r){for(!t.ending&&!e.destroyed&&t.length===0&&t.needDrain&&(t.needDrain=!1,e.emit("drain"));n-- >0;)t.pendingcb--,r();t.destroyed&&ct(t),bt(e,t)}function ct(e){if(e.writing)return;for(let i=e.bufferedIndex;i1&&e._writev){t.pendingcb-=o-1;let s=t.allNoop?dt:f=>{for(let c=l;c256?(n.splice(0,l),t.bufferedIndex=0):t.bufferedIndex=l}t.bufferProcessing=!1}E.prototype._write=function(e,t,n){if(this._writev)this._writev([{chunk:e,encoding:t}],n);else throw new yf("_write()")};E.prototype._writev=null;E.prototype.end=function(e,t,n){let r=this._writableState;typeof e=="function"?(n=e,e=null,t=null):typeof t=="function"&&(n=t,t=null);let i;if(e!=null){let o=fr(this,e,t);o instanceof ff&&(i=o)}return r.corked&&(r.corked=1,this.uncork()),i||(!r.errored&&!r.ending?(r.ending=!0,bt(this,r,!0),r.ended=!0):r.finished?i=new _f("end"):r.destroyed&&(i=new be("end"))),typeof n=="function"&&(i||r.finished?__Process$.nextTick(n,i):r[le].push(n)),this};function qe(e){return e.ending&&!e.destroyed&&e.constructed&&e.length===0&&!e.errored&&e.buffered.length===0&&!e.finished&&!e.writing&&!e.errorEmitted&&!e.closeEmitted}function Tf(e,t){let n=!1;function r(i){if(n){oe(e,i??or());return}if(n=!0,t.pendingcb--,i){let o=t[le].splice(0);for(let l=0;l{qe(i)?ut(r,i):i.pendingcb--},e,t)):qe(t)&&(t.pendingcb++,ut(e,t))))}function ut(e,t){t.pendingcb--,t.finished=!0;let n=t[le].splice(0);for(let r=0;r{"use strict";var Mf=__buffer$,{isReadable:Df,isWritable:xf,isIterable:dr,isNodeStream:Of,isReadableNodeStream:cr,isWritableNodeStream:hr,isDuplexNodeStream:Lf}=V(),br=Y(),{AbortError:Sr,codes:{ERR_INVALID_ARG_TYPE:Pf,ERR_INVALID_RETURN_VALUE:pr}}=D(),{destroyer:fe}=J(),qf=j(),kf=ce(),{createDeferredPromise:wr}=W(),yr=rt(),gr=globalThis.Blob||Mf.Blob,Wf=typeof gr<"u"?function(t){return t instanceof gr}:function(t){return!1},Cf=globalThis.AbortController,{FunctionPrototypeCall:_r}=T(),Z=class extends qf{constructor(t){super(t),t?.readable===!1&&(this._readableState.readable=!1,this._readableState.ended=!0,this._readableState.endEmitted=!0),t?.writable===!1&&(this._writableState.writable=!1,this._writableState.ending=!0,this._writableState.ended=!0,this._writableState.finished=!0)}};Er.exports=function e(t,n){if(Lf(t))return t;if(cr(t))return Ce({readable:t});if(hr(t))return Ce({writable:t});if(Of(t))return Ce({writable:!1,readable:!1});if(typeof t=="function"){let{value:i,write:o,final:l,destroy:s}=jf(t);if(dr(i))return yr(Z,i,{objectMode:!0,write:o,final:l,destroy:s});let a=i?.then;if(typeof a=="function"){let f,c=_r(a,i,u=>{if(u!=null)throw new pr("nully","body",u)},u=>{fe(f,u)});return f=new Z({objectMode:!0,readable:!1,write:o,final(u){l(async()=>{try{await c,__Process$.nextTick(u,null)}catch(p){__Process$.nextTick(u,p)}})},destroy:s})}throw new pr("Iterable, AsyncIterable or AsyncFunction",n,i)}if(Wf(t))return e(t.arrayBuffer());if(dr(t))return yr(Z,t,{objectMode:!0,writable:!1});if(typeof t?.writable=="object"||typeof t?.readable=="object"){let i=t!=null&&t.readable?cr(t?.readable)?t?.readable:e(t.readable):void 0,o=t!=null&&t.writable?hr(t?.writable)?t?.writable:e(t.writable):void 0;return Ce({readable:i,writable:o})}let r=t?.then;if(typeof r=="function"){let i;return _r(r,t,o=>{o!=null&&i.push(o),i.push(null)},o=>{fe(i,o)}),i=new Z({objectMode:!0,writable:!1,read(){}})}throw new Pf(n,["Blob","ReadableStream","WritableStream","Stream","Iterable","AsyncIterable","Function","{ readable, writable } pair","Promise"],t)};function jf(e){let{promise:t,resolve:n}=wr(),r=new Cf,i=r.signal;return{value:e(async function*(){for(;;){let l=t;t=null;let{chunk:s,done:a,cb:f}=await l;if(__Process$.nextTick(f),a)return;if(i.aborted)throw new Sr(void 0,{cause:i.reason});({promise:t,resolve:n}=wr()),yield s}}(),{signal:i}),write(l,s,a){let f=n;n=null,f({chunk:l,done:!1,cb:a})},final(l){let s=n;n=null,s({done:!0,cb:l})},destroy(l,s){r.abort(),s(l)}}}function Ce(e){let t=e.readable&&typeof e.readable.read!="function"?kf.wrap(e.readable):e.readable,n=e.writable,r=!!Df(t),i=!!xf(n),o,l,s,a,f;function c(u){let p=a;a=null,p?p(u):u?f.destroy(u):!r&&!i&&f.destroy()}return f=new Z({readableObjectMode:!!(t!=null&&t.readableObjectMode),writableObjectMode:!!(n!=null&&n.writableObjectMode),readable:r,writable:i}),i&&(br(n,u=>{i=!1,u&&fe(t,u),c(u)}),f._write=function(u,p,d){n.write(u,p)?d():o=d},f._final=function(u){n.end(),l=u},n.on("drain",function(){if(o){let u=o;o=null,u()}}),n.on("finish",function(){if(l){let u=l;l=null,u()}})),r&&(br(t,u=>{r=!1,u&&fe(t,u),c(u)}),t.on("readable",function(){if(s){let u=s;s=null,u()}}),t.on("end",function(){f.push(null)}),f._read=function(){for(;;){let u=t.read();if(u===null){s=f._read;return}if(!f.push(u))return}}),f._destroy=function(u,p){!u&&a!==null&&(u=new Sr),s=null,o=null,l=null,a===null?p(u):(a=p,fe(n,u),fe(t,u))},f}});var j=_((Ua,Tr)=>{"use strict";var{ObjectDefineProperties:vf,ObjectGetOwnPropertyDescriptor:F,ObjectKeys:$f,ObjectSetPrototypeOf:Ar}=T();Tr.exports=k;var gt=ce(),P=pt();Ar(k.prototype,gt.prototype);Ar(k,gt);{let e=$f(P.prototype);for(let t=0;t{"use strict";var{ObjectSetPrototypeOf:Ir,Symbol:Ff}=T();Nr.exports=B;var{ERR_METHOD_NOT_IMPLEMENTED:Bf}=D().codes,St=j();Ir(B.prototype,St.prototype);Ir(B,St);var we=Ff("kCallback");function B(e){if(!(this instanceof B))return new B(e);St.call(this,e),this._readableState.sync=!1,this[we]=null,e&&(typeof e.transform=="function"&&(this._transform=e.transform),typeof e.flush=="function"&&(this._flush=e.flush)),this.on("prefinish",Uf)}function _t(e){typeof this._flush=="function"&&!this.destroyed?this._flush((t,n)=>{if(t){e?e(t):this.destroy(t);return}n!=null&&this.push(n),this.push(null),e&&e()}):(this.push(null),e&&e())}function Uf(){this._final!==_t&&_t.call(this)}B.prototype._final=_t;B.prototype._transform=function(e,t,n){throw new Bf("_transform()")};B.prototype._write=function(e,t,n){let r=this._readableState,i=this._writableState,o=r.length;this._transform(e,t,(l,s)=>{if(l){n(l);return}s!=null&&this.push(s),i.ended||o===r.length||r.length{"use strict";var{ObjectSetPrototypeOf:Mr}=T();Dr.exports=ae;var Rt=Et();Mr(ae.prototype,Rt.prototype);Mr(ae,Rt);function ae(e){if(!(this instanceof ae))return new ae(e);Rt.call(this,e)}ae.prototype._transform=function(e,t,n){n(null,e)}});var ve=_((Va,Wr)=>{"use strict";var{ArrayIsArray:Gf,Promise:Hf,SymbolAsyncIterator:Vf}=T(),je=Y(),{once:Yf}=W(),Kf=J(),xr=j(),{aggregateTwoErrors:zf,codes:{ERR_INVALID_ARG_TYPE:qr,ERR_INVALID_RETURN_VALUE:mt,ERR_MISSING_ARGS:Xf,ERR_STREAM_DESTROYED:Jf},AbortError:Qf}=D(),{validateFunction:Zf,validateAbortSignal:ea}=ue(),{isIterable:se,isReadable:Tt,isReadableNodeStream:Mt,isNodeStream:Or}=V(),ta=globalThis.AbortController,It,Nt;function Lr(e,t,n){let r=!1;e.on("close",()=>{r=!0});let i=je(e,{readable:t,writable:n},o=>{r=!o});return{destroy:o=>{r||(r=!0,Kf.destroyer(e,o||new Jf("pipe")))},cleanup:i}}function na(e){return Zf(e[e.length-1],"streams[stream.length - 1]"),e.pop()}function ra(e){if(se(e))return e;if(Mt(e))return ia(e);throw new qr("val",["Readable","Iterable","AsyncIterable"],e)}async function*ia(e){Nt||(Nt=ce()),yield*Nt.prototype[Vf].call(e)}async function Pr(e,t,n,{end:r}){let i,o=null,l=f=>{if(f&&(i=f),o){let c=o;o=null,c()}},s=()=>new Hf((f,c)=>{i?c(i):o=()=>{i?c(i):f()}});t.on("drain",l);let a=je(t,{readable:!1},l);try{t.writableNeedDrain&&await s();for await(let f of e)t.write(f)||await s();r&&t.end(),await s(),n()}catch(f){n(i!==f?zf(i,f):f)}finally{a(),t.off("drain",l)}}function oa(...e){return kr(e,Yf(na(e)))}function kr(e,t,n){if(e.length===1&&Gf(e[0])&&(e=e[0]),e.length<2)throw new Xf("streams");let r=new ta,i=r.signal,o=n?.signal,l=[];ea(o,"options.signal");function s(){d(new Qf)}o?.addEventListener("abort",s);let a,f,c=[],u=0;function p(g){d(g,--u===0)}function d(g,h){if(g&&(!a||a.code==="ERR_STREAM_PREMATURE_CLOSE")&&(a=g),!(!a&&!h)){for(;c.length;)c.shift()(a);o?.removeEventListener("abort",s),r.abort(),h&&(a||l.forEach(S=>S()),__Process$.nextTick(t,a,f))}}let b;for(let g=0;g0,R=S||n?.end!==!1,G=g===e.length-1;if(Or(h)){let L=function(v){v&&v.name!=="AbortError"&&v.code!=="ERR_STREAM_PREMATURE_CLOSE"&&p(v)};if(R){let{destroy:v,cleanup:Fe}=Lr(h,S,x);c.push(v),Tt(h)&&G&&l.push(Fe)}h.on("error",L),Tt(h)&&G&&l.push(()=>{h.removeListener("error",L)})}if(g===0)if(typeof h=="function"){if(b=h({signal:i}),!se(b))throw new mt("Iterable, AsyncIterable or Stream","source",b)}else se(h)||Mt(h)?b=h:b=xr.from(h);else if(typeof h=="function")if(b=ra(b),b=h(b,{signal:i}),S){if(!se(b,!0))throw new mt("AsyncIterable",`transform[${g-1}]`,b)}else{var M;It||(It=At());let L=new It({objectMode:!0}),v=(M=b)===null||M===void 0?void 0:M.then;if(typeof v=="function")u++,v.call(b,ee=>{f=ee,ee!=null&&L.write(ee),R&&L.end(),__Process$.nextTick(p)},ee=>{L.destroy(ee),__Process$.nextTick(p,ee)});else if(se(b,!0))u++,Pr(b,L,p,{end:R});else throw new mt("AsyncIterable or Promise","destination",b);b=L;let{destroy:Fe,cleanup:ni}=Lr(b,!1,!0);c.push(Fe),G&&l.push(ni)}else if(Or(h)){if(Mt(b)){u+=2;let L=la(b,h,p,{end:R});Tt(h)&&G&&l.push(L)}else if(se(b))u++,Pr(b,h,p,{end:R});else throw new qr("val",["Readable","Iterable","AsyncIterable"],b);b=h}else b=xr.from(h)}return(i!=null&&i.aborted||o!=null&&o.aborted)&&__Process$.nextTick(s),b}function la(e,t,n,{end:r}){return e.pipe(t,{end:r}),r?e.once("end",()=>t.end()):n(),je(e,{readable:!0,writable:!1},i=>{let o=e._readableState;i&&i.code==="ERR_STREAM_PREMATURE_CLOSE"&&o&&o.ended&&!o.errored&&!o.errorEmitted?e.once("end",n).once("error",n):n(i)}),je(t,{readable:!1,writable:!0},n)}Wr.exports={pipelineImpl:kr,pipeline:oa}});var Fr=_((Ya,$r)=>{"use strict";var{pipeline:fa}=ve(),$e=j(),{destroyer:aa}=J(),{isNodeStream:sa,isReadable:Cr,isWritable:jr}=V(),{AbortError:ua,codes:{ERR_INVALID_ARG_VALUE:vr,ERR_MISSING_ARGS:da}}=D();$r.exports=function(...t){if(t.length===0)throw new da("streams");if(t.length===1)return $e.from(t[0]);let n=[...t];if(typeof t[0]=="function"&&(t[0]=$e.from(t[0])),typeof t[t.length-1]=="function"){let d=t.length-1;t[d]=$e.from(t[d])}for(let d=0;d0&&!jr(t[d]))throw new vr(`streams[${d}]`,n[d],"must be writable")}let r,i,o,l,s;function a(d){let b=l;l=null,b?b(d):d?s.destroy(d):!p&&!u&&s.destroy()}let f=t[0],c=fa(t,a),u=!!jr(f),p=!!Cr(c);return s=new $e({writableObjectMode:!!(f!=null&&f.writableObjectMode),readableObjectMode:!!(c!=null&&c.writableObjectMode),writable:u,readable:p}),u&&(s._write=function(d,b,M){f.write(d,b)?M():r=M},s._final=function(d){f.end(),i=d},f.on("drain",function(){if(r){let d=r;r=null,d()}}),c.on("finish",function(){if(i){let d=i;i=null,d()}})),p&&(c.on("readable",function(){if(o){let d=o;o=null,d()}}),c.on("end",function(){s.push(null)}),s._read=function(){for(;;){let d=c.read();if(d===null){o=s._read;return}if(!s.push(d))return}}),s._destroy=function(d,b){!d&&l!==null&&(d=new ua),o=null,r=null,i=null,l===null?b(d):(l=b,aa(c,d))},s}});var Dt=_((Ka,Br)=>{"use strict";var{ArrayPrototypePop:ca,Promise:ha}=T(),{isIterable:ba,isNodeStream:pa}=V(),{pipelineImpl:wa}=ve(),{finished:ya}=Y();function ga(...e){return new ha((t,n)=>{let r,i,o=e[e.length-1];if(o&&typeof o=="object"&&!pa(o)&&!ba(o)){let l=ca(e);r=l.signal,i=l.end}wa(e,(l,s)=>{l?n(l):t(s)},{signal:r,end:i})})}Br.exports={finished:ya,pipeline:ga}});var Qr=_((za,Jr)=>{"use strict";var{ObjectDefineProperty:U,ObjectKeys:Hr,ReflectApply:Vr}=T(),{promisify:{custom:Yr}}=W(),{streamReturningOperators:Ur,promiseReturningOperators:Gr}=Sn(),{codes:{ERR_ILLEGAL_CONSTRUCTOR:Kr}}=D(),_a=Fr(),{pipeline:zr}=ve(),{destroyer:Sa}=J(),Xr=Y(),xt=Dt(),Ot=V(),A=Jr.exports=Me().Stream;A.isDisturbed=Ot.isDisturbed;A.isErrored=Ot.isErrored;A.isReadable=Ot.isReadable;A.Readable=ce();for(let e of Hr(Ur)){let n=function(...r){if(new.target)throw Kr();return A.Readable.from(Vr(t,this,r))},t=Ur[e];U(n,"name",{value:t.name}),U(n,"length",{value:t.length}),U(A.Readable.prototype,e,{value:n,enumerable:!1,configurable:!0,writable:!0})}for(let e of Hr(Gr)){let n=function(...r){if(new.target)throw Kr();return Vr(t,this,r)},t=Gr[e];U(n,"name",{value:t.name}),U(n,"length",{value:t.length}),U(A.Readable.prototype,e,{value:n,enumerable:!1,configurable:!0,writable:!0})}A.Writable=pt();A.Duplex=j();A.Transform=Et();A.PassThrough=At();A.pipeline=zr;var{addAbortSignal:Ea}=xe();A.addAbortSignal=Ea;A.finished=Xr;A.destroy=Sa;A.compose=_a;U(A,"promises",{configurable:!0,enumerable:!0,get(){return xt}});U(zr,Yr,{enumerable:!0,get(){return xt.pipeline}});U(Xr,Yr,{enumerable:!0,get(){return xt.finished}});A.Stream=A;A._isUint8Array=function(t){return t instanceof Uint8Array};A._uint8ArrayToBuffer=function(t){return __Buffer$.from(t.buffer,t.byteOffset,t.byteLength)}});var Zr=_((Xa,m)=>{"use strict";var I=Qr(),Ra=Dt(),Aa=I.Readable.destroy;m.exports=I.Readable;m.exports._uint8ArrayToBuffer=I._uint8ArrayToBuffer;m.exports._isUint8Array=I._isUint8Array;m.exports.isDisturbed=I.isDisturbed;m.exports.isErrored=I.isErrored;m.exports.isReadable=I.isReadable;m.exports.Readable=I.Readable;m.exports.Writable=I.Writable;m.exports.Duplex=I.Duplex;m.exports.Transform=I.Transform;m.exports.PassThrough=I.PassThrough;m.exports.addAbortSignal=I.addAbortSignal;m.exports.finished=I.finished;m.exports.destroy=I.destroy;m.exports.destroy=Aa;m.exports.pipeline=I.pipeline;m.exports.compose=I.compose;Object.defineProperty(I,"promises",{configurable:!0,enumerable:!0,get(){return Ra}});m.exports.Stream=I.Stream;m.exports.default=m.exports});var ti=si(Zr()),Ja=!0,{_uint8ArrayToBuffer:Qa,_isUint8Array:Za,isDisturbed:es,isErrored:ts,isReadable:ns,Readable:rs,Writable:is,Duplex:os,Transform:ls,PassThrough:fs,addAbortSignal:as,finished:ss,destroy:us,pipeline:ds,compose:cs,Stream:hs}=ti,{default:ei,...ma}=ti,bs=ei!==void 0?ei:ma;export{os as Duplex,fs as PassThrough,rs as Readable,hs as Stream,ls as Transform,is as Writable,Ja as __esModule,Za as _isUint8Array,Qa as _uint8ArrayToBuffer,as as addAbortSignal,cs as compose,bs as default,us as destroy,ss as finished,es as isDisturbed,ts as isErrored,ns as isReadable,ds as pipeline}; +/* End esm.sh bundle */ + +// The following code implements Readable.fromWeb(), Writable.fromWeb(), and +// Duplex.fromWeb(). These functions are not properly implemented in the +// readable-stream module yet. This can be removed once the following upstream +// issue is resolved: https://github.com/nodejs/readable-stream/issues/482 + +import { + ERR_INVALID_ARG_TYPE, + ERR_INVALID_ARG_VALUE, + ERR_STREAM_PREMATURE_CLOSE, +} from "./internal/errors.ts"; +import { destroy } from "./internal/streams/destroy.mjs"; +import { isReadableEnded, isWritableEnded } from "./internal/streams/utils.mjs"; +import { validateBoolean, validateObject } from "./internal/validators.mjs"; + +let process = __Process$; +let Buffer = __Buffer$; +let Readable = rs; +let Writable = is; +let Duplex = os; + +function isReadableStream(object) { + return object instanceof ReadableStream; +} + +function isWritableStream(object) { + return object instanceof WritableStream; +} + +Readable.fromWeb = function ( + readableStream, + options = {}, +) { + if (!isReadableStream(readableStream)) { + throw new ERR_INVALID_ARG_TYPE( + "readableStream", + "ReadableStream", + readableStream, + ); + } + + validateObject(options, "options"); + const { + highWaterMark, + encoding, + objectMode = false, + signal, + } = options; + + if (encoding !== undefined && !Buffer.isEncoding(encoding)) { + throw new ERR_INVALID_ARG_VALUE(encoding, "options.encoding"); + } + validateBoolean(objectMode, "options.objectMode"); + + const reader = readableStream.getReader(); + let closed = false; + + const readable = new Readable({ + objectMode, + highWaterMark, + encoding, + signal, + + read() { + reader.read().then( + (chunk) => { + if (chunk.done) { + readable.push(null); + } else { + readable.push(chunk.value); + } + }, + (error) => destroy.call(readable, error), + ); + }, + + destroy(error, callback) { + function done() { + try { + callback(error); + } catch (error) { + // In a next tick because this is happening within + // a promise context, and if there are any errors + // thrown we don't want those to cause an unhandled + // rejection. Let's just escape the promise and + // handle it separately. + process.nextTick(() => { + throw error; + }); + } + } + + if (!closed) { + reader.cancel(error).then(done, done); + return; + } + + done(); + }, + }); + + reader.closed.then( + () => { + closed = true; + if (!isReadableEnded(readable)) { + readable.push(null); + } + }, + (error) => { + closed = true; + destroy.call(readable, error); + }, + ); + + return readable; +}; + +Writable.fromWeb = function ( + writableStream, + options = {}, +) { + if (!isWritableStream(writableStream)) { + throw new ERR_INVALID_ARG_TYPE( + "writableStream", + "WritableStream", + writableStream, + ); + } + + validateObject(options, "options"); + const { + highWaterMark, + decodeStrings = true, + objectMode = false, + signal, + } = options; + + validateBoolean(objectMode, "options.objectMode"); + validateBoolean(decodeStrings, "options.decodeStrings"); + + const writer = writableStream.getWriter(); + let closed = false; + + const writable = new Writable({ + highWaterMark, + objectMode, + decodeStrings, + signal, + + writev(chunks, callback) { + function done(error) { + error = error.filter((e) => e); + try { + callback(error.length === 0 ? undefined : error); + } catch (error) { + // In a next tick because this is happening within + // a promise context, and if there are any errors + // thrown we don't want those to cause an unhandled + // rejection. Let's just escape the promise and + // handle it separately. + process.nextTick(() => destroy.call(writable, error)); + } + } + + writer.ready.then( + () => + Promise.all( + chunks.map((data) => writer.write(data.chunk)), + ).then(done, done), + done, + ); + }, + + write(chunk, encoding, callback) { + if (typeof chunk === "string" && decodeStrings && !objectMode) { + chunk = Buffer.from(chunk, encoding); + chunk = new Uint8Array( + chunk.buffer, + chunk.byteOffset, + chunk.byteLength, + ); + } + + function done(error) { + try { + callback(error); + } catch (error) { + destroy(this, duplex, error); + } + } + + writer.ready.then( + () => writer.write(chunk).then(done, done), + done, + ); + }, + + destroy(error, callback) { + function done() { + try { + callback(error); + } catch (error) { + // In a next tick because this is happening within + // a promise context, and if there are any errors + // thrown we don't want those to cause an unhandled + // rejection. Let's just escape the promise and + // handle it separately. + process.nextTick(() => { + throw error; + }); + } + } + + if (!closed) { + if (error != null) { + writer.abort(error).then(done, done); + } else { + writer.close().then(done, done); + } + return; + } + + done(); + }, + + final(callback) { + function done(error) { + try { + callback(error); + } catch (error) { + // In a next tick because this is happening within + // a promise context, and if there are any errors + // thrown we don't want those to cause an unhandled + // rejection. Let's just escape the promise and + // handle it separately. + process.nextTick(() => destroy.call(writable, error)); + } + } + + if (!closed) { + writer.close().then(done, done); + } + }, + }); + + writer.closed.then( + () => { + closed = true; + if (!isWritableEnded(writable)) { + destroy.call(writable, new ERR_STREAM_PREMATURE_CLOSE()); + } + }, + (error) => { + closed = true; + destroy.call(writable, error); + }, + ); + + return writable; }; + +Duplex.fromWeb = function (pair, options) { + validateObject(pair, "pair"); + const { + readable: readableStream, + writable: writableStream, + } = pair; + + if (!isReadableStream(readableStream)) { + throw new ERR_INVALID_ARG_TYPE( + "pair.readable", + "ReadableStream", + readableStream, + ); + } + if (!isWritableStream(writableStream)) { + throw new ERR_INVALID_ARG_TYPE( + "pair.writable", + "WritableStream", + writableStream, + ); + } + + validateObject(options, "options"); + const { + allowHalfOpen = false, + objectMode = false, + encoding, + decodeStrings = true, + highWaterMark, + signal, + } = options; + + validateBoolean(objectMode, "options.objectMode"); + if (encoding !== undefined && !Buffer.isEncoding(encoding)) { + throw new ERR_INVALID_ARG_VALUE(encoding, "options.encoding"); + } + + const writer = writableStream.getWriter(); + const reader = readableStream.getReader(); + let writableClosed = false; + let readableClosed = false; + + const duplex = new Duplex({ + allowHalfOpen, + highWaterMark, + objectMode, + encoding, + decodeStrings, + signal, + + writev(chunks, callback) { + function done(error) { + error = error.filter((e) => e); + try { + callback(error.length === 0 ? undefined : error); + } catch (error) { + // In a next tick because this is happening within + // a promise context, and if there are any errors + // thrown we don't want those to cause an unhandled + // rejection. Let's just escape the promise and + // handle it separately. + process.nextTick(() => destroy(duplex, error)); + } + } + + writer.ready.then( + () => + Promise.all( + chunks.map((data) => writer.write(data.chunk)), + ).then(done, done), + done, + ); + }, + + write(chunk, encoding, callback) { + if (typeof chunk === "string" && decodeStrings && !objectMode) { + chunk = Buffer.from(chunk, encoding); + chunk = new Uint8Array( + chunk.buffer, + chunk.byteOffset, + chunk.byteLength, + ); + } + + function done(error) { + try { + callback(error); + } catch (error) { + destroy(duplex, error); + } + } + + writer.ready.then( + () => writer.write(chunk).then(done, done), + done, + ); + }, + + final(callback) { + function done(error) { + try { + callback(error); + } catch (error) { + // In a next tick because this is happening within + // a promise context, and if there are any errors + // thrown we don't want those to cause an unhandled + // rejection. Let's just escape the promise and + // handle it separately. + process.nextTick(() => destroy(duplex, error)); + } + } + + if (!writableClosed) { + writer.close().then(done, done); + } + }, + + read() { + reader.read().then( + (chunk) => { + if (chunk.done) { + duplex.push(null); + } else { + duplex.push(chunk.value); + } + }, + (error) => destroy(duplex, error), + ); + }, + + destroy(error, callback) { + function done() { + try { + callback(error); + } catch (error) { + // In a next tick because this is happening within + // a promise context, and if there are any errors + // thrown we don't want those to cause an unhandled + // rejection. Let's just escape the promise and + // handle it separately. + process.nextTick(() => { + throw error; + }); + } + } + + async function closeWriter() { + if (!writableClosed) { + await writer.abort(error); + } + } + + async function closeReader() { + if (!readableClosed) { + await reader.cancel(error); + } + } + + if (!writableClosed || !readableClosed) { + Promise.all([ + closeWriter(), + closeReader(), + ]).then(done, done); + return; + } + + done(); + }, + }); + + writer.closed.then( + () => { + writableClosed = true; + if (!isWritableEnded(duplex)) { + destroy(duplex, new ERR_STREAM_PREMATURE_CLOSE()); + } + }, + (error) => { + writableClosed = true; + readableClosed = true; + destroy(duplex, error); + }, + ); + + reader.closed.then( + () => { + readableClosed = true; + if (!isReadableEnded(duplex)) { + duplex.push(null); + } + }, + (error) => { + writableClosed = true; + readableClosed = true; + destroy(duplex, error); + }, + ); + + return duplex; +}; + +// readable-stream attaches these to Readable, but Node.js core does not. +// Delete them here to better match Node.js core. These can be removed once +// https://github.com/nodejs/readable-stream/issues/485 is resolved. +delete Readable.Duplex; +delete Readable.PassThrough; +delete Readable.Readable; +delete Readable.Stream; +delete Readable.Transform; +delete Readable.Writable; +delete Readable._isUint8Array; +delete Readable._uint8ArrayToBuffer; +delete Readable.addAbortSignal; +delete Readable.compose; +delete Readable.destroy; +delete Readable.finished; +delete Readable.isDisturbed; +delete Readable.isErrored; +delete Readable.isReadable; +delete Readable.pipeline; diff --git a/node/_tools/README.md b/node/_tools/README.md new file mode 100644 index 000000000000..5730471aaad5 --- /dev/null +++ b/node/_tools/README.md @@ -0,0 +1,17 @@ +# Node.js Compatibility Tooling + +This directory contains tooling for implementing Deno's Node.js compatibility +layer. + +## Updating the Streams Implementation + +The Node.js streams implementation is based on the `readable-stream` module on +npm. To update the code, run the following command: + +``` +deno run -A --unstable node/_tools/vendor_readable_stream.ts +``` + +At the top of this script, there is a variable named `sourceUrl`. This is the +implementation that is downloaded, modified, and included in `node/_stream.mjs`. +To change the vendored version of `readable-stream`, update this URL. diff --git a/node/_tools/config.json b/node/_tools/config.json index 858f23242338..aab7969f01bb 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -50,7 +50,13 @@ "test-path.js", "test-querystring.js", "test-readline-interface.js", + "test-stream-duplex-destroy.js", + "test-stream-readable-with-unimplemented-_read.js", + "test-stream-transform-destroy.js", "test-stream-writable-change-default-encoding.js", + "test-stream-writable-destroy.js", + "test-stream-writable-end-cb-error.js", + "test-stream-write-destroy.js", "test-url-urltooptions.js", "test-util-format.js", "test-util-inspect-namespace.js", diff --git a/node/_tools/test/parallel/test-stream-duplex-destroy.js b/node/_tools/test/parallel/test-stream-duplex-destroy.js index e8c407f7fd97..cfb6ef70fe82 100644 --- a/node/_tools/test/parallel/test-stream-duplex-destroy.js +++ b/node/_tools/test/parallel/test-stream-duplex-destroy.js @@ -5,6 +5,10 @@ // Taken from Node 16.13.0 // This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually +// TODO(cjihrig): This test was updated in Node.js 18. In order to vendor +// readable-stream, this must be updated manually. Once std node has been +// updated to Node.js 18 this can be updated automatically. + 'use strict'; const common = require('../common'); @@ -132,7 +136,7 @@ const assert = require('assert'); duplex.removeListener('end', fail); duplex.removeListener('finish', fail); duplex.on('end', common.mustNotCall()); - duplex.on('finish', common.mustCall()); + duplex.on('finish', common.mustNotCall()); assert.strictEqual(duplex.destroyed, true); } diff --git a/node/_tools/test/parallel/test-stream-readable-with-unimplemented-_read.js b/node/_tools/test/parallel/test-stream-readable-with-unimplemented-_read.js index a2cd2ab41034..5d3dd23932b6 100644 --- a/node/_tools/test/parallel/test-stream-readable-with-unimplemented-_read.js +++ b/node/_tools/test/parallel/test-stream-readable-with-unimplemented-_read.js @@ -5,21 +5,20 @@ // Taken from Node 16.13.0 // This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually -'use strict'; -require('../common'); +// TODO(cjihrig): This test was updated in Node.js 18. In order to vendor +// readable-stream, this must be updated manually. Once std node has been +// updated to Node.js 18 this can be updated automatically. -const assert = require('assert'); +'use strict'; +const common = require('../common'); const { Readable } = require('stream'); const readable = new Readable(); -assert.throws( - () => { - readable.read(); - }, - { - code: 'ERR_METHOD_NOT_IMPLEMENTED', - name: 'Error', - message: 'The _read() method is not implemented' - } -); +readable.read(); +readable.on('error', common.expectsError({ + code: 'ERR_METHOD_NOT_IMPLEMENTED', + name: 'Error', + message: 'The _read() method is not implemented' +})); +readable.on('close', common.mustCall()); diff --git a/node/_tools/test/parallel/test-stream-transform-destroy.js b/node/_tools/test/parallel/test-stream-transform-destroy.js index 38de085346f3..62e7ca3552ce 100644 --- a/node/_tools/test/parallel/test-stream-transform-destroy.js +++ b/node/_tools/test/parallel/test-stream-transform-destroy.js @@ -5,6 +5,10 @@ // Taken from Node 16.13.0 // This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually +// TODO(cjihrig): This test was updated in Node.js 18. In order to vendor +// readable-stream, this must be updated manually. Once std node has been +// updated to Node.js 18 this can be updated automatically. + 'use strict'; const common = require('../common'); @@ -124,7 +128,7 @@ const assert = require('assert'); transform.removeListener('end', fail); transform.removeListener('finish', fail); transform.on('end', common.mustCall()); - transform.on('finish', common.mustCall()); + transform.on('finish', common.mustNotCall()); } { diff --git a/node/_tools/test/parallel/test-stream-writable-change-default-encoding.js b/node/_tools/test/parallel/test-stream-writable-change-default-encoding.js index 022000698946..1443fbcf5419 100644 --- a/node/_tools/test/parallel/test-stream-writable-change-default-encoding.js +++ b/node/_tools/test/parallel/test-stream-writable-change-default-encoding.js @@ -5,6 +5,10 @@ // Taken from Node 16.13.0 // This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually +// TODO(cjihrig): This test was updated in Node.js 18. In order to vendor +// readable-stream, this must be updated manually. Once std node has been +// updated to Node.js 18 this can be updated automatically. + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -72,10 +76,10 @@ assert.throws(() => { }, { name: 'TypeError', code: 'ERR_UNKNOWN_ENCODING', - message: 'Unknown encoding: [object Object]' + message: 'Unknown encoding: {}' }); -(function checkVairableCaseEncoding() { +(function checkVariableCaseEncoding() { const m = new MyWritable(function(isBuffer, type, enc) { assert.strictEqual(enc, 'ascii'); }, { decodeStrings: false }); diff --git a/node/_tools/test/parallel/test-stream-writable-destroy.js b/node/_tools/test/parallel/test-stream-writable-destroy.js index c5307c4862d4..72594236fb65 100644 --- a/node/_tools/test/parallel/test-stream-writable-destroy.js +++ b/node/_tools/test/parallel/test-stream-writable-destroy.js @@ -5,6 +5,10 @@ // Taken from Node 16.13.0 // This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually +// TODO(cjihrig): This test was updated in Node.js 18. In order to vendor +// readable-stream, this must be updated manually. Once std node has been +// updated to Node.js 18 this can be updated automatically. + 'use strict'; const common = require('../common'); @@ -131,8 +135,6 @@ const assert = require('assert'); write.destroy(); - write.removeListener('finish', fail); - write.on('finish', common.mustCall()); assert.strictEqual(write.destroyed, true); } @@ -358,33 +360,35 @@ const assert = require('assert'); const write = new Writable({ write(chunk, enc, cb) { process.nextTick(cb); } }); + const _err = new Error('asd'); write.once('error', common.mustCall((err) => { assert.strictEqual(err.message, 'asd'); })); write.end('asd', common.mustCall((err) => { - assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + assert.strictEqual(err, _err); })); - write.destroy(new Error('asd')); + write.destroy(_err); } { // Call buffered write callback with error + const _err = new Error('asd'); const write = new Writable({ write(chunk, enc, cb) { - process.nextTick(cb, new Error('asd')); + process.nextTick(cb, _err); }, autoDestroy: false }); write.cork(); write.write('asd', common.mustCall((err) => { - assert.strictEqual(err.message, 'asd'); + assert.strictEqual(err, _err); })); write.write('asd', common.mustCall((err) => { - assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + assert.strictEqual(err, _err); })); write.on('error', common.mustCall((err) => { - assert.strictEqual(err.message, 'asd'); + assert.strictEqual(err, _err); })); write.uncork(); } @@ -478,3 +482,19 @@ const assert = require('assert'); write.destroy(); write.destroy(); } + +{ + // https://github.com/nodejs/node/issues/39356 + const s = new Writable({ + final() {} + }); + const _err = new Error('oh no'); + // Remove `callback` and it works + s.end(common.mustCall((err) => { + assert.strictEqual(err, _err); + })); + s.on('error', common.mustCall((err) => { + assert.strictEqual(err, _err); + })); + s.destroy(_err); +} diff --git a/node/_tools/test/parallel/test-stream-writable-end-cb-error.js b/node/_tools/test/parallel/test-stream-writable-end-cb-error.js index 77ae05cde5eb..1784801f8782 100644 --- a/node/_tools/test/parallel/test-stream-writable-end-cb-error.js +++ b/node/_tools/test/parallel/test-stream-writable-end-cb-error.js @@ -5,6 +5,10 @@ // Taken from Node 16.13.0 // This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually +// TODO(cjihrig): This test was updated in Node.js 18. In order to vendor +// readable-stream, this must be updated manually. Once std node has been +// updated to Node.js 18 this can be updated automatically. + 'use strict'; const common = require('../common'); @@ -15,19 +19,20 @@ const stream = require('stream'); // Invoke end callback on failure. const writable = new stream.Writable(); + const _err = new Error('kaboom'); writable._write = (chunk, encoding, cb) => { - process.nextTick(cb, new Error('kaboom')); + process.nextTick(cb, _err); }; writable.on('error', common.mustCall((err) => { - assert.strictEqual(err.message, 'kaboom'); + assert.strictEqual(err, _err); })); writable.write('asd'); writable.end(common.mustCall((err) => { - assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + assert.strictEqual(err, _err); })); writable.end(common.mustCall((err) => { - assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + assert.strictEqual(err, _err); })); } @@ -64,18 +69,12 @@ const stream = require('stream'); } }); w.end('testing ended state', common.mustCall((err) => { - // This errors since .destroy(err), which is invoked by errors - // in same tick below, will error all pending callbacks. - // Does this make sense? Not sure. - assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + assert.strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); })); assert.strictEqual(w.destroyed, false); assert.strictEqual(w.writableEnded, true); w.end(common.mustCall((err) => { - // This errors since .destroy(err), which is invoked by errors - // in same tick below, will error all pending callbacks. - // Does this make sense? Not sure. - assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED'); + assert.strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); })); assert.strictEqual(w.destroyed, false); assert.strictEqual(w.writableEnded, true); diff --git a/node/_tools/test/parallel/test-stream-write-destroy.js b/node/_tools/test/parallel/test-stream-write-destroy.js index fbacb7cf78ec..37f8c94deb29 100644 --- a/node/_tools/test/parallel/test-stream-write-destroy.js +++ b/node/_tools/test/parallel/test-stream-write-destroy.js @@ -5,6 +5,10 @@ // Taken from Node 16.13.0 // This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually +// TODO(cjihrig): This test was updated in Node.js 18. In order to vendor +// readable-stream, this must be updated manually. Once std node has been +// updated to Node.js 18 this can be updated automatically. + 'use strict'; require('../common'); const assert = require('assert'); @@ -27,9 +31,7 @@ for (const withPendingData of [ false, true ]) { let chunksWritten = 0; let drains = 0; - let finished = false; w.on('drain', () => drains++); - w.on('finish', () => finished = true); function onWrite(err) { if (err) { @@ -67,9 +69,5 @@ for (const withPendingData of [ false, true ]) { assert.strictEqual(chunksWritten, useEnd && !withPendingData ? 1 : 2); assert.strictEqual(callbacks.length, 0); assert.strictEqual(drains, 1); - - // When we used `.end()`, we see the 'finished' event if and only if - // we actually finished processing the write queue. - assert.strictEqual(finished, !withPendingData && useEnd); } } diff --git a/node/_tools/vendor_readable_stream.ts b/node/_tools/vendor_readable_stream.ts new file mode 100644 index 000000000000..8a9e7fa6f6c3 --- /dev/null +++ b/node/_tools/vendor_readable_stream.ts @@ -0,0 +1,47 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +// usage: deno run -A --unstable node/_tools/vendor_readable_stream.ts +const sourceUrl = + "https://esm.sh/v92/readable-stream@4.1.0/es2022/readable-stream.js"; +const header = + `// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// deno-fmt-ignore-file +// deno-lint-ignore-file +import { nextTick } from "./_next_tick.ts"; +import { stdio } from "./_process/stdio.mjs"; + +`; +const outputFile = new URL("../_stream.mjs", import.meta.url).pathname; +const endMarker = "/* End esm.sh bundle */"; + +// Download the readable-stream module. +const res = await fetch(sourceUrl); +let src = await res.text(); + +// Remove the AbortController fallback code since AbortController always +// exists in Deno. +src = src.replaceAll(/import { AbortController as.+?;/g, ""); +src = src.replaceAll("||__abort_controller$AbortController", ""); + +// Replace Node.js core module imports with Deno std modules. +src = src.replaceAll(/"\/v\d+\/node_buffer.js"/g, '"./buffer.ts"'); +src = src.replaceAll(/"\/v\d+\/string_decoder.+?"/g, '"./string_decoder.ts"'); +src = src.replaceAll(/"\/v\d+\/events@.+?"/g, '"./events.ts"'); + +// Replace import of the Node.js process object with the APIs that are actually +// used to avoid issues with circular imports. +src = src.replaceAll( + /import __Process\$ from "\/v\d+\/node_process.js";/g, + "const __Process$ = { nextTick, stdio };", +); + +// Get any additional code from the end of the current file. +const current = Deno.readTextFileSync(outputFile); +const trailer = current.split(endMarker)[1] ?? ""; + +// Prepend copyrights, Deno tooling directives, and necessary imports and make +// sure any code at the end of the file is maintained. +src = header + src + endMarker + trailer; + +// Update the local file. +Deno.writeTextFileSync(outputFile, src); diff --git a/node/internal/crypto/cipher.ts b/node/internal/crypto/cipher.ts index 0813f570df51..c1911495967a 100644 --- a/node/internal/crypto/cipher.ts +++ b/node/internal/crypto/cipher.ts @@ -46,7 +46,7 @@ export interface CipherOCBOptions extends TransformOptions { authTagLength: number; } -export interface Cipher extends Transform { +export interface Cipher extends ReturnType { update(data: BinaryLike): Buffer; update(data: string, inputEncoding: Encoding): Buffer; update( diff --git a/node/internal/streams/_utils.ts b/node/internal/streams/_utils.ts deleted file mode 100644 index e8161c08f0af..000000000000 --- a/node/internal/streams/_utils.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -import { Buffer } from "../../buffer.ts"; - -export function _uint8ArrayToBuffer(chunk: Uint8Array) { - return Buffer.from( - chunk.buffer, - chunk.byteOffset, - chunk.byteLength, - ); -} diff --git a/node/internal/streams/compose.mjs b/node/internal/streams/compose.mjs deleted file mode 100644 index f1296dc3f7a4..000000000000 --- a/node/internal/streams/compose.mjs +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// deno-lint-ignore-file - -import { destroyer } from "./destroy.mjs"; -import { isNodeStream, isReadable, isWritable } from "./utils.mjs"; -import { pipeline } from "./pipeline.mjs"; -import { - AbortError, - ERR_INVALID_ARG_VALUE, - ERR_MISSING_ARGS, -} from "../errors.ts"; -import Duplex from "./duplex.mjs"; - -// This is needed for pre node 17. -class ComposeDuplex extends Duplex { - constructor(options) { - super(options); - - // https://github.com/nodejs/node/pull/34385 - - if (options?.readable === false) { - this._readableState.readable = false; - this._readableState.ended = true; - this._readableState.endEmitted = true; - } - - if (options?.writable === false) { - this._writableState.writable = false; - this._writableState.ending = true; - this._writableState.ended = true; - this._writableState.finished = true; - } - } -} - -function compose(...streams) { - if (streams.length === 0) { - throw new ERR_MISSING_ARGS("streams"); - } - - if (streams.length === 1) { - return Duplex.from(streams[0]); - } - - const orgStreams = [...streams]; - - if (typeof streams[0] === "function") { - streams[0] = Duplex.from(streams[0]); - } - - if (typeof streams[streams.length - 1] === "function") { - const idx = streams.length - 1; - streams[idx] = Duplex.from(streams[idx]); - } - - for (let n = 0; n < streams.length; ++n) { - if (!isNodeStream(streams[n])) { - // TODO(ronag): Add checks for non streams. - continue; - } - if (n < streams.length - 1 && !isReadable(streams[n])) { - throw new ERR_INVALID_ARG_VALUE( - `streams[${n}]`, - orgStreams[n], - "must be readable", - ); - } - if (n > 0 && !isWritable(streams[n])) { - throw new ERR_INVALID_ARG_VALUE( - `streams[${n}]`, - orgStreams[n], - "must be writable", - ); - } - } - - let ondrain; - let onfinish; - let onreadable; - let onclose; - let d; - - function onfinished(err) { - const cb = onclose; - onclose = null; - - if (cb) { - cb(err); - } else if (err) { - d.destroy(err); - } else if (!readable && !writable) { - d.destroy(); - } - } - - const head = streams[0]; - const tail = pipeline(streams, onfinished); - - const writable = !!isWritable(head); - const readable = !!isReadable(tail); - - // TODO(ronag): Avoid double buffering. - // Implement Writable/Readable/Duplex traits. - // See, https://github.com/nodejs/node/pull/33515. - d = new ComposeDuplex({ - // TODO (ronag): highWaterMark? - writableObjectMode: !!head?.writableObjectMode, - readableObjectMode: !!tail?.writableObjectMode, - writable, - readable, - }); - - if (writable) { - d._write = function (chunk, encoding, callback) { - if (head.write(chunk, encoding)) { - callback(); - } else { - ondrain = callback; - } - }; - - d._final = function (callback) { - head.end(); - onfinish = callback; - }; - - head.on("drain", function () { - if (ondrain) { - const cb = ondrain; - ondrain = null; - cb(); - } - }); - - tail.on("finish", function () { - if (onfinish) { - const cb = onfinish; - onfinish = null; - cb(); - } - }); - } - - if (readable) { - tail.on("readable", function () { - if (onreadable) { - const cb = onreadable; - onreadable = null; - cb(); - } - }); - - tail.on("end", function () { - d.push(null); - }); - - d._read = function () { - while (true) { - const buf = tail.read(); - - if (buf === null) { - onreadable = d._read; - return; - } - - if (!d.push(buf)) { - return; - } - } - }; - } - - d._destroy = function (err, callback) { - if (!err && onclose !== null) { - err = new AbortError(); - } - - onreadable = null; - ondrain = null; - onfinish = null; - - if (onclose === null) { - callback(err); - } else { - onclose = callback; - destroyer(tail, err); - } - }; - - return d; -} - -export default compose; diff --git a/node/internal/streams/duplex.mjs b/node/internal/streams/duplex.mjs index d4bd2a0d9ead..c97c067ebd96 100644 --- a/node/internal/streams/duplex.mjs +++ b/node/internal/streams/duplex.mjs @@ -2,708 +2,8 @@ // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file -import { createDeferredPromise } from "../util.mjs"; -import { destroyer } from "./destroy.mjs"; -import { isBlob } from "../blob.mjs"; -import { - AbortError, - ERR_INVALID_ARG_TYPE, - ERR_INVALID_ARG_VALUE, - ERR_INVALID_RETURN_VALUE, - ERR_STREAM_PREMATURE_CLOSE, -} from "../errors.ts"; -import { - isDuplexNodeStream, - isIterable, - isNodeStream, - isReadable, - isReadableEnded, - isReadableNodeStream, - isWritable, - isWritableEnded, - isWritableNodeStream, -} from "./utils.mjs"; -import * as process from "../../_process/process.ts"; -import _from from "./from.mjs"; -import eos from "./end-of-stream.mjs"; -import Readable from "./readable.mjs"; -import Writable from "./writable.mjs"; -import { validateBoolean, validateObject } from "../validators.mjs"; -import { Buffer } from "../../buffer.ts"; - -Object.setPrototypeOf(Duplex.prototype, Readable.prototype); -Object.setPrototypeOf(Duplex, Readable); - -{ - // Allow the keys array to be GC'ed. - for (const method of Object.keys(Writable.prototype)) { - if (!Duplex.prototype[method]) { - Duplex.prototype[method] = Writable.prototype[method]; - } - } -} - -function Duplex(options) { - if (!(this instanceof Duplex)) { - return new Duplex(options); - } - - Readable.call(this, options); - Writable.call(this, options); - this.allowHalfOpen = true; - - if (options) { - if (options.readable === false) { - this.readable = false; - } - - if (options.writable === false) { - this.writable = false; - } - - if (options.allowHalfOpen === false) { - this.allowHalfOpen = false; - } - } -} - -Object.defineProperties(Duplex.prototype, { - writable: Object.getOwnPropertyDescriptor(Writable.prototype, "writable"), - writableHighWaterMark: Object.getOwnPropertyDescriptor( - Writable.prototype, - "writableHighWaterMark", - ), - writableObjectMode: Object.getOwnPropertyDescriptor( - Writable.prototype, - "writableObjectMode", - ), - writableBuffer: Object.getOwnPropertyDescriptor( - Writable.prototype, - "writableBuffer", - ), - writableLength: Object.getOwnPropertyDescriptor( - Writable.prototype, - "writableLength", - ), - writableFinished: Object.getOwnPropertyDescriptor( - Writable.prototype, - "writableFinished", - ), - writableCorked: Object.getOwnPropertyDescriptor( - Writable.prototype, - "writableCorked", - ), - writableEnded: Object.getOwnPropertyDescriptor( - Writable.prototype, - "writableEnded", - ), - writableNeedDrain: Object.getOwnPropertyDescriptor( - Writable.prototype, - "writableNeedDrain", - ), - - destroyed: { - get() { - if ( - this._readableState === undefined || - this._writableState === undefined - ) { - return false; - } - return this._readableState.destroyed && this._writableState.destroyed; - }, - set(value) { - // Backward compatibility, the user is explicitly - // managing destroyed. - if (this._readableState && this._writableState) { - this._readableState.destroyed = value; - this._writableState.destroyed = value; - } - }, - }, -}); - -function isReadableStream(object) { - return object instanceof ReadableStream; -} - -function isWritableStream(object) { - return object instanceof WritableStream; -} - -export const fromWeb = Duplex.fromWeb = function (pair, options) { - validateObject(pair, "pair"); - const { - readable: readableStream, - writable: writableStream, - } = pair; - - if (!isReadableStream(readableStream)) { - throw new ERR_INVALID_ARG_TYPE( - "pair.readable", - "ReadableStream", - readableStream, - ); - } - if (!isWritableStream(writableStream)) { - throw new ERR_INVALID_ARG_TYPE( - "pair.writable", - "WritableStream", - writableStream, - ); - } - - validateObject(options, "options"); - const { - allowHalfOpen = false, - objectMode = false, - encoding, - decodeStrings = true, - highWaterMark, - signal, - } = options; - - validateBoolean(objectMode, "options.objectMode"); - if (encoding !== undefined && !Buffer.isEncoding(encoding)) { - throw new ERR_INVALID_ARG_VALUE(encoding, "options.encoding"); - } - - const writer = writableStream.getWriter(); - const reader = readableStream.getReader(); - let writableClosed = false; - let readableClosed = false; - - const duplex = new Duplex({ - allowHalfOpen, - highWaterMark, - objectMode, - encoding, - decodeStrings, - signal, - - writev(chunks, callback) { - function done(error) { - error = error.filter((e) => e); - try { - callback(error.length === 0 ? undefined : error); - } catch (error) { - // In a next tick because this is happening within - // a promise context, and if there are any errors - // thrown we don't want those to cause an unhandled - // rejection. Let's just escape the promise and - // handle it separately. - process.nextTick(() => destroy(duplex, error)); - } - } - - writer.ready.then( - () => - Promise.all( - chunks.map((data) => writer.write(data.chunk)), - ).then(done, done), - done, - ); - }, - - write(chunk, encoding, callback) { - if (typeof chunk === "string" && decodeStrings && !objectMode) { - chunk = Buffer.from(chunk, encoding); - chunk = new Uint8Array( - chunk.buffer, - chunk.byteOffset, - chunk.byteLength, - ); - } - - function done(error) { - try { - callback(error); - } catch (error) { - destroy(duplex, error); - } - } - - writer.ready.then( - () => writer.write(chunk).then(done, done), - done, - ); - }, - - final(callback) { - function done(error) { - try { - callback(error); - } catch (error) { - // In a next tick because this is happening within - // a promise context, and if there are any errors - // thrown we don't want those to cause an unhandled - // rejection. Let's just escape the promise and - // handle it separately. - process.nextTick(() => destroy(duplex, error)); - } - } - - if (!writableClosed) { - writer.close().then(done, done); - } - }, - - read() { - reader.read().then( - (chunk) => { - if (chunk.done) { - duplex.push(null); - } else { - duplex.push(chunk.value); - } - }, - (error) => destroy(duplex, error), - ); - }, - - destroy(error, callback) { - function done() { - try { - callback(error); - } catch (error) { - // In a next tick because this is happening within - // a promise context, and if there are any errors - // thrown we don't want those to cause an unhandled - // rejection. Let's just escape the promise and - // handle it separately. - process.nextTick(() => { - throw error; - }); - } - } - - async function closeWriter() { - if (!writableClosed) { - await writer.abort(error); - } - } - - async function closeReader() { - if (!readableClosed) { - await reader.cancel(error); - } - } - - if (!writableClosed || !readableClosed) { - Promise.all([ - closeWriter(), - closeReader(), - ]).then(done, done); - return; - } - - done(); - }, - }); - - writer.closed.then( - () => { - writableClosed = true; - if (!isWritableEnded(duplex)) { - destroy(duplex, new ERR_STREAM_PREMATURE_CLOSE()); - } - }, - (error) => { - writableClosed = true; - readableClosed = true; - destroy(duplex, error); - }, - ); - - reader.closed.then( - () => { - readableClosed = true; - if (!isReadableEnded(duplex)) { - duplex.push(null); - } - }, - (error) => { - writableClosed = true; - readableClosed = true; - destroy(duplex, error); - }, - ); - - return duplex; -}; - -/////////////////////////// -// This is part of the duplexify module, but had to be brought into scope -// to avoid a circular dependency -/////////////////////////// - -// This is needed for pre node 17. -class Duplexify extends Duplex { - constructor(options) { - super(options); - - // https://github.com/nodejs/node/pull/34385 - - if (options?.readable === false) { - this._readableState.readable = false; - this._readableState.ended = true; - this._readableState.endEmitted = true; - } - - if (options?.writable === false) { - this._writableState.writable = false; - this._writableState.ending = true; - this._writableState.ended = true; - this._writableState.finished = true; - } - } -} - -function duplexify(body, name) { - if (isDuplexNodeStream(body)) { - return body; - } - - if (isReadableNodeStream(body)) { - return _duplexify({ readable: body }); - } - - if (isWritableNodeStream(body)) { - return _duplexify({ writable: body }); - } - - if (isNodeStream(body)) { - return _duplexify({ writable: false, readable: false }); - } - - // TODO: Webstreams - // if (isReadableStream(body)) { - // return _duplexify({ readable: Readable.fromWeb(body) }); - // } - - // TODO: Webstreams - // if (isWritableStream(body)) { - // return _duplexify({ writable: Writable.fromWeb(body) }); - // } - - if (typeof body === "function") { - const { value, write, final, destroy } = fromAsyncGen(body); - - if (isIterable(value)) { - return _from(Duplexify, value, { - // TODO (ronag): highWaterMark? - objectMode: true, - write, - final, - destroy, - }); - } - - const then = value?.then; - if (typeof then === "function") { - let d; - - const promise = then.call( - value, - (val) => { - if (val != null) { - throw new ERR_INVALID_RETURN_VALUE("nully", "body", val); - } - }, - (err) => { - destroyer(d, err); - }, - ); - - return d = new Duplexify({ - // TODO (ronag): highWaterMark? - objectMode: true, - readable: false, - write, - final(cb) { - final(async () => { - try { - await promise; - process.nextTick(cb, null); - } catch (err) { - process.nextTick(cb, err); - } - }); - }, - destroy, - }); - } - - throw new ERR_INVALID_RETURN_VALUE( - "Iterable, AsyncIterable or AsyncFunction", - name, - value, - ); - } - - if (isBlob(body)) { - return duplexify(body.arrayBuffer()); - } - - if (isIterable(body)) { - return _from(Duplexify, body, { - // TODO (ronag): highWaterMark? - objectMode: true, - writable: false, - }); - } - - // TODO: Webstreams. - // if ( - // isReadableStream(body?.readable) && - // isWritableStream(body?.writable) - // ) { - // return Duplexify.fromWeb(body); - // } - - if ( - typeof body?.writable === "object" || - typeof body?.readable === "object" - ) { - const readable = body?.readable - ? isReadableNodeStream(body?.readable) - ? body?.readable - : duplexify(body.readable) - : undefined; - - const writable = body?.writable - ? isWritableNodeStream(body?.writable) - ? body?.writable - : duplexify(body.writable) - : undefined; - - return _duplexify({ readable, writable }); - } - - const then = body?.then; - if (typeof then === "function") { - let d; - - then.call( - body, - (val) => { - if (val != null) { - d.push(val); - } - d.push(null); - }, - (err) => { - destroyer(d, err); - }, - ); - - return d = new Duplexify({ - objectMode: true, - writable: false, - read() {}, - }); - } - - throw new ERR_INVALID_ARG_TYPE( - name, - [ - "Blob", - "ReadableStream", - "WritableStream", - "Stream", - "Iterable", - "AsyncIterable", - "Function", - "{ readable, writable } pair", - "Promise", - ], - body, - ); -} - -function fromAsyncGen(fn) { - let { promise, resolve } = createDeferredPromise(); - const ac = new AbortController(); - const signal = ac.signal; - const value = fn( - async function* () { - while (true) { - const _promise = promise; - promise = null; - const { chunk, done, cb } = await _promise; - process.nextTick(cb); - if (done) return; - if (signal.aborted) throw new AbortError(); - ({ promise, resolve } = createDeferredPromise()); - yield chunk; - } - }(), - { signal }, - ); - - return { - value, - write(chunk, encoding, cb) { - const _resolve = resolve; - resolve = null; - _resolve({ chunk, done: false, cb }); - }, - final(cb) { - const _resolve = resolve; - resolve = null; - _resolve({ done: true, cb }); - }, - destroy(err, cb) { - ac.abort(); - cb(err); - }, - }; -} - -function _duplexify(pair) { - const r = pair.readable && typeof pair.readable.read !== "function" - ? Readable.wrap(pair.readable) - : pair.readable; - const w = pair.writable; - - let readable = !!isReadable(r); - let writable = !!isWritable(w); - - let ondrain; - let onfinish; - let onreadable; - let onclose; - let d; - - function onfinished(err) { - const cb = onclose; - onclose = null; - - if (cb) { - cb(err); - } else if (err) { - d.destroy(err); - } else if (!readable && !writable) { - d.destroy(); - } - } - - // TODO(ronag): Avoid double buffering. - // Implement Writable/Readable/Duplex traits. - // See, https://github.com/nodejs/node/pull/33515. - d = new Duplexify({ - // TODO (ronag): highWaterMark? - readableObjectMode: !!r?.readableObjectMode, - writableObjectMode: !!w?.writableObjectMode, - readable, - writable, - }); - - if (writable) { - eos(w, (err) => { - writable = false; - if (err) { - destroyer(r, err); - } - onfinished(err); - }); - - d._write = function (chunk, encoding, callback) { - if (w.write(chunk, encoding)) { - callback(); - } else { - ondrain = callback; - } - }; - - d._final = function (callback) { - w.end(); - onfinish = callback; - }; - - w.on("drain", function () { - if (ondrain) { - const cb = ondrain; - ondrain = null; - cb(); - } - }); - - w.on("finish", function () { - if (onfinish) { - const cb = onfinish; - onfinish = null; - cb(); - } - }); - } - - if (readable) { - eos(r, (err) => { - readable = false; - if (err) { - destroyer(r, err); - } - onfinished(err); - }); - - r.on("readable", function () { - if (onreadable) { - const cb = onreadable; - onreadable = null; - cb(); - } - }); - - r.on("end", function () { - d.push(null); - }); - - d._read = function () { - while (true) { - const buf = r.read(); - - if (buf === null) { - onreadable = d._read; - return; - } - - if (!d.push(buf)) { - return; - } - } - }; - } - - d._destroy = function (err, callback) { - if (!err && onclose !== null) { - err = new AbortError(); - } - - onreadable = null; - ondrain = null; - onfinish = null; - - if (onclose === null) { - callback(err); - } else { - onclose = callback; - destroyer(w, err); - destroyer(r, err); - } - }; - - return d; -} - -/////////////////////////// - -function duplexFrom(body) { - return duplexify(body, "body"); -} - -Duplex.from = duplexFrom; -Duplex.duplexify = duplexify; +import { Duplex } from "../../_stream.mjs"; +const { from, fromWeb, toWeb } = Duplex; export default Duplex; -export { duplexFrom as from, duplexify }; +export { from, fromWeb, toWeb }; diff --git a/node/internal/streams/duplexify.mjs b/node/internal/streams/duplexify.mjs deleted file mode 100644 index 08107073508c..000000000000 --- a/node/internal/streams/duplexify.mjs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// deno-lint-ignore-file - -import { duplexify } from "./duplex.mjs"; -export default duplexify; diff --git a/node/internal/streams/from.mjs b/node/internal/streams/from.mjs deleted file mode 100644 index 1c2482e76492..000000000000 --- a/node/internal/streams/from.mjs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// deno-lint-ignore-file - -import { Buffer } from "../../buffer.ts"; -import { ERR_INVALID_ARG_TYPE, ERR_STREAM_NULL_VALUES } from "../errors.ts"; -import * as process from "../../_process/process.ts"; - -function _from(Readable, iterable, opts) { - let iterator; - if (typeof iterable === "string" || iterable instanceof Buffer) { - return new Readable({ - objectMode: true, - ...opts, - read() { - this.push(iterable); - this.push(null); - }, - }); - } - - let isAsync; - if (iterable && iterable[Symbol.asyncIterator]) { - isAsync = true; - iterator = iterable[Symbol.asyncIterator](); - } else if (iterable && iterable[Symbol.iterator]) { - isAsync = false; - iterator = iterable[Symbol.iterator](); - } else { - throw new ERR_INVALID_ARG_TYPE("iterable", ["Iterable"], iterable); - } - - const readable = new Readable({ - objectMode: true, - highWaterMark: 1, - // TODO(ronag): What options should be allowed? - ...opts, - }); - - // Flag to protect against _read - // being called before last iteration completion. - let reading = false; - - readable._read = function () { - if (!reading) { - reading = true; - next(); - } - }; - - readable._destroy = function (error, cb) { - close(error).then( - () => process.nextTick(cb, error), // nextTick is here in case cb throws - (e) => process.nextTick(cb, e || error), - ); - }; - - async function close(error) { - const hadError = (error !== undefined) && (error !== null); - const hasThrow = typeof iterator.throw === "function"; - if (hadError && hasThrow) { - const { value, done } = await iterator.throw(error); - await value; - if (done) { - return; - } - } - if (typeof iterator.return === "function") { - const { value } = await iterator.return(); - await value; - } - } - - async function next() { - for (;;) { - try { - const { value, done } = isAsync - ? await iterator.next() - : iterator.next(); - - if (done) { - readable.push(null); - } else { - const res = (value && - typeof value.then === "function") - ? await value - : value; - if (res === null) { - reading = false; - throw new ERR_STREAM_NULL_VALUES(); - } else if (readable.push(res)) { - continue; - } else { - reading = false; - } - } - } catch (err) { - readable.destroy(err); - } - break; - } - } - return readable; -} - -export default _from; diff --git a/node/internal/streams/passthrough.mjs b/node/internal/streams/passthrough.mjs index 83e6826f787e..650f7d744207 100644 --- a/node/internal/streams/passthrough.mjs +++ b/node/internal/streams/passthrough.mjs @@ -2,21 +2,6 @@ // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file -import Transform from "./transform.mjs"; - -Object.setPrototypeOf(PassThrough.prototype, Transform.prototype); -Object.setPrototypeOf(PassThrough, Transform); - -function PassThrough(options) { - if (!(this instanceof PassThrough)) { - return new PassThrough(options); - } - - Transform.call(this, options); -} - -PassThrough.prototype._transform = function (chunk, encoding, cb) { - cb(null, chunk); -}; +import { PassThrough } from "../../_stream.mjs"; export default PassThrough; diff --git a/node/internal/streams/pipeline.mjs b/node/internal/streams/pipeline.mjs index b51500674877..4e892ad8fc2b 100644 --- a/node/internal/streams/pipeline.mjs +++ b/node/internal/streams/pipeline.mjs @@ -147,17 +147,6 @@ async function pump(iterable, writable, finish) { } } -function pipeline(...streams) { - const callback = once(popCallback(streams)); - - // stream.pipeline(streams, callback) - if (Array.isArray(streams[0]) && streams.length === 1) { - streams = streams[0]; - } - - return pipelineImpl(streams, callback); -} - function pipelineImpl(streams, callback, opts) { if (streams.length < 2) { throw new ERR_MISSING_ARGS("streams"); @@ -309,5 +298,5 @@ function pipelineImpl(streams, callback, opts) { return ret; } -export default { pipeline, pipelineImpl }; -export { pipeline, pipelineImpl }; +export default { pipelineImpl }; +export { pipelineImpl }; diff --git a/node/internal/streams/readable.mjs b/node/internal/streams/readable.mjs index 057f1df3871f..14d33b7535fe 100644 --- a/node/internal/streams/readable.mjs +++ b/node/internal/streams/readable.mjs @@ -2,1490 +2,8 @@ // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file -import { addAbortSignalNoValidate } from "./add-abort-signal.mjs"; -import { Buffer } from "../../buffer.ts"; -import { debuglog } from "../util/debuglog.ts"; -import { getDefaultHighWaterMark, getHighWaterMark } from "./state.mjs"; -import { prependListener, Stream } from "./legacy.mjs"; -import { StringDecoder } from "../../string_decoder.ts"; -import { validateBoolean, validateObject } from "../validators.mjs"; -import { - ERR_INVALID_ARG_TYPE, - ERR_INVALID_ARG_VALUE, - ERR_METHOD_NOT_IMPLEMENTED, - ERR_STREAM_PUSH_AFTER_EOF, - ERR_STREAM_UNSHIFT_AFTER_END_EVENT, -} from "../errors.ts"; -import { nextTick } from "../../_next_tick.ts"; -import { stdio } from "../../_process/stdio.mjs"; -import _from from "./from.mjs"; -import BufferList from "./buffer_list.mjs"; -import destroyImpl from "./destroy.mjs"; -import EE from "../../events.ts"; -import { isReadableEnded } from "./utils.mjs"; - -let debug = debuglog("stream", (fn) => { - debug = fn; -}); - -const kPaused = Symbol("kPaused"); - -Object.setPrototypeOf(Readable.prototype, Stream.prototype); -Object.setPrototypeOf(Readable, Stream); -const nop = () => {}; - -const { errorOrDestroy } = destroyImpl; - -function ReadableState(options, stream, isDuplex) { - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream. - // These options can be provided separately as readableXXX and writableXXX. - if (typeof isDuplex !== "boolean") { - isDuplex = stream instanceof Stream.Duplex; - } - - // Object stream flag. Used to make read(n) ignore n and to - // make all the buffer merging and length checks go away. - this.objectMode = !!(options && options.objectMode); - - if (isDuplex) { - this.objectMode = this.objectMode || - !!(options && options.readableObjectMode); - } - - // The point at which it stops calling _read() to fill the buffer - // Note: 0 is a valid value, means "don't call _read preemptively ever" - this.highWaterMark = options - ? getHighWaterMark(this, options, "readableHighWaterMark", isDuplex) - : getDefaultHighWaterMark(false); - - // A linked list is used to store data chunks instead of an array because the - // linked list can remove elements from the beginning faster than - // array.shift(). - this.buffer = new BufferList(); - this.length = 0; - this.pipes = []; - this.flowing = null; - this.ended = false; - this.endEmitted = false; - this.reading = false; - - // Stream is still being constructed and cannot be - // destroyed until construction finished or failed. - // Async construction is opt in, therefore we start as - // constructed. - this.constructed = true; - - // A flag to be able to tell if the event 'readable'/'data' is emitted - // immediately, or on a later tick. We set this to true at first, because - // any actions that shouldn't happen until "later" should generally also - // not happen before the first read call. - this.sync = true; - - // Whenever we return null, then we set a flag to say - // that we're awaiting a 'readable' event emission. - this.needReadable = false; - this.emittedReadable = false; - this.readableListening = false; - this.resumeScheduled = false; - this[kPaused] = null; - - // True if the error was already emitted and should not be thrown again. - this.errorEmitted = false; - - // Should close be emitted on destroy. Defaults to true. - this.emitClose = !options || options.emitClose !== false; - - // Should .destroy() be called after 'end' (and potentially 'finish'). - this.autoDestroy = !options || options.autoDestroy !== false; - - // Has it been destroyed. - this.destroyed = false; - - // Indicates whether the stream has errored. When true no further - // _read calls, 'data' or 'readable' events should occur. This is needed - // since when autoDestroy is disabled we need a way to tell whether the - // stream has failed. - this.errored = null; - - // Indicates whether the stream has finished destroying. - this.closed = false; - - // True if close has been emitted or would have been emitted - // depending on emitClose. - this.closeEmitted = false; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = (options && options.defaultEncoding) || "utf8"; - - // Ref the piped dest which we need a drain event on it - // type: null | Writable | Set. - this.awaitDrainWriters = null; - this.multiAwaitDrain = false; - - // If true, a maybeReadMore has been scheduled. - this.readingMore = false; - - this.dataEmitted = false; - - this.decoder = null; - this.encoding = null; - if (options && options.encoding) { - this.decoder = new StringDecoder(options.encoding); - this.encoding = options.encoding; - } -} - -function Readable(options) { - if (!(this instanceof Readable)) { - return new Readable(options); - } - - // Checking for a Stream.Duplex instance is faster here instead of inside - // the ReadableState constructor, at least with V8 6.5. - const isDuplex = this instanceof Stream.Duplex; - - this._readableState = new ReadableState(options, this, isDuplex); - - if (options) { - if (typeof options.read === "function") { - this._read = options.read; - } - - if (typeof options.destroy === "function") { - this._destroy = options.destroy; - } - - if (typeof options.construct === "function") { - this._construct = options.construct; - } - if (options.signal && !isDuplex) { - addAbortSignalNoValidate(options.signal, this); - } - } - - Stream.call(this, options); - - destroyImpl.construct(this, () => { - if (this._readableState.needReadable) { - maybeReadMore(this, this._readableState); - } - }); -} - -Readable.prototype.destroy = destroyImpl.destroy; -Readable.prototype._undestroy = destroyImpl.undestroy; -Readable.prototype._destroy = function (err, cb) { - cb(err); -}; - -Readable.prototype[EE.captureRejectionSymbol] = function (err) { - this.destroy(err); -}; - -// Manually shove something into the read() buffer. -// This returns true if the highWaterMark has not been hit yet, -// similar to how Writable.write() returns true if you should -// write() some more. -Readable.prototype.push = function (chunk, encoding) { - return readableAddChunk(this, chunk, encoding, false); -}; - -// Unshift should *always* be something directly out of read(). -Readable.prototype.unshift = function (chunk, encoding) { - return readableAddChunk(this, chunk, encoding, true); -}; - -function readableAddChunk(stream, chunk, encoding, addToFront) { - debug("readableAddChunk", chunk); - const state = stream._readableState; - - let err; - if (!state.objectMode) { - if (typeof chunk === "string") { - encoding = encoding || state.defaultEncoding; - if (state.encoding !== encoding) { - if (addToFront && state.encoding) { - // When unshifting, if state.encoding is set, we have to save - // the string in the BufferList with the state encoding. - chunk = Buffer.from(chunk, encoding).toString(state.encoding); - } else { - chunk = Buffer.from(chunk, encoding); - encoding = ""; - } - } - } else if (chunk instanceof Buffer) { - encoding = ""; - } else if (Stream._isUint8Array(chunk)) { - chunk = Stream._uint8ArrayToBuffer(chunk); - encoding = ""; - } else if (chunk != null) { - err = new ERR_INVALID_ARG_TYPE( - "chunk", - ["string", "Buffer", "Uint8Array"], - chunk, - ); - } - } - - if (err) { - errorOrDestroy(stream, err); - } else if (chunk === null) { - state.reading = false; - onEofChunk(stream, state); - } else if (state.objectMode || (chunk && chunk.length > 0)) { - if (addToFront) { - if (state.endEmitted) { - errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); - } else { - addChunk(stream, state, chunk, true); - } - } else if (state.ended) { - errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF()); - } else if (state.destroyed || state.errored) { - return false; - } else { - state.reading = false; - if (state.decoder && !encoding) { - chunk = state.decoder.write(chunk); - if (state.objectMode || chunk.length !== 0) { - addChunk(stream, state, chunk, false); - } else { - maybeReadMore(stream, state); - } - } else { - addChunk(stream, state, chunk, false); - } - } - } else if (!addToFront) { - state.reading = false; - maybeReadMore(stream, state); - } - - // We can push more data if we are below the highWaterMark. - // Also, if we have no data yet, we can stand some more bytes. - // This is to work around cases where hwm=0, such as the repl. - return !state.ended && - (state.length < state.highWaterMark || state.length === 0); -} - -function addChunk(stream, state, chunk, addToFront) { - if ( - state.flowing && state.length === 0 && !state.sync && - stream.listenerCount("data") > 0 - ) { - // Use the guard to avoid creating `Set()` repeatedly - // when we have multiple pipes. - if (state.multiAwaitDrain) { - state.awaitDrainWriters.clear(); - } else { - state.awaitDrainWriters = null; - } - state.dataEmitted = true; - stream.emit("data", chunk); - } else { - // Update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) { - state.buffer.unshift(chunk); - } else { - state.buffer.push(chunk); - } - - if (state.needReadable) { - emitReadable(stream); - } - } - maybeReadMore(stream, state); -} - -Readable.prototype.isPaused = function () { - const state = this._readableState; - return state[kPaused] === true || state.flowing === false; -}; - -// Backwards compatibility. -Readable.prototype.setEncoding = function (enc) { - const decoder = new StringDecoder(enc); - this._readableState.decoder = decoder; - // If setEncoding(null), decoder.encoding equals utf8. - this._readableState.encoding = this._readableState.decoder.encoding; - - const buffer = this._readableState.buffer; - // Iterate over current buffer to convert already stored Buffers: - let content = ""; - for (const data of buffer) { - content += decoder.write(data); - } - buffer.clear(); - if (content !== "") { - buffer.push(content); - } - this._readableState.length = content.length; - return this; -}; - -// Don't raise the hwm > 1GB. -const MAX_HWM = 0x40000000; -function computeNewHighWaterMark(n) { - if (n >= MAX_HWM) { - // TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE. - n = MAX_HWM; - } else { - // Get the next highest power of 2 to prevent increasing hwm excessively in - // tiny amounts. - n--; - n |= n >>> 1; - n |= n >>> 2; - n |= n >>> 4; - n |= n >>> 8; - n |= n >>> 16; - n++; - } - return n; -} - -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function howMuchToRead(n, state) { - if (n <= 0 || (state.length === 0 && state.ended)) { - return 0; - } - if (state.objectMode) { - return 1; - } - if (Number.isNaN(n)) { - // Only flow one buffer at a time. - if (state.flowing && state.length) { - return state.buffer.first().length; - } - return state.length; - } - if (n <= state.length) { - return n; - } - return state.ended ? state.length : 0; -} - -// You can override either this method, or the async _read(n) below. -Readable.prototype.read = function (n) { - debug("read", n); - // Same as parseInt(undefined, 10), however V8 7.3 performance regressed - // in this scenario, so we are doing it manually. - if (n === undefined) { - n = NaN; - } else if (!Number.isInteger(n)) { - n = Number.parseInt(n, 10); - } - const state = this._readableState; - const nOrig = n; - - // If we're asking for more than the current hwm, then raise the hwm. - if (n > state.highWaterMark) { - state.highWaterMark = computeNewHighWaterMark(n); - } - - if (n !== 0) { - state.emittedReadable = false; - } - - // If we're doing read(0) to trigger a readable event, but we - // already have a bunch of data in the buffer, then just trigger - // the 'readable' event and move on. - if ( - n === 0 && - state.needReadable && - ((state.highWaterMark !== 0 - ? state.length >= state.highWaterMark - : state.length > 0) || - state.ended) - ) { - debug("read: emitReadable", state.length, state.ended); - if (state.length === 0 && state.ended) { - endReadable(this); - } else { - emitReadable(this); - } - return null; - } - - n = howMuchToRead(n, state); - - // If we've ended, and we're now clear, then finish it up. - if (n === 0 && state.ended) { - if (state.length === 0) { - endReadable(this); - } - return null; - } - - // All the actual chunk generation logic needs to be - // *below* the call to _read. The reason is that in certain - // synthetic stream cases, such as passthrough streams, _read - // may be a completely synchronous operation which may change - // the state of the read buffer, providing enough data when - // before there was *not* enough. - // - // So, the steps are: - // 1. Figure out what the state of things will be after we do - // a read from the buffer. - // - // 2. If that resulting state will trigger a _read, then call _read. - // Note that this may be asynchronous, or synchronous. Yes, it is - // deeply ugly to write APIs this way, but that still doesn't mean - // that the Readable class should behave improperly, as streams are - // designed to be sync/async agnostic. - // Take note if the _read call is sync or async (ie, if the read call - // has returned yet), so that we know whether or not it's safe to emit - // 'readable' etc. - // - // 3. Actually pull the requested chunks out of the buffer and return. - - // if we need a readable event, then we need to do some reading. - let doRead = state.needReadable; - debug("need readable", doRead); - - // If we currently have less than the highWaterMark, then also read some. - if (state.length === 0 || state.length - n < state.highWaterMark) { - doRead = true; - debug("length less than watermark", doRead); - } - - // However, if we've ended, then there's no point, if we're already - // reading, then it's unnecessary, if we're constructing we have to wait, - // and if we're destroyed or errored, then it's not allowed, - if ( - state.ended || state.reading || state.destroyed || state.errored || - !state.constructed - ) { - doRead = false; - debug("reading, ended or constructing", doRead); - } else if (doRead) { - debug("do read"); - state.reading = true; - state.sync = true; - // If the length is currently zero, then we *need* a readable event. - if (state.length === 0) { - state.needReadable = true; - } - - // Call internal read method - this._read(state.highWaterMark); - - state.sync = false; - // If _read pushed data synchronously, then `reading` will be false, - // and we need to re-evaluate how much data we can return to the user. - if (!state.reading) { - n = howMuchToRead(nOrig, state); - } - } - - let ret; - if (n > 0) { - ret = fromList(n, state); - } else { - ret = null; - } - - if (ret === null) { - state.needReadable = state.length <= state.highWaterMark; - n = 0; - } else { - state.length -= n; - if (state.multiAwaitDrain) { - state.awaitDrainWriters.clear(); - } else { - state.awaitDrainWriters = null; - } - } - - if (state.length === 0) { - // If we have nothing in the buffer, then we want to know - // as soon as we *do* get something into the buffer. - if (!state.ended) { - state.needReadable = true; - } - - // If we tried to read() past the EOF, then emit end on the next tick. - if (nOrig !== n && state.ended) { - endReadable(this); - } - } - - if (ret !== null) { - state.dataEmitted = true; - this.emit("data", ret); - } - - return ret; -}; - -function onEofChunk(stream, state) { - debug("onEofChunk"); - if (state.ended) return; - if (state.decoder) { - const chunk = state.decoder.end(); - if (chunk && chunk.length) { - state.buffer.push(chunk); - state.length += state.objectMode ? 1 : chunk.length; - } - } - state.ended = true; - - if (state.sync) { - // If we are sync, wait until next tick to emit the data. - // Otherwise we risk emitting data in the flow() - // the readable code triggers during a read() call. - emitReadable(stream); - } else { - // Emit 'readable' now to make sure it gets picked up. - state.needReadable = false; - state.emittedReadable = true; - // We have to emit readable now that we are EOF. Modules - // in the ecosystem (e.g. dicer) rely on this event being sync. - emitReadable_(stream); - } -} - -// Don't emit readable right away in sync mode, because this can trigger -// another read() call => stack overflow. This way, it might trigger -// a nextTick recursion warning, but that's not so bad. -function emitReadable(stream) { - const state = stream._readableState; - debug("emitReadable", state.needReadable, state.emittedReadable); - state.needReadable = false; - if (!state.emittedReadable) { - debug("emitReadable", state.flowing); - state.emittedReadable = true; - nextTick(emitReadable_, stream); - } -} - -function emitReadable_(stream) { - const state = stream._readableState; - debug("emitReadable_", state.destroyed, state.length, state.ended); - if (!state.destroyed && !state.errored && (state.length || state.ended)) { - stream.emit("readable"); - state.emittedReadable = false; - } - - // The stream needs another readable event if: - // 1. It is not flowing, as the flow mechanism will take - // care of it. - // 2. It is not ended. - // 3. It is below the highWaterMark, so we can schedule - // another readable later. - state.needReadable = !state.flowing && - !state.ended && - state.length <= state.highWaterMark; - flow(stream); -} - -// At this point, the user has presumably seen the 'readable' event, -// and called read() to consume some data. that may have triggered -// in turn another _read(n) call, in which case reading = true if -// it's in progress. -// However, if we're not ended, or reading, and the length < hwm, -// then go ahead and try to read some more preemptively. -function maybeReadMore(stream, state) { - if (!state.readingMore && state.constructed) { - state.readingMore = true; - nextTick(maybeReadMore_, stream, state); - } -} - -function maybeReadMore_(stream, state) { - // Attempt to read more data if we should. - // - // The conditions for reading more data are (one of): - // - Not enough data buffered (state.length < state.highWaterMark). The loop - // is responsible for filling the buffer with enough data if such data - // is available. If highWaterMark is 0 and we are not in the flowing mode - // we should _not_ attempt to buffer any extra data. We'll get more data - // when the stream consumer calls read() instead. - // - No data in the buffer, and the stream is in flowing mode. In this mode - // the loop below is responsible for ensuring read() is called. Failing to - // call read here would abort the flow and there's no other mechanism for - // continuing the flow if the stream consumer has just subscribed to the - // 'data' event. - // - // In addition to the above conditions to keep reading data, the following - // conditions prevent the data from being read: - // - The stream has ended (state.ended). - // - There is already a pending 'read' operation (state.reading). This is a - // case where the stream has called the implementation defined _read() - // method, but they are processing the call asynchronously and have _not_ - // called push() with new data. In this case we skip performing more - // read()s. The execution ends in this method again after the _read() ends - // up calling push() with more data. - while ( - !state.reading && !state.ended && - (state.length < state.highWaterMark || - (state.flowing && state.length === 0)) - ) { - const len = state.length; - debug("maybeReadMore read 0"); - stream.read(0); - if (len === state.length) { - // Didn't get any data, stop spinning. - break; - } - } - state.readingMore = false; -} - -// Abstract method. to be overridden in specific implementation classes. -// call cb(er, data) where data is <= n in length. -// for virtual (non-string, non-buffer) streams, "length" is somewhat -// arbitrary, and perhaps not very meaningful. -Readable.prototype._read = function (n) { - throw new ERR_METHOD_NOT_IMPLEMENTED("_read()"); -}; - -Readable.prototype.pipe = function (dest, pipeOpts) { - const src = this; - const state = this._readableState; - - if (state.pipes.length === 1) { - if (!state.multiAwaitDrain) { - state.multiAwaitDrain = true; - state.awaitDrainWriters = new Set( - state.awaitDrainWriters ? [state.awaitDrainWriters] : [], - ); - } - } - - state.pipes.push(dest); - debug("pipe count=%d opts=%j", state.pipes.length, pipeOpts); - - const doEnd = (!pipeOpts || pipeOpts.end !== false) && - dest !== stdio.stdout && - dest !== stdio.stderr; - - const endFn = doEnd ? onend : unpipe; - if (state.endEmitted) { - nextTick(endFn); - } else { - src.once("end", endFn); - } - - dest.on("unpipe", onunpipe); - function onunpipe(readable, unpipeInfo) { - debug("onunpipe"); - if (readable === src) { - if (unpipeInfo && unpipeInfo.hasUnpiped === false) { - unpipeInfo.hasUnpiped = true; - cleanup(); - } - } - } - - function onend() { - debug("onend"); - dest.end(); - } - - let ondrain; - - let cleanedUp = false; - function cleanup() { - debug("cleanup"); - // Cleanup event handlers once the pipe is broken. - dest.removeListener("close", onclose); - dest.removeListener("finish", onfinish); - if (ondrain) { - dest.removeListener("drain", ondrain); - } - dest.removeListener("error", onerror); - dest.removeListener("unpipe", onunpipe); - src.removeListener("end", onend); - src.removeListener("end", unpipe); - src.removeListener("data", ondata); - - cleanedUp = true; - - // If the reader is waiting for a drain event from this - // specific writer, then it would cause it to never start - // flowing again. - // So, if this is awaiting a drain, then we just call it now. - // If we don't know, then assume that we are waiting for one. - if ( - ondrain && state.awaitDrainWriters && - (!dest._writableState || dest._writableState.needDrain) - ) { - ondrain(); - } - } - - function pause() { - // If the user unpiped during `dest.write()`, it is possible - // to get stuck in a permanently paused state if that write - // also returned false. - // => Check whether `dest` is still a piping destination. - if (!cleanedUp) { - if (state.pipes.length === 1 && state.pipes[0] === dest) { - debug("false write response, pause", 0); - state.awaitDrainWriters = dest; - state.multiAwaitDrain = false; - } else if (state.pipes.length > 1 && state.pipes.includes(dest)) { - debug("false write response, pause", state.awaitDrainWriters.size); - state.awaitDrainWriters.add(dest); - } - src.pause(); - } - if (!ondrain) { - // When the dest drains, it reduces the awaitDrain counter - // on the source. This would be more elegant with a .once() - // handler in flow(), but adding and removing repeatedly is - // too slow. - ondrain = pipeOnDrain(src, dest); - dest.on("drain", ondrain); - } - } - - src.on("data", ondata); - function ondata(chunk) { - debug("ondata"); - const ret = dest.write(chunk); - debug("dest.write", ret); - if (ret === false) { - pause(); - } - } - - // If the dest has an error, then stop piping into it. - // However, don't suppress the throwing behavior for this. - function onerror(er) { - debug("onerror", er); - unpipe(); - dest.removeListener("error", onerror); - if (EE.listenerCount(dest, "error") === 0) { - const s = dest._writableState || dest._readableState; - if (s && !s.errorEmitted) { - // User incorrectly emitted 'error' directly on the stream. - errorOrDestroy(dest, er); - } else { - dest.emit("error", er); - } - } - } - - // Make sure our error handler is attached before userland ones. - prependListener(dest, "error", onerror); - - // Both close and finish should trigger unpipe, but only once. - function onclose() { - dest.removeListener("finish", onfinish); - unpipe(); - } - dest.once("close", onclose); - function onfinish() { - debug("onfinish"); - dest.removeListener("close", onclose); - unpipe(); - } - dest.once("finish", onfinish); - - function unpipe() { - debug("unpipe"); - src.unpipe(dest); - } - - // Tell the dest that it's being piped to. - dest.emit("pipe", src); - - // Start the flow if it hasn't been started already. - - if (dest.writableNeedDrain === true) { - if (state.flowing) { - pause(); - } - } else if (!state.flowing) { - debug("pipe resume"); - src.resume(); - } - - return dest; -}; - -function pipeOnDrain(src, dest) { - return function pipeOnDrainFunctionResult() { - const state = src._readableState; - - // `ondrain` will call directly, - // `this` maybe not a reference to dest, - // so we use the real dest here. - if (state.awaitDrainWriters === dest) { - debug("pipeOnDrain", 1); - state.awaitDrainWriters = null; - } else if (state.multiAwaitDrain) { - debug("pipeOnDrain", state.awaitDrainWriters.size); - state.awaitDrainWriters.delete(dest); - } - - if ( - (!state.awaitDrainWriters || state.awaitDrainWriters.size === 0) && - EE.listenerCount(src, "data") - ) { - state.flowing = true; - flow(src); - } - }; -} - -Readable.prototype.unpipe = function (dest) { - const state = this._readableState; - const unpipeInfo = { hasUnpiped: false }; - - // If we're not piping anywhere, then do nothing. - if (state.pipes.length === 0) { - return this; - } - - if (!dest) { - // remove all. - const dests = state.pipes; - state.pipes = []; - this.pause(); - - for (let i = 0; i < dests.length; i++) { - dests[i].emit("unpipe", this, { hasUnpiped: false }); - } - return this; - } - - // Try to find the right one. - const index = state.pipes.indexOf(dest); - if (index === -1) { - return this; - } - - state.pipes.splice(index, 1); - if (state.pipes.length === 0) { - this.pause(); - } - - dest.emit("unpipe", this, unpipeInfo); - - return this; -}; - -// Set up data events if they are asked for -// Ensure readable listeners eventually get something. -Readable.prototype.on = function (ev, fn) { - const res = Stream.prototype.on.call(this, ev, fn); - const state = this._readableState; - - if (ev === "data") { - // Update readableListening so that resume() may be a no-op - // a few lines down. This is needed to support once('readable'). - state.readableListening = this.listenerCount("readable") > 0; - - // Try start flowing on next tick if stream isn't explicitly paused. - if (state.flowing !== false) { - this.resume(); - } - } else if (ev === "readable") { - if (!state.endEmitted && !state.readableListening) { - state.readableListening = state.needReadable = true; - state.flowing = false; - state.emittedReadable = false; - debug("on readable", state.length, state.reading); - if (state.length) { - emitReadable(this); - } else if (!state.reading) { - nextTick(nReadingNextTick, this); - } - } - } - - return res; -}; -Readable.prototype.addListener = Readable.prototype.on; - -Readable.prototype.removeListener = function (ev, fn) { - const res = Stream.prototype.removeListener.call(this, ev, fn); - - if (ev === "readable") { - // We need to check if there is someone still listening to - // readable and reset the state. However this needs to happen - // after readable has been emitted but before I/O (nextTick) to - // support once('readable', fn) cycles. This means that calling - // resume within the same tick will have no - // effect. - nextTick(updateReadableListening, this); - } - - return res; -}; -Readable.prototype.off = Readable.prototype.removeListener; - -Readable.prototype.removeAllListeners = function (ev) { - const res = Stream.prototype.removeAllListeners.apply(this, arguments); - - if (ev === "readable" || ev === undefined) { - // We need to check if there is someone still listening to - // readable and reset the state. However this needs to happen - // after readable has been emitted but before I/O (nextTick) to - // support once('readable', fn) cycles. This means that calling - // resume within the same tick will have no - // effect. - nextTick(updateReadableListening, this); - } - - return res; -}; - -function updateReadableListening(self) { - const state = self._readableState; - state.readableListening = self.listenerCount("readable") > 0; - - if (state.resumeScheduled && state[kPaused] === false) { - // Flowing needs to be set to true now, otherwise - // the upcoming resume will not flow. - state.flowing = true; - - // Crude way to check if we should resume. - } else if (self.listenerCount("data") > 0) { - self.resume(); - } else if (!state.readableListening) { - state.flowing = null; - } -} - -function nReadingNextTick(self) { - debug("readable nexttick read 0"); - self.read(0); -} - -// pause() and resume() are remnants of the legacy readable stream API -// If the user uses them, then switch into old mode. -Readable.prototype.resume = function () { - const state = this._readableState; - if (!state.flowing) { - debug("resume"); - // We flow only if there is no one listening - // for readable, but we still have to call - // resume(). - state.flowing = !state.readableListening; - resume(this, state); - } - state[kPaused] = false; - return this; -}; - -function resume(stream, state) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - nextTick(resume_, stream, state); - } -} - -function resume_(stream, state) { - debug("resume", state.reading); - if (!state.reading) { - stream.read(0); - } - - state.resumeScheduled = false; - stream.emit("resume"); - flow(stream); - if (state.flowing && !state.reading) { - stream.read(0); - } -} - -Readable.prototype.pause = function () { - debug("call pause flowing=%j", this._readableState.flowing); - if (this._readableState.flowing !== false) { - debug("pause"); - this._readableState.flowing = false; - this.emit("pause"); - } - this._readableState[kPaused] = true; - return this; -}; - -function flow(stream) { - const state = stream._readableState; - debug("flow", state.flowing); - while (state.flowing && stream.read() !== null); -} - -// Wrap an old-style stream as the async data source. -// This is *not* part of the readable stream interface. -// It is an ugly unfortunate mess of history. -Readable.prototype.wrap = function (stream) { - let paused = false; - - // TODO (ronag): Should this.destroy(err) emit - // 'error' on the wrapped stream? Would require - // a static factory method, e.g. Readable.wrap(stream). - - stream.on("data", (chunk) => { - if (!this.push(chunk) && stream.pause) { - paused = true; - stream.pause(); - } - }); - - stream.on("end", () => { - this.push(null); - }); - - stream.on("error", (err) => { - errorOrDestroy(this, err); - }); - - stream.on("close", () => { - this.destroy(); - }); - - stream.on("destroy", () => { - this.destroy(); - }); - - this._read = () => { - if (paused && stream.resume) { - paused = false; - stream.resume(); - } - }; - - // Proxy all the other methods. Important when wrapping filters and duplexes. - const streamKeys = Object.keys(stream); - for (let j = 1; j < streamKeys.length; j++) { - const i = streamKeys[j]; - if (this[i] === undefined && typeof stream[i] === "function") { - this[i] = stream[i].bind(stream); - } - } - - return this; -}; - -Readable.prototype[Symbol.asyncIterator] = function () { - return streamToAsyncIterator(this); -}; - -Readable.prototype.iterator = function (options) { - if (options !== undefined) { - validateObject(options, "options"); - } - return streamToAsyncIterator(this, options); -}; - -function streamToAsyncIterator(stream, options) { - if (typeof stream.read !== "function") { - stream = Readable.wrap(stream, { objectMode: true }); - } - - const iter = createAsyncIterator(stream, options); - iter.stream = stream; - return iter; -} - -async function* createAsyncIterator(stream, options) { - let callback = nop; - - const opts = { - destroyOnReturn: true, - destroyOnError: true, - ...options, - }; - - function next(resolve) { - if (this === stream) { - callback(); - callback = nop; - } else { - callback = resolve; - } - } - - const state = stream._readableState; - - let error = state.errored; - let errorEmitted = state.errorEmitted; - let endEmitted = state.endEmitted; - let closeEmitted = state.closeEmitted; - - stream - .on("readable", next) - .on("error", function (err) { - error = err; - errorEmitted = true; - next.call(this); - }) - .on("end", function () { - endEmitted = true; - next.call(this); - }) - .on("close", function () { - closeEmitted = true; - next.call(this); - }); - - let errorThrown = false; - try { - while (true) { - const chunk = stream.destroyed ? null : stream.read(); - if (chunk !== null) { - yield chunk; - } else if (errorEmitted) { - throw error; - } else if (endEmitted) { - break; - } else if (closeEmitted) { - break; - } else { - await new Promise(next); - } - } - } catch (err) { - if (opts.destroyOnError) { - destroyImpl.destroyer(stream, err); - } - errorThrown = true; - throw err; - } finally { - if (!errorThrown && opts.destroyOnReturn) { - if (state.autoDestroy || !endEmitted) { - // TODO(ronag): ERR_PREMATURE_CLOSE? - destroyImpl.destroyer(stream, null); - } - } - } -} - -// Making it explicit these properties are not enumerable -// because otherwise some prototype manipulation in -// userland will fail. -Object.defineProperties(Readable.prototype, { - readable: { - get() { - const r = this._readableState; - // r.readable === false means that this is part of a Duplex stream - // where the readable side was disabled upon construction. - // Compat. The user might manually disable readable side through - // deprecated setter. - return !!r && r.readable !== false && !r.destroyed && !r.errorEmitted && - !r.endEmitted; - }, - set(val) { - // Backwards compat. - if (this._readableState) { - this._readableState.readable = !!val; - } - }, - }, - - readableDidRead: { - enumerable: false, - get: function () { - return this._readableState.dataEmitted; - }, - }, - - readableAborted: { - enumerable: false, - get: function () { - return !!(this._readableState.destroyed || this._readableState.errored) && - !this._readableState.endEmitted; - }, - }, - - readableHighWaterMark: { - enumerable: false, - get: function () { - return this._readableState.highWaterMark; - }, - }, - - readableBuffer: { - enumerable: false, - get: function () { - return this._readableState && this._readableState.buffer; - }, - }, - - readableFlowing: { - enumerable: false, - get: function () { - return this._readableState.flowing; - }, - set: function (state) { - if (this._readableState) { - this._readableState.flowing = state; - } - }, - }, - - readableLength: { - enumerable: false, - get() { - return this._readableState.length; - }, - }, - - readableObjectMode: { - enumerable: false, - get() { - return this._readableState ? this._readableState.objectMode : false; - }, - }, - - readableEncoding: { - enumerable: false, - get() { - return this._readableState ? this._readableState.encoding : null; - }, - }, - - destroyed: { - enumerable: false, - get() { - if (this._readableState === undefined) { - return false; - } - return this._readableState.destroyed; - }, - set(value) { - // We ignore the value if the stream - // has not been initialized yet. - if (!this._readableState) { - return; - } - - // Backward compatibility, the user is explicitly - // managing destroyed. - this._readableState.destroyed = value; - }, - }, - - readableEnded: { - enumerable: false, - get() { - return this._readableState ? this._readableState.endEmitted : false; - }, - }, -}); - -Object.defineProperties(ReadableState.prototype, { - // Legacy getter for `pipesCount`. - pipesCount: { - get() { - return this.pipes.length; - }, - }, - - // Legacy property for `paused`. - paused: { - get() { - return this[kPaused] !== false; - }, - set(value) { - this[kPaused] = !!value; - }, - }, -}); - -// Pluck off n bytes from an array of buffers. -// Length is the combined lengths of all the buffers in the list. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromList(n, state) { - // nothing buffered. - if (state.length === 0) { - return null; - } - - let ret; - if (state.objectMode) { - ret = state.buffer.shift(); - } else if (!n || n >= state.length) { - // Read it all, truncate the list. - if (state.decoder) { - ret = state.buffer.join(""); - } else if (state.buffer.length === 1) { - ret = state.buffer.first(); - } else { - ret = state.buffer.concat(state.length); - } - state.buffer.clear(); - } else { - // read part of list. - ret = state.buffer.consume(n, state.decoder); - } - - return ret; -} - -function endReadable(stream) { - const state = stream._readableState; - - debug("endReadable", state.endEmitted); - if (!state.endEmitted) { - state.ended = true; - nextTick(endReadableNT, state, stream); - } -} - -function endReadableNT(state, stream) { - debug("endReadableNT", state.endEmitted, state.length); - - // Check that we didn't get one last unshift. - if ( - !state.errorEmitted && !state.closeEmitted && - !state.endEmitted && state.length === 0 - ) { - state.endEmitted = true; - stream.emit("end"); - - if (stream.writable && stream.allowHalfOpen === false) { - nextTick(endWritableNT, stream); - } else if (state.autoDestroy) { - // In case of duplex streams we need a way to detect - // if the writable side is ready for autoDestroy as well. - const wState = stream._writableState; - const autoDestroy = !wState || ( - wState.autoDestroy && - // We don't expect the writable to ever 'finish' - // if writable is explicitly set to false. - (wState.finished || wState.writable === false) - ); - - if (autoDestroy) { - stream.destroy(); - } - } - } -} - -function endWritableNT(stream) { - const writable = stream.writable && !stream.writableEnded && - !stream.destroyed; - if (writable) { - stream.end(); - } -} - -function readableFrom(iterable, opts) { - return _from(Readable, iterable, opts); -} - -function isReadableStream(object) { - return object instanceof ReadableStream; -} - -export const fromWeb = Readable.fromWeb = function ( - readableStream, - options = {}, -) { - if (!isReadableStream(readableStream)) { - throw new ERR_INVALID_ARG_TYPE( - "readableStream", - "ReadableStream", - readableStream, - ); - } - - validateObject(options, "options"); - const { - highWaterMark, - encoding, - objectMode = false, - signal, - } = options; - - if (encoding !== undefined && !Buffer.isEncoding(encoding)) { - throw new ERR_INVALID_ARG_VALUE(encoding, "options.encoding"); - } - validateBoolean(objectMode, "options.objectMode"); - - const reader = readableStream.getReader(); - let closed = false; - - const readable = new Readable({ - objectMode, - highWaterMark, - encoding, - signal, - - read() { - reader.read().then( - (chunk) => { - if (chunk.done) { - readable.push(null); - } else { - readable.push(chunk.value); - } - }, - (error) => destroy.call(readable, error), - ); - }, - - destroy(error, callback) { - function done() { - try { - callback(error); - } catch (error) { - // In a next tick because this is happening within - // a promise context, and if there are any errors - // thrown we don't want those to cause an unhandled - // rejection. Let's just escape the promise and - // handle it separately. - process.nextTick(() => { - throw error; - }); - } - } - - if (!closed) { - reader.cancel(error).then(done, done); - return; - } - - done(); - }, - }); - - reader.closed.then( - () => { - closed = true; - if (!isReadableEnded(readable)) { - readable.push(null); - } - }, - (error) => { - closed = true; - destroy.call(readable, error); - }, - ); - - return readable; -}; - -function wrap(src, options) { - return new Readable({ - objectMode: src.readableObjectMode ?? src.objectMode ?? true, - ...options, - destroy(err, callback) { - destroyImpl.destroyer(src, err); - callback(err); - }, - }).wrap(src); -} - -// Exposed for testing purposes only. -Readable._fromList = fromList; -Readable.ReadableState = ReadableState; -Readable.from = readableFrom; -Readable.wrap = wrap; +import { Readable } from "../../_stream.mjs"; +const { ReadableState, _fromList, from, fromWeb, toWeb, wrap } = Readable; export default Readable; -export { fromList as _fromList, readableFrom as from, ReadableState, wrap }; +export { _fromList, from, fromWeb, ReadableState, toWeb, wrap }; diff --git a/node/internal/streams/state.mjs b/node/internal/streams/state.mjs index 381a03d956ef..2ca5fa353413 100644 --- a/node/internal/streams/state.mjs +++ b/node/internal/streams/state.mjs @@ -2,36 +2,9 @@ // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file -import { ERR_INVALID_ARG_VALUE } from "../errors.ts"; - -function highWaterMarkFrom(options, isDuplex, duplexKey) { - return options.highWaterMark != null - ? options.highWaterMark - : isDuplex - ? options[duplexKey] - : null; -} - function getDefaultHighWaterMark(objectMode) { return objectMode ? 16 : 16 * 1024; } -function getHighWaterMark(state, options, duplexKey, isDuplex) { - const hwm = highWaterMarkFrom(options, isDuplex, duplexKey); - if (hwm != null) { - if (!Number.isInteger(hwm) || hwm < 0) { - const name = isDuplex ? `options.${duplexKey}` : "options.highWaterMark"; - throw new ERR_INVALID_ARG_VALUE(name, hwm); - } - return Math.floor(hwm); - } - - // Default value - return getDefaultHighWaterMark(state.objectMode); -} - -export default { - getHighWaterMark, - getDefaultHighWaterMark, -}; -export { getDefaultHighWaterMark, getHighWaterMark }; +export default { getDefaultHighWaterMark }; +export { getDefaultHighWaterMark }; diff --git a/node/internal/streams/transform.mjs b/node/internal/streams/transform.mjs index 91f4c9e8127a..7736db6a0fa5 100644 --- a/node/internal/streams/transform.mjs +++ b/node/internal/streams/transform.mjs @@ -2,190 +2,6 @@ // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file -import { ERR_METHOD_NOT_IMPLEMENTED } from "../errors.ts"; -import * as process from "../../_process/process.ts"; -import Duplex from "./duplex.mjs"; - -Object.setPrototypeOf(Transform.prototype, Duplex.prototype); -Object.setPrototypeOf(Transform, Duplex); - -const kCallback = Symbol("kCallback"); - -function Transform(options) { - if (!(this instanceof Transform)) { - return new Transform(options); - } - - Duplex.call(this, options); - - // We have implemented the _read method, and done the other things - // that Readable wants before the first _read call, so unset the - // sync guard flag. - this._readableState.sync = false; - - this[kCallback] = null; - - if (options) { - if (typeof options.transform === "function") { - this._transform = options.transform; - } - - if (typeof options.flush === "function") { - this._flush = options.flush; - } - } - - // When the writable side finishes, then flush out anything remaining. - // Backwards compat. Some Transform streams incorrectly implement _final - // instead of or in addition to _flush. By using 'prefinish' instead of - // implementing _final we continue supporting this unfortunate use case. - this.on("prefinish", prefinish); -} - -function final(cb) { - let called = false; - if (typeof this._flush === "function" && !this.destroyed) { - const result = this._flush((er, data) => { - called = true; - if (er) { - if (cb) { - cb(er); - } else { - this.destroy(er); - } - return; - } - - if (data != null) { - this.push(data); - } - this.push(null); - if (cb) { - cb(); - } - }); - if (result !== undefined && result !== null) { - try { - const then = result.then; - if (typeof then === "function") { - then.call( - result, - (data) => { - if (called) { - return; - } - if (data != null) { - this.push(data); - } - this.push(null); - if (cb) { - process.nextTick(cb); - } - }, - (err) => { - if (cb) { - process.nextTick(cb, err); - } else { - process.nextTick(() => this.destroy(err)); - } - }, - ); - } - } catch (err) { - process.nextTick(() => this.destroy(err)); - } - } - } else { - this.push(null); - if (cb) { - cb(); - } - } -} - -function prefinish() { - if (this._final !== final) { - final.call(this); - } -} - -Transform.prototype._final = final; - -Transform.prototype._transform = function (chunk, encoding, callback) { - throw new ERR_METHOD_NOT_IMPLEMENTED("_transform()"); -}; - -Transform.prototype._write = function (chunk, encoding, callback) { - const rState = this._readableState; - const wState = this._writableState; - const length = rState.length; - - let called = false; - const result = this._transform(chunk, encoding, (err, val) => { - called = true; - if (err) { - callback(err); - return; - } - - if (val != null) { - this.push(val); - } - - if ( - wState.ended || // Backwards compat. - length === rState.length || // Backwards compat. - rState.length < rState.highWaterMark || - rState.length === 0 - ) { - callback(); - } else { - this[kCallback] = callback; - } - }); - if (result !== undefined && result != null) { - try { - const then = result.then; - if (typeof then === "function") { - then.call( - result, - (val) => { - if (called) { - return; - } - - if (val != null) { - this.push(val); - } - - if ( - wState.ended || - length === rState.length || - rState.length < rState.highWaterMark || - rState.length === 0 - ) { - process.nextTick(callback); - } else { - this[kCallback] = callback; - } - }, - (err) => { - process.nextTick(callback, err); - }, - ); - } - } catch (err) { - process.nextTick(callback, err); - } - } -}; - -Transform.prototype._read = function () { - if (this[kCallback]) { - const callback = this[kCallback]; - this[kCallback] = null; - callback(); - } -}; +import { Transform } from "../../_stream.mjs"; export default Transform; diff --git a/node/internal/streams/writable.mjs b/node/internal/streams/writable.mjs index d9492582a701..1626118abe36 100644 --- a/node/internal/streams/writable.mjs +++ b/node/internal/streams/writable.mjs @@ -2,1034 +2,8 @@ // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file -import { validateBoolean, validateObject } from "../validators.mjs"; -import { _uint8ArrayToBuffer } from "./_utils.ts"; -import { addAbortSignalNoValidate } from "./add-abort-signal.mjs"; -import { Buffer } from "../../buffer.ts"; -import { getDefaultHighWaterMark, getHighWaterMark } from "./state.mjs"; -import { isUint8Array } from "../util/types.ts"; -import { Stream } from "./legacy.mjs"; -import { - ERR_INVALID_ARG_TYPE, - ERR_METHOD_NOT_IMPLEMENTED, - ERR_MULTIPLE_CALLBACK, - ERR_STREAM_ALREADY_FINISHED, - ERR_STREAM_CANNOT_PIPE, - ERR_STREAM_DESTROYED, - ERR_STREAM_NULL_VALUES, - ERR_STREAM_PREMATURE_CLOSE, - ERR_STREAM_WRITE_AFTER_END, - ERR_UNKNOWN_ENCODING, -} from "../errors.ts"; -import * as process from "../../_process/process.ts"; -import destroyImpl from "./destroy.mjs"; -import EE from "../../events.ts"; -import Readable from "./readable.mjs"; -import { isWritableEnded } from "./utils.mjs"; - -const { errorOrDestroy } = destroyImpl; - -// This function prevents a circular dependency with Duplex -// This checks if the passed stream is an instance of a Readable stream -// and one of its prototypes is named Duplex -function isDuplexStream(maybe_duplex) { - const isReadable = Readable.prototype.isPrototypeOf(maybe_duplex); - - let prototype = maybe_duplex; - let isDuplex = false; - while (prototype?.constructor && prototype.constructor.name !== "Object") { - if (prototype.constructor.name === "Duplex") { - isDuplex = true; - break; - } - prototype = Object.getPrototypeOf(prototype); - } - - return isReadable && isDuplex; -} - -Object.setPrototypeOf(Writable.prototype, Stream.prototype); -Object.setPrototypeOf(Writable, Stream); - -function nop() {} - -const kOnFinished = Symbol("kOnFinished"); - -function WritableState(options, stream, isDuplex) { - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream, - // e.g. options.readableObjectMode vs. options.writableObjectMode, etc. - if (typeof isDuplex !== "boolean") { - isDuplex = isDuplexStream(stream); - } - - // Object stream flag to indicate whether or not this stream - // contains buffers or objects. - this.objectMode = !!(options && options.objectMode); - - if (isDuplex) { - this.objectMode = this.objectMode || - !!(options && options.writableObjectMode); - } - - // The point at which write() starts returning false - // Note: 0 is a valid value, means that we always return false if - // the entire buffer is not flushed immediately on write(). - this.highWaterMark = options - ? getHighWaterMark(this, options, "writableHighWaterMark", isDuplex) - : getDefaultHighWaterMark(false); - - // if _final has been called. - this.finalCalled = false; - - // drain event flag. - this.needDrain = false; - // At the start of calling end() - this.ending = false; - // When end() has been called, and returned. - this.ended = false; - // When 'finish' is emitted. - this.finished = false; - - // Has it been destroyed - this.destroyed = false; - - // Should we decode strings into buffers before passing to _write? - // this is here so that some node-core streams can optimize string - // handling at a lower level. - const noDecode = !!(options && options.decodeStrings === false); - this.decodeStrings = !noDecode; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = (options && options.defaultEncoding) || "utf8"; - - // Not an actual buffer we keep track of, but a measurement - // of how much we're waiting to get pushed to some underlying - // socket or file. - this.length = 0; - - // A flag to see when we're in the middle of a write. - this.writing = false; - - // When true all writes will be buffered until .uncork() call. - this.corked = 0; - - // A flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // A flag to know if we're processing previously buffered items, which - // may call the _write() callback in the same tick, so that we don't - // end up in an overlapped onwrite situation. - this.bufferProcessing = false; - - // The callback that's passed to _write(chunk, cb). - this.onwrite = onwrite.bind(undefined, stream); - - // The callback that the user supplies to write(chunk, encoding, cb). - this.writecb = null; - - // The amount that is being written when _write is called. - this.writelen = 0; - - // Storage for data passed to the afterWrite() callback in case of - // synchronous _write() completion. - this.afterWriteTickInfo = null; - - resetBuffer(this); - - // Number of pending user-supplied write callbacks - // this must be 0 before 'finish' can be emitted. - this.pendingcb = 0; - - // Stream is still being constructed and cannot be - // destroyed until construction finished or failed. - // Async construction is opt in, therefore we start as - // constructed. - this.constructed = true; - - // Emit prefinish if the only thing we're waiting for is _write cbs - // This is relevant for synchronous Transform streams. - this.prefinished = false; - - // True if the error was already emitted and should not be thrown again. - this.errorEmitted = false; - - // Should close be emitted on destroy. Defaults to true. - this.emitClose = !options || options.emitClose !== false; - - // Should .destroy() be called after 'finish' (and potentially 'end'). - this.autoDestroy = !options || options.autoDestroy !== false; - - // Indicates whether the stream has errored. When true all write() calls - // should return false. This is needed since when autoDestroy - // is disabled we need a way to tell whether the stream has failed. - this.errored = null; - - // Indicates whether the stream has finished destroying. - this.closed = false; - - // True if close has been emitted or would have been emitted - // depending on emitClose. - this.closeEmitted = false; - - this[kOnFinished] = []; -} - -function resetBuffer(state) { - state.buffered = []; - state.bufferedIndex = 0; - state.allBuffers = true; - state.allNoop = true; -} - -WritableState.prototype.getBuffer = function getBuffer() { - return this.buffered.slice(this.bufferedIndex); -}; - -Object.defineProperty(WritableState.prototype, "bufferedRequestCount", { - get() { - return this.buffered.length - this.bufferedIndex; - }, -}); - -function Writable(options) { - // Writable ctor is applied to Duplexes, too. - // `realHasInstance` is necessary because using plain `instanceof` - // would return false, as no `_writableState` property is attached. - - // Trying to use the custom `instanceof` for Writable here will also break the - // Node.js LazyTransform implementation, which has a non-trivial getter for - // `_writableState` that would lead to infinite recursion. - - // Checking for a Stream.Duplex instance is faster here instead of inside - // the WritableState constructor, at least with V8 6.5. - const isDuplex = isDuplexStream(this); - - if ( - !isDuplex && !Function.prototype[Symbol.hasInstance].call(Writable, this) - ) { - return new Writable(options); - } - - this._writableState = new WritableState(options, this, isDuplex); - - if (options) { - if (typeof options.write === "function") { - this._write = options.write; - } - - if (typeof options.writev === "function") { - this._writev = options.writev; - } - - if (typeof options.destroy === "function") { - this._destroy = options.destroy; - } - - if (typeof options.final === "function") { - this._final = options.final; - } - - if (typeof options.construct === "function") { - this._construct = options.construct; - } - if (options.signal) { - addAbortSignalNoValidate(options.signal, this); - } - } - - Stream.call(this, options); - - destroyImpl.construct(this, () => { - const state = this._writableState; - - if (!state.writing) { - clearBuffer(this, state); - } - - finishMaybe(this, state); - }); -} - -Object.defineProperty(Writable, Symbol.hasInstance, { - value: function (object) { - if (Function.prototype[Symbol.hasInstance].call(this, object)) return true; - if (this !== Writable) return false; - - return object && object._writableState instanceof WritableState; - }, -}); - -// Otherwise people can pipe Writable streams, which is just wrong. -Writable.prototype.pipe = function () { - errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE()); -}; - -function _write(stream, chunk, encoding, cb) { - const state = stream._writableState; - - if (typeof encoding === "function") { - cb = encoding; - encoding = state.defaultEncoding; - } else { - if (!encoding) { - encoding = state.defaultEncoding; - } else if (encoding !== "buffer" && !Buffer.isEncoding(encoding)) { - throw new ERR_UNKNOWN_ENCODING(encoding); - } - if (typeof cb !== "function") { - cb = nop; - } - } - - if (chunk === null) { - throw new ERR_STREAM_NULL_VALUES(); - } else if (!state.objectMode) { - if (typeof chunk === "string") { - if (state.decodeStrings !== false) { - chunk = Buffer.from(chunk, encoding); - encoding = "buffer"; - } - } else if (chunk instanceof Buffer) { - encoding = "buffer"; - } else if (isUint8Array(chunk)) { - chunk = _uint8ArrayToBuffer(chunk); - encoding = "buffer"; - } else { - throw new ERR_INVALID_ARG_TYPE( - "chunk", - ["string", "Buffer", "Uint8Array"], - chunk, - ); - } - } - - let err; - if (state.ending) { - err = new ERR_STREAM_WRITE_AFTER_END(); - } else if (state.destroyed) { - err = new ERR_STREAM_DESTROYED("write"); - } - - if (err) { - process.nextTick(cb, err); - errorOrDestroy(stream, err, true); - return err; - } - state.pendingcb++; - return writeOrBuffer(stream, state, chunk, encoding, cb); -} - -Writable.prototype.write = function (chunk, encoding, cb) { - return _write(this, chunk, encoding, cb) === true; -}; - -Writable.prototype.cork = function () { - this._writableState.corked++; -}; - -Writable.prototype.uncork = function () { - const state = this._writableState; - - if (state.corked) { - state.corked--; - - if (!state.writing) { - clearBuffer(this, state); - } - } -}; - -Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { - // node::ParseEncoding() requires lower case. - if (typeof encoding === "string") { - encoding = encoding.toLowerCase(); - } - if (!Buffer.isEncoding(encoding)) { - throw new ERR_UNKNOWN_ENCODING(encoding); - } - this._writableState.defaultEncoding = encoding; - return this; -}; - -// If we're already writing something, then just put this -// in the queue, and wait our turn. Otherwise, call _write -// If we return false, then we need a drain event, so set that flag. -function writeOrBuffer(stream, state, chunk, encoding, callback) { - const len = state.objectMode ? 1 : chunk.length; - - state.length += len; - - // stream._write resets state.length - const ret = state.length < state.highWaterMark; - // We must ensure that previous needDrain will not be reset to false. - if (!ret) { - state.needDrain = true; - } - - if (state.writing || state.corked || state.errored || !state.constructed) { - state.buffered.push({ chunk, encoding, callback }); - if (state.allBuffers && encoding !== "buffer") { - state.allBuffers = false; - } - if (state.allNoop && callback !== nop) { - state.allNoop = false; - } - } else { - state.writelen = len; - state.writecb = callback; - state.writing = true; - state.sync = true; - stream._write(chunk, encoding, state.onwrite); - state.sync = false; - } - - // Return false if errored or destroyed in order to break - // any synchronous while(stream.write(data)) loops. - return ret && !state.errored && !state.destroyed; -} - -function doWrite(stream, state, writev, len, chunk, encoding, cb) { - state.writelen = len; - state.writecb = cb; - state.writing = true; - state.sync = true; - if (state.destroyed) { - state.onwrite(new ERR_STREAM_DESTROYED("write")); - } else if (writev) { - stream._writev(chunk, state.onwrite); - } else { - stream._write(chunk, encoding, state.onwrite); - } - state.sync = false; -} - -function onwriteError(stream, state, er, cb) { - --state.pendingcb; - - cb(er); - // Ensure callbacks are invoked even when autoDestroy is - // not enabled. Passing `er` here doesn't make sense since - // it's related to one specific write, not to the buffered - // writes. - errorBuffer(state); - // This can emit error, but error must always follow cb. - errorOrDestroy(stream, er); -} - -function onwrite(stream, er) { - const state = stream._writableState; - const sync = state.sync; - const cb = state.writecb; - - if (typeof cb !== "function") { - errorOrDestroy(stream, new ERR_MULTIPLE_CALLBACK()); - return; - } - - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; - - if (er) { - // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 - er.stack; // eslint-disable-line no-unused-expressions - - if (!state.errored) { - state.errored = er; - } - - // In case of duplex streams we need to notify the readable side of the - // error. - if (stream._readableState && !stream._readableState.errored) { - stream._readableState.errored = er; - } - - if (sync) { - process.nextTick(onwriteError, stream, state, er, cb); - } else { - onwriteError(stream, state, er, cb); - } - } else { - if (state.buffered.length > state.bufferedIndex) { - clearBuffer(stream, state); - } - - if (sync) { - // It is a common case that the callback passed to .write() is always - // the same. In that case, we do not schedule a new nextTick(), but - // rather just increase a counter, to improve performance and avoid - // memory allocations. - if ( - state.afterWriteTickInfo !== null && - state.afterWriteTickInfo.cb === cb - ) { - state.afterWriteTickInfo.count++; - } else { - state.afterWriteTickInfo = { count: 1, cb, stream, state }; - process.nextTick(afterWriteTick, state.afterWriteTickInfo); - } - } else { - afterWrite(stream, state, 1, cb); - } - } -} - -function afterWriteTick({ stream, state, count, cb }) { - state.afterWriteTickInfo = null; - return afterWrite(stream, state, count, cb); -} - -function afterWrite(stream, state, count, cb) { - const needDrain = !state.ending && !stream.destroyed && state.length === 0 && - state.needDrain; - if (needDrain) { - state.needDrain = false; - stream.emit("drain"); - } - - while (count-- > 0) { - state.pendingcb--; - cb(); - } - - if (state.destroyed) { - errorBuffer(state); - } - - finishMaybe(stream, state); -} - -// If there's something in the buffer waiting, then invoke callbacks. -function errorBuffer(state) { - if (state.writing) { - return; - } - - for (let n = state.bufferedIndex; n < state.buffered.length; ++n) { - const { chunk, callback } = state.buffered[n]; - const len = state.objectMode ? 1 : chunk.length; - state.length -= len; - callback(new ERR_STREAM_DESTROYED("write")); - } - - const onfinishCallbacks = state[kOnFinished].splice(0); - for (let i = 0; i < onfinishCallbacks.length; i++) { - onfinishCallbacks[i](new ERR_STREAM_DESTROYED("end")); - } - - resetBuffer(state); -} - -// If there's something in the buffer waiting, then process it. -function clearBuffer(stream, state) { - if ( - state.corked || - state.bufferProcessing || - state.destroyed || - !state.constructed - ) { - return; - } - - const { buffered, bufferedIndex, objectMode } = state; - const bufferedLength = buffered.length - bufferedIndex; - - if (!bufferedLength) { - return; - } - - let i = bufferedIndex; - - state.bufferProcessing = true; - if (bufferedLength > 1 && stream._writev) { - state.pendingcb -= bufferedLength - 1; - - const callback = state.allNoop ? nop : (err) => { - for (let n = i; n < buffered.length; ++n) { - buffered[n].callback(err); - } - }; - // Make a copy of `buffered` if it's going to be used by `callback` above, - // since `doWrite` will mutate the array. - const chunks = state.allNoop && i === 0 ? buffered : buffered.slice(i); - chunks.allBuffers = state.allBuffers; - - doWrite(stream, state, true, state.length, chunks, "", callback); - - resetBuffer(state); - } else { - do { - const { chunk, encoding, callback } = buffered[i]; - buffered[i++] = null; - const len = objectMode ? 1 : chunk.length; - doWrite(stream, state, false, len, chunk, encoding, callback); - } while (i < buffered.length && !state.writing); - - if (i === buffered.length) { - resetBuffer(state); - } else if (i > 256) { - buffered.splice(0, i); - state.bufferedIndex = 0; - } else { - state.bufferedIndex = i; - } - } - state.bufferProcessing = false; -} - -Writable.prototype._write = function (chunk, encoding, cb) { - if (this._writev) { - this._writev([{ chunk, encoding }], cb); - } else { - throw new ERR_METHOD_NOT_IMPLEMENTED("_write()"); - } -}; - -Writable.prototype._writev = null; - -Writable.prototype.end = function (chunk, encoding, cb) { - const state = this._writableState; - - if (typeof chunk === "function") { - cb = chunk; - chunk = null; - encoding = null; - } else if (typeof encoding === "function") { - cb = encoding; - encoding = null; - } - - let err; - - if (chunk !== null && chunk !== undefined) { - const ret = _write(this, chunk, encoding); - if (ret instanceof Error) { - err = ret; - } - } - - // .end() fully uncorks. - if (state.corked) { - state.corked = 1; - this.uncork(); - } - - if (err) { - // Do nothing... - } else if (!state.errored && !state.ending) { - // This is forgiving in terms of unnecessary calls to end() and can hide - // logic errors. However, usually such errors are harmless and causing a - // hard error can be disproportionately destructive. It is not always - // trivial for the user to determine whether end() needs to be called - // or not. - - state.ending = true; - finishMaybe(this, state, true); - state.ended = true; - } else if (state.finished) { - err = new ERR_STREAM_ALREADY_FINISHED("end"); - } else if (state.destroyed) { - err = new ERR_STREAM_DESTROYED("end"); - } - - if (typeof cb === "function") { - if (err || state.finished) { - process.nextTick(cb, err); - } else { - state[kOnFinished].push(cb); - } - } - - return this; -}; - -function needFinish(state) { - return (state.ending && - state.constructed && - state.length === 0 && - !state.errored && - state.buffered.length === 0 && - !state.finished && - !state.writing && - !state.errorEmitted && - !state.closeEmitted); -} - -function callFinal(stream, state) { - let called = false; - - function onFinish(err) { - if (called) { - errorOrDestroy(stream, err ?? ERR_MULTIPLE_CALLBACK()); - return; - } - called = true; - - state.pendingcb--; - if (err) { - const onfinishCallbacks = state[kOnFinished].splice(0); - for (let i = 0; i < onfinishCallbacks.length; i++) { - onfinishCallbacks[i](err); - } - errorOrDestroy(stream, err, state.sync); - } else if (needFinish(state)) { - state.prefinished = true; - stream.emit("prefinish"); - // Backwards compat. Don't check state.sync here. - // Some streams assume 'finish' will be emitted - // asynchronously relative to _final callback. - state.pendingcb++; - process.nextTick(finish, stream, state); - } - } - - state.sync = true; - state.pendingcb++; - - try { - const result = stream._final(onFinish); - if (result != null) { - const then = result.then; - if (typeof then === "function") { - then.call( - result, - function () { - process.nextTick(onFinish, null); - }, - function (err) { - process.nextTick(onFinish, err); - }, - ); - } - } - } catch (err) { - onFinish(stream, state, err); - } - - state.sync = false; -} - -function prefinish(stream, state) { - if (!state.prefinished && !state.finalCalled) { - if (typeof stream._final === "function" && !state.destroyed) { - state.finalCalled = true; - callFinal(stream, state); - } else { - state.prefinished = true; - stream.emit("prefinish"); - } - } -} - -function finishMaybe(stream, state, sync) { - if (needFinish(state)) { - prefinish(stream, state); - if (state.pendingcb === 0 && needFinish(state)) { - state.pendingcb++; - if (sync) { - process.nextTick(finish, stream, state); - } else { - finish(stream, state); - } - } - } -} - -function finish(stream, state) { - state.pendingcb--; - state.finished = true; - - const onfinishCallbacks = state[kOnFinished].splice(0); - for (let i = 0; i < onfinishCallbacks.length; i++) { - onfinishCallbacks[i](); - } - - stream.emit("finish"); - - if (state.autoDestroy) { - // In case of duplex streams we need a way to detect - // if the readable side is ready for autoDestroy as well. - const rState = stream._readableState; - const autoDestroy = !rState || ( - rState.autoDestroy && - // We don't expect the readable to ever 'end' - // if readable is explicitly set to false. - (rState.endEmitted || rState.readable === false) - ); - if (autoDestroy) { - stream.destroy(); - } - } -} - -Object.defineProperties(Writable.prototype, { - destroyed: { - get() { - return this._writableState ? this._writableState.destroyed : false; - }, - set(value) { - // Backward compatibility, the user is explicitly managing destroyed. - if (this._writableState) { - this._writableState.destroyed = value; - } - }, - }, - - writable: { - get() { - const w = this._writableState; - // w.writable === false means that this is part of a Duplex stream - // where the writable side was disabled upon construction. - // Compat. The user might manually disable writable side through - // deprecated setter. - return !!w && w.writable !== false && !w.destroyed && !w.errored && - !w.ending && !w.ended; - }, - set(val) { - // Backwards compatible. - if (this._writableState) { - this._writableState.writable = !!val; - } - }, - }, - - writableFinished: { - get() { - return this._writableState ? this._writableState.finished : false; - }, - }, - - writableObjectMode: { - get() { - return this._writableState ? this._writableState.objectMode : false; - }, - }, - - writableBuffer: { - get() { - return this._writableState && this._writableState.getBuffer(); - }, - }, - - writableEnded: { - get() { - return this._writableState ? this._writableState.ending : false; - }, - }, - - writableNeedDrain: { - get() { - const wState = this._writableState; - if (!wState) return false; - return !wState.destroyed && !wState.ending && wState.needDrain; - }, - }, - - writableHighWaterMark: { - get() { - return this._writableState && this._writableState.highWaterMark; - }, - }, - - writableCorked: { - get() { - return this._writableState ? this._writableState.corked : 0; - }, - }, - - writableLength: { - get() { - return this._writableState && this._writableState.length; - }, - }, -}); - -const destroy = destroyImpl.destroy; -Writable.prototype.destroy = function (err, cb) { - const state = this._writableState; - - // Invoke pending callbacks. - if ( - !state.destroyed && - (state.bufferedIndex < state.buffered.length || - state[kOnFinished].length) - ) { - process.nextTick(errorBuffer, state); - } - - destroy.call(this, err, cb); - return this; -}; - -Writable.prototype._undestroy = destroyImpl.undestroy; -Writable.prototype._destroy = function (err, cb) { - cb(err); -}; - -Writable.prototype[EE.captureRejectionSymbol] = function (err) { - this.destroy(err); -}; - -Writable.WritableState = WritableState; - -function isWritableStream(object) { - return object instanceof WritableStream; -} - -export const fromWeb = Writable.fromWeb = function ( - writableStream, - options = {}, -) { - if (!isWritableStream(writableStream)) { - throw new ERR_INVALID_ARG_TYPE( - "writableStream", - "WritableStream", - writableStream, - ); - } - - validateObject(options, "options"); - const { - highWaterMark, - decodeStrings = true, - objectMode = false, - signal, - } = options; - - validateBoolean(objectMode, "options.objectMode"); - validateBoolean(decodeStrings, "options.decodeStrings"); - - const writer = writableStream.getWriter(); - let closed = false; - - const writable = new Writable({ - highWaterMark, - objectMode, - decodeStrings, - signal, - - writev(chunks, callback) { - function done(error) { - error = error.filter((e) => e); - try { - callback(error.length === 0 ? undefined : error); - } catch (error) { - // In a next tick because this is happening within - // a promise context, and if there are any errors - // thrown we don't want those to cause an unhandled - // rejection. Let's just escape the promise and - // handle it separately. - process.nextTick(() => destroy.call(writable, error)); - } - } - - writer.ready.then( - () => - Promise.all( - chunks.map((data) => writer.write(data.chunk)), - ).then(done, done), - done, - ); - }, - - write(chunk, encoding, callback) { - if (typeof chunk === "string" && decodeStrings && !objectMode) { - chunk = Buffer.from(chunk, encoding); - chunk = new Uint8Array( - chunk.buffer, - chunk.byteOffset, - chunk.byteLength, - ); - } - - function done(error) { - try { - callback(error); - } catch (error) { - destroy(this, duplex, error); - } - } - - writer.ready.then( - () => writer.write(chunk).then(done, done), - done, - ); - }, - - destroy(error, callback) { - function done() { - try { - callback(error); - } catch (error) { - // In a next tick because this is happening within - // a promise context, and if there are any errors - // thrown we don't want those to cause an unhandled - // rejection. Let's just escape the promise and - // handle it separately. - process.nextTick(() => { - throw error; - }); - } - } - - if (!closed) { - if (error != null) { - writer.abort(error).then(done, done); - } else { - writer.close().then(done, done); - } - return; - } - - done(); - }, - - final(callback) { - function done(error) { - try { - callback(error); - } catch (error) { - // In a next tick because this is happening within - // a promise context, and if there are any errors - // thrown we don't want those to cause an unhandled - // rejection. Let's just escape the promise and - // handle it separately. - process.nextTick(() => destroy.call(writable, error)); - } - } - - if (!closed) { - writer.close().then(done, done); - } - }, - }); - - writer.closed.then( - () => { - closed = true; - if (!isWritableEnded(writable)) { - destroy.call(writable, new ERR_STREAM_PREMATURE_CLOSE()); - } - }, - (error) => { - closed = true; - destroy.call(writable, error); - }, - ); - - return writable; -}; - -Writable.Writable = Writable; +import { Writable } from "../../_stream.mjs"; +const { WritableState, fromWeb, toWeb } = Writable; export default Writable; -export { Writable, WritableState }; +export { fromWeb, toWeb, WritableState }; diff --git a/node/module_all.ts b/node/module_all.ts index 31e49beb20de..16172df240eb 100644 --- a/node/module_all.ts +++ b/node/module_all.ts @@ -49,7 +49,6 @@ import internalHttp from "./internal/http.ts"; import internalReadlineUtils from "./internal/readline/utils.mjs"; import internalStreamsAddAbortSignal from "./internal/streams/add-abort-signal.mjs"; import internalStreamsBufferList from "./internal/streams/buffer_list.mjs"; -import internalStreamsDuplexify from "./internal/streams/duplexify.mjs"; import internalStreamsLazyTransform from "./internal/streams/lazy_transform.mjs"; import internalStreamsState from "./internal/streams/state.mjs"; import internalTestBinding from "./internal/test/binding.ts"; @@ -138,7 +137,6 @@ export default { "internal/readline/utils": internalReadlineUtils, "internal/streams/add-abort-signal": internalStreamsAddAbortSignal, "internal/streams/buffer_list": internalStreamsBufferList, - "internal/streams/duplexify": internalStreamsDuplexify, "internal/streams/lazy_transform": internalStreamsLazyTransform, "internal/streams/state": internalStreamsState, "internal/test/binding": internalTestBinding, diff --git a/node/module_all_test.ts b/node/module_all_test.ts index b72427d65fd2..1d29bfca44db 100644 --- a/node/module_all_test.ts +++ b/node/module_all_test.ts @@ -53,7 +53,6 @@ import * as internalHttp from "./internal/http.ts"; import * as internalReadlineUtils from "./internal/readline/utils.mjs"; import * as internalStreamsAddAbortSignal from "./internal/streams/add-abort-signal.mjs"; import * as internalStreamsBufferList from "./internal/streams/buffer_list.mjs"; -import * as internalStreamsDuplexify from "./internal/streams/duplexify.mjs"; import * as internalStreamsLazyTransform from "./internal/streams/lazy_transform.mjs"; import * as internalStreamsState from "./internal/streams/state.mjs"; import * as internalTestBinding from "./internal/test/binding.ts"; @@ -193,10 +192,6 @@ Deno.test("modules", () => { keys(moduleAll["internal/streams/buffer_list"]), keys(internalStreamsBufferList), ); - assertEquals( - keys(moduleAll["internal/streams/duplexify"]), - keys(internalStreamsDuplexify), - ); assertEquals( keys(moduleAll["internal/streams/lazy_transform"]), keys(internalStreamsLazyTransform),