node_modules: update (#344)

Co-authored-by: dawidd6 <9713907+dawidd6@users.noreply.github.com>
This commit is contained in:
Dawid Dziurlaanddawidd6 authored and GitHub committed 2026-10-10 17:27:57 +02:00
1 parent b099186883
commit 6e88c72525
63 files changed
+2863 -1227

No files matched your search

+170 -110
View File
@@ -71,6 +71,14 @@ const PLAIN_ADDRESS = /^[^\s"(),:;<>@[\\\]]+@[^\s"(),:;<>@[\\\]]+$/;
// unroutable garbage into mail for a domain the sender never named. None of these
// characters are legal in a domain, so keep them away from the mapper.
const URL_PARSER_UNSAFE = /[/\\?#%\x00-\x20\x7F]/;
// pipeline() needs a callback to not throw, the errors it sees reach the last stream anyway
const PIPELINE_NOOP = () => false;
// The error a node streaming into an output that was destroyed stops with
function abortedError() {
const err = new Error('Message stream was closed before the message was generated');
err.code = errors.ESTREAM;
return err;
}
/**
* Encodes a domain the way browsers, the WHATWG URL Standard and DNS facing resolvers do,
* which is with UTS-46 mapping applied before the Punycode step.
@@ -90,9 +98,14 @@ const URL_PARSER_UNSAFE = /[/\\?#%\x00-\x20\x7F]/;
*/
function normalizeDomain(domain, toUnicode) {
// domainToASCII and domainToUnicode landed in Node 7, the bundled codec covers Node 6
const mapper = toUnicode ? node_url_1.default.domainToUnicode : node_url_1.default.domainToASCII;
if (typeof mapper === 'function' && !URL_PARSER_UNSAFE.test(domain)) {
const mapped = mapper(domain);
if (typeof node_url_1.default.domainToASCII === 'function' &&
typeof node_url_1.default.domainToUnicode === 'function' &&
!URL_PARSER_UNSAFE.test(domain)) {
// The U-label form is decoded from the A-label form rather than from the input:
// Deno's domainToASCII returns an empty string for a label it cannot decode, while
// its domainToUnicode returns the label with U+FFFD in place of the bad part
const ascii = node_url_1.default.domainToASCII(domain);
const mapped = ascii && toUnicode ? node_url_1.default.domainToUnicode(ascii) : ascii;
if (mapped) {
return mapped;
}
@@ -444,11 +457,7 @@ class MimeNode {
if (typeof this.content.pipe === 'function') {
// pre-stream handler. might be triggered if a stream is set as content
// and 'error' fires before anything is done with this stream
this._contentErrorHandler = err => {
this.content.removeListener('error', this._contentErrorHandler);
this.content = err;
};
this.content.once('error', this._contentErrorHandler);
shared.recordStreamErrors(this.content);
}
else if (typeof this.content === 'string') {
this._isPlainText = mimeFuncs.isPlainText(this.content);
@@ -660,40 +669,45 @@ class MimeNode {
createReadStream(options) {
options = options || {};
const stream = new node_stream_1.PassThrough(options);
let outputStream = stream;
let transform;
this.stream(stream, options, err => {
if (err) {
outputStream.emit('error', err);
stream.destroy(err);
return;
}
stream.end();
});
for (let i = 0, len = this._transforms.length; i < len; i++) {
transform =
typeof this._transforms[i] === 'function' ? this._transforms[i]() : this._transforms[i];
outputStream.once('error', err => {
transform.emit('error', err);
});
outputStream = outputStream.pipe(transform);
// the content streams of the nodes the message did not get to are not going to be read
stream.once('close', () => {
if (!stream.writableFinished) {
this._destroyContentStreams();
}
});
// The stages are joined with pipeline, which destroys all of them when any one fails
// or is destroyed. An error anywhere reaches the returned stream exactly once, and a
// consumer that destroys the returned stream stops the tree from reading its sources
const stages = [stream];
for (const transform of this._transforms) {
stages.push(typeof transform === 'function' ? transform() : transform);
}
// ensure terminating newline after possible user transforms
transform = new last_newline_js_1.default();
outputStream.once('error', err => {
transform.emit('error', err);
});
outputStream = outputStream.pipe(transform);
// dkim and stuff
for (let i = 0, len = this._processFuncs.length; i < len; i++) {
transform = this._processFuncs[i];
outputStream = transform(outputStream);
stages.push(new last_newline_js_1.default());
let outputStream = (0, node_stream_1.pipeline)(stages, PIPELINE_NOOP);
// dkim and stuff. A process function reads its input itself and reports the errors of
// that input on its output, so only a consumer abort has to be carried back upstream
for (const processFunc of this._processFuncs) {
const input = outputStream;
outputStream = processFunc(input);
if (outputStream !== input) {
(0, node_stream_1.finished)(outputStream, err => {
if (err) {
input.destroy();
}
});
}
}
if (this.newline) {
const winbreak = ['win', 'windows', 'dos', '\r\n'].includes(this.newline.toString().toLowerCase());
const newlineTransform = winbreak ? new le_windows_js_1.default() : new le_unix_js_1.default();
const stream = outputStream.pipe(newlineTransform);
outputStream.on('error', err => stream.emit('error', err));
return stream;
outputStream = (0, node_stream_1.pipeline)(outputStream, winbreak ? new le_windows_js_1.default() : new le_unix_js_1.default(), PIPELINE_NOOP);
}
return outputStream;
}
@@ -719,8 +733,10 @@ class MimeNode {
}
stream(outputStream, options, done) {
const transferEncoding = this.getTransferEncoding();
let contentStream;
let localStream;
// the streams this node is reading from. A consumer that goes away mid-message destroys
// the output, and these are released with it instead of staying paused with a file or a
// socket open behind them
let activeStreams = [];
// protect actual callback against multiple triggering
let returned = false;
const callback = (err) => {
@@ -728,13 +744,39 @@ class MimeNode {
return;
}
returned = true;
outputStream.removeListener('close', onOutputClose);
done(err);
};
function onOutputClose() {
for (const stream of activeStreams) {
stream.destroy();
}
return callback(abortedError());
}
// reads the streams into the output. The listener is only attached while the node reads
// something, a deeply nested tree would otherwise stack one per level on the output
const readInto = (...streams) => {
if (!activeStreams.length) {
outputStream.once('close', onOutputClose);
}
activeStreams = streams;
};
// stops here if the output was destroyed in the meantime
const aborted = () => {
if (outputStream.destroyed) {
callback(abortedError());
return true;
}
return false;
};
// for multipart nodes, push child nodes
// for content nodes end the stream
const finalize = () => {
let childId = 0;
const processChildNode = () => {
if (aborted()) {
return;
}
if (childId >= this.childNodes.length) {
outputStream.write('\r\n--' + this.boundary + '--\r\n');
return callback();
@@ -757,89 +799,80 @@ class MimeNode {
};
// pushes node content
const sendContent = () => {
if (this.content) {
if (Object.prototype.toString.call(this.content) === '[object Error]') {
// content is already errored
return callback(this.content);
}
if (typeof this.content.pipe === 'function') {
this.content.removeListener('error', this._contentErrorHandler);
this._contentErrorHandler = err => callback(err);
this.content.once('error', this._contentErrorHandler);
}
const createStream = () => {
if (['quoted-printable', 'base64'].includes(transferEncoding)) {
contentStream = new (transferEncoding === 'base64' ? base64 : qp).Encoder(options);
contentStream.pipe(outputStream, {
end: false
});
contentStream.once('end', finalize);
contentStream.once('error', err => callback(err));
localStream = this._getStream(this.content);
localStream.pipe(contentStream);
}
else {
// anything that is not QP or Base54 passes as-is
localStream = this._getStream(this.content);
localStream.pipe(outputStream, {
end: false
});
localStream.once('end', finalize);
}
localStream.once('error', err => callback(err));
};
if (this.content._resolve) {
const chunks = [];
let chunklen = 0;
let returned = false;
const sourceStream = this._getStream(this.content);
sourceStream.on('error', err => {
if (returned) {
return;
}
returned = true;
callback(err);
});
sourceStream.on('readable', () => {
let chunk;
while ((chunk = sourceStream.read()) !== null) {
chunks.push(chunk);
chunklen += chunk.length;
}
});
sourceStream.on('end', () => {
if (returned) {
return;
}
returned = true;
this.content._resolve = false;
this.content._resolvedValue = Buffer.concat(chunks, chunklen);
setImmediate(createStream);
});
}
else {
setImmediate(createStream);
}
if (aborted()) {
return;
}
return setImmediate(finalize);
if (!this.content) {
return setImmediate(finalize);
}
const createStream = () => {
if (aborted()) {
return;
}
const contentError = this._takeStreamContent(this.content);
if (contentError) {
return callback(contentError);
}
const localStream = this._getStream(this.content);
if (['quoted-printable', 'base64'].includes(transferEncoding)) {
const contentStream = transferEncoding === 'base64'
? new base64.Encoder(options)
: // outside of text a lone CR or LF is data, encoding it keeps it from being
// turned into a line break by a newline transform or the receiving side
new qp.Encoder(Object.assign({}, options, { binary: !/^text\//i.test(this.contentType || '') }));
readInto(localStream, contentStream);
contentStream.pipe(outputStream, {
end: false
});
// pipeline reports errors and tears both streams down. It calls back once the
// encoder took all of its input, the encoded output may still be waiting to
// be read, so the node is only done once the encoder's readable side ended
(0, node_stream_1.pipeline)(localStream, contentStream, err => err && callback(err));
(0, node_stream_1.finished)(contentStream, { writable: false }, err => (err ? callback(err) : finalize()));
}
else {
// anything that is not QP or Base54 passes as-is
readInto(localStream);
localStream.pipe(outputStream, {
end: false
});
(0, node_stream_1.finished)(localStream, { writable: false }, err => (err ? callback(err) : finalize()));
}
};
if (this.content._resolve) {
const sourceStream = this._getStream(this.content);
readInto(sourceStream);
shared.resolveStream(sourceStream, (err, value) => {
if (err) {
return callback(err);
}
if (returned) {
return;
}
this.content._resolve = false;
this.content._resolvedValue = value;
setImmediate(createStream);
});
}
else {
setImmediate(createStream);
}
};
if (this._raw) {
setImmediate(() => {
if (Object.prototype.toString.call(this._raw) === '[object Error]') {
// content is already errored
return callback(this._raw);
if (aborted()) {
return;
}
// remove default error handler (if set)
if (typeof this._raw.pipe === 'function') {
this._raw.removeListener('error', this._contentErrorHandler);
const rawError = this._takeStreamContent(this._raw);
if (rawError) {
return callback(rawError);
}
const raw = this._getStream(this._raw);
readInto(raw);
raw.pipe(outputStream, {
end: false
});
raw.on('error', err => outputStream.emit('error', err));
raw.on('end', finalize);
(0, node_stream_1.finished)(raw, { writable: false }, err => (err ? callback(err) : finalize()));
});
}
else {
@@ -955,11 +988,7 @@ class MimeNode {
if (this._raw && typeof this._raw.pipe === 'function') {
// pre-stream handler. might be triggered if a stream is set as content
// and 'error' fires before anything is done with this stream
this._contentErrorHandler = err => {
this._raw.removeListener('error', this._contentErrorHandler);
this._raw = err;
};
this._raw.once('error', this._contentErrorHandler);
shared.recordStreamErrors(this._raw);
}
return this;
}
@@ -985,6 +1014,37 @@ class MimeNode {
}
return false;
}
/**
* Destroys the content streams of this node and of every node below it
*
* @internal
*/
_destroyContentStreams() {
shared.destroyStream(this.content);
shared.destroyStream(this._raw);
for (const child of this.childNodes) {
child._destroyContentStreams();
}
}
/**
* Checks that a content value can still be read before the node streams it. A stream is
* refused once it errored, ended or was destroyed: piping it would either never finish or
* produce an empty body without any error
*
* @param content Node content or raw value
* @returns The error to stop with, or null when the content can be read
* @internal
*/
_takeStreamContent(content) {
if (Object.prototype.toString.call(content) === '[object Error]') {
return content;
}
if (!content || typeof content.pipe !== 'function' || content._resolvedValue) {
// the value of a resolved stream is read from the buffered copy
return null;
}
return shared.unreadableStreamError(content);
}
/**
* Detects and returns handle to a stream related with the content.
*