Compare commits

..
1 Commits
Author SHA1 Message Date
dependabot[bot] 7776e50e92 Bump @typescript-eslint/eslint-plugin from 8.62.0 to 8.70.1
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.62.0 to 8.70.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.70.1/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.64.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-25 22:28:52 +00:00
5 changed files with 444 additions and 1106 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: undici name: undici
version: 6.29.0 version: 6.28.0
type: npm type: npm
summary: An HTTP/1.1 client, written from scratch for Node.js summary: An HTTP/1.1 client, written from scratch for Node.js
homepage: https://undici.nodejs.org homepage: https://undici.nodejs.org
+186 -452
View File
@@ -15982,77 +15982,11 @@ class Request {
} }
} }
/** onUpgrade (statusCode, headers, socket) {
* @param {number|null} statusCode
* @param {Buffer[]|null} headers
* @param {import('node:stream').Duplex} socket
* @param {string} [statusText]
*/
onUpgrade (statusCode, headers, socket, statusText = '') {
this.onFinally()
assert(!this.aborted) assert(!this.aborted)
assert(!this.completed) assert(!this.completed)
if (statusCode !== null) { return this[kHandler].onUpgrade(statusCode, headers, socket)
this.#publishUpgradeHeaders(statusCode, headers, statusText)
}
const result = this[kHandler].onUpgrade(statusCode, headers, socket)
if (!this.aborted) {
this.completed = true
if (statusCode !== null) {
this.#publishUpgradeTrailers()
}
}
return result
}
/**
* @param {number} statusCode
* @param {import('node:http2').IncomingHttpHeaders} headers
* @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders
* @param {string} [statusText]
*/
onUpgradeResponse (statusCode, headers, parseHeaders, statusText = '') {
assert(!this.aborted)
assert(this.completed)
if (channels.headers.hasSubscribers) {
this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText)
}
this.#publishUpgradeTrailers()
}
/**
* @param {Error} error
*/
onUpgradeError (error) {
assert(!this.aborted)
assert(this.completed)
if (channels.error.hasSubscribers) {
channels.error.publish({ request: this, error })
}
}
/**
* @param {number} statusCode
* @param {Buffer[]} headers
* @param {string} statusText
*/
#publishUpgradeHeaders (statusCode, headers, statusText) {
if (channels.headers.hasSubscribers) {
channels.headers.publish({ request: this, response: { statusCode, headers, statusText } })
}
}
#publishUpgradeTrailers () {
if (channels.trailers.hasSubscribers) {
channels.trailers.publish({ request: this, trailers: [] })
}
} }
onComplete (trailers) { onComplete (trailers) {
@@ -17951,7 +17885,7 @@ class Parser {
} }
onUpgrade (head) { onUpgrade (head) {
const { upgrade, client, socket, headers, statusCode, statusText } = this const { upgrade, client, socket, headers, statusCode } = this
assert(upgrade) assert(upgrade)
assert(client[kSocket] === socket) assert(client[kSocket] === socket)
@@ -17986,10 +17920,9 @@ class Parser {
client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade')) client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade'))
try { try {
request.onUpgrade(statusCode, headers, socket, statusText) request.onUpgrade(statusCode, headers, socket)
} catch (error) { } catch (err) {
util.errorRequest(client, request, error) util.destroy(socket, err)
util.destroy(socket, error)
} }
client[kResume]() client[kResume]()
@@ -18396,7 +18329,7 @@ async function connectH1 (client, socket) {
function clearIdleSocketValidation (socket) { function clearIdleSocketValidation (socket) {
if (socket[kIdleSocketValidationTimeout]) { if (socket[kIdleSocketValidationTimeout]) {
clearImmediate(socket[kIdleSocketValidationTimeout]) clearTimeout(socket[kIdleSocketValidationTimeout])
socket[kIdleSocketValidationTimeout] = null socket[kIdleSocketValidationTimeout] = null
} }
@@ -18405,23 +18338,15 @@ function clearIdleSocketValidation (socket) {
function scheduleIdleSocketValidation (client, socket) { function scheduleIdleSocketValidation (client, socket) {
socket[kIdleSocketValidation] = 1 socket[kIdleSocketValidation] = 1
// Yield to the check phase (after poll) so unsolicited bytes / FIN / RST socket[kIdleSocketValidationTimeout] = setTimeout(() => {
// already pending on this idle keep-alive socket are processed before the
// next request is written (GHSA-35p6-xmwp-9g52).
//
// setTimeout(0) pays Node's ~1ms timer floor on every sequential reuse
// (#5493). setImmediate avoids that, but an *unref'd* Immediate lets poll
// block for ~500ms when the event loop is otherwise idle (#5600 / #5606).
// A ref'd Immediate both keeps the pending request alive and makes poll
// return immediately — the hybrid those issues asked for.
socket[kIdleSocketValidationTimeout] = setImmediate(() => {
socket[kIdleSocketValidationTimeout] = null socket[kIdleSocketValidationTimeout] = null
socket[kIdleSocketValidation] = 2 socket[kIdleSocketValidation] = 2
if (client[kSocket] === socket && !socket.destroyed) { if (client[kSocket] === socket && !socket.destroyed) {
client[kResume]() client[kResume]()
} }
}) }, 0)
socket[kIdleSocketValidationTimeout].unref?.()
} }
/** /**
@@ -18570,22 +18495,12 @@ function writeH1 (client, request) {
const socket = client[kSocket] const socket = client[kSocket]
clearIdleSocketValidation(socket) clearIdleSocketValidation(socket)
/** const abort = (err) => {
* @param {Error} [error] if (request.aborted || request.completed) {
*/
const abort = (error) => {
if (request.aborted) {
return return
} }
if (request.completed) { util.errorRequest(client, request, err || new RequestAbortedError())
if (request.upgrade || request.method === 'CONNECT') {
util.destroy(socket, new InformationalError('aborted'))
}
return
}
util.errorRequest(client, request, error || new RequestAbortedError())
util.destroy(body) util.destroy(body)
util.destroy(socket, new InformationalError('aborted')) util.destroy(socket, new InformationalError('aborted'))
@@ -19042,7 +18957,6 @@ module.exports = connectH1
const assert = __nccwpck_require__(4589) const assert = __nccwpck_require__(4589)
const { errorMonitor } = __nccwpck_require__(8474)
const { pipeline } = __nccwpck_require__(7075) const { pipeline } = __nccwpck_require__(7075)
const util = __nccwpck_require__(3440) const util = __nccwpck_require__(3440)
const { const {
@@ -19119,15 +19033,6 @@ function parseH2Headers (headers) {
return result return result
} }
/**
* @param {import('node:http2').IncomingHttpHeaders} headers
* @returns {Buffer[]}
*/
function parseH2ResponseHeaders (headers) {
const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers
return parseH2Headers(realHeaders)
}
async function connectH2 (client, socket) { async function connectH2 (client, socket) {
client[kSocket] = socket client[kSocket] = socket
@@ -19348,32 +19253,22 @@ function writeH2 (client, request) {
headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ''}` headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ''}`
headers[HTTP2_HEADER_METHOD] = method headers[HTTP2_HEADER_METHOD] = method
/** const abort = (err) => {
* @param {Error} [error] if (request.aborted || request.completed) {
*/
const abort = (error) => {
if (request.aborted) {
return return
} }
if (request.completed) { err = err || new RequestAbortedError()
if (method === 'CONNECT' && stream != null) {
util.destroy(stream, error || new RequestAbortedError())
}
return
}
error = error || new RequestAbortedError() util.errorRequest(client, request, err)
util.errorRequest(client, request, error)
if (stream != null) { if (stream != null) {
util.destroy(stream, error) util.destroy(stream, err)
} }
// We do not destroy the socket as we can continue using the session // We do not destroy the socket as we can continue using the session
// the stream get's destroyed and the session remains to create new streams // the stream get's destroyed and the session remains to create new streams
util.destroy(body, error) util.destroy(body, err)
client[kQueue][client[kRunningIdx]++] = null client[kQueue][client[kRunningIdx]++] = null
client[kResume]() client[kResume]()
} }
@@ -19392,57 +19287,25 @@ function writeH2 (client, request) {
if (method === 'CONNECT') { if (method === 'CONNECT') {
session.ref() session.ref()
// We are already connected, streams are pending, first request
// will create a new stream. We trigger a request to create the stream and wait until
// `ready` event is triggered
// We disabled endStream to allow the user to write to the stream // We disabled endStream to allow the user to write to the stream
stream = session.request(headers, { endStream: false, signal }) stream = session.request(headers, { endStream: false, signal })
let upgradeResponseFinished = false
/** if (stream.id && !stream.pending) {
* @param {import('node:http2').IncomingHttpHeaders} headers request.onUpgrade(null, null, stream)
*/ ++session[kOpenStreams]
const onResponse = (headers) => {
upgradeResponseFinished = true
stream.off(errorMonitor, onUpgradeError)
request.onUpgradeResponse(Number(headers[HTTP2_HEADER_STATUS]), headers, parseH2ResponseHeaders)
}
/**
* @param {Error} error
*/
const onUpgradeError = (error) => {
upgradeResponseFinished = true
stream.off('response', onResponse)
request.onUpgradeError(error)
}
const onReady = () => {
try {
request.onUpgrade(null, null, stream)
} catch (error) {
stream.off('response', onResponse)
abort(error)
return
}
if (request.aborted) {
return
}
stream.off('error', abort)
stream.once(errorMonitor, onUpgradeError)
client[kQueue][client[kRunningIdx]++] = null client[kQueue][client[kRunningIdx]++] = null
} else {
stream.once('ready', () => {
request.onUpgrade(null, null, stream)
++session[kOpenStreams]
client[kQueue][client[kRunningIdx]++] = null
})
} }
stream.once('response', onResponse)
stream.once('error', abort)
++session[kOpenStreams]
onReady()
stream.once('close', () => { stream.once('close', () => {
if (!upgradeResponseFinished && request.completed) {
stream.off('response', onResponse)
stream.off(errorMonitor, onUpgradeError)
request.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`))
}
session[kOpenStreams] -= 1 session[kOpenStreams] -= 1
if (session[kOpenStreams] === 0) session.unref() if (session[kOpenStreams] === 0) session.unref()
}) })
@@ -22141,7 +22004,6 @@ class RetryHandler {
this.end = null this.end = null
this.etag = null this.etag = null
this.resume = null this.resume = null
this.headersSent = false
// Handle possible onConnect duplication // Handle possible onConnect duplication
this.handler.onConnect(reason => { this.handler.onConnect(reason => {
@@ -22154,20 +22016,6 @@ class RetryHandler {
}) })
} }
checkpointResponseEnd (headers, resume) {
if (this.end == null && this.opts.method !== 'HEAD') {
const contentLength = headers['content-length']
this.end = contentLength != null ? Number(contentLength) - 1 : null
assert(
this.end == null || Number.isFinite(this.end),
'invalid content-length'
)
}
this.resume = this.end != null ? resume : null
}
onRequestSent () { onRequestSent () {
if (this.handler.onRequestSent) { if (this.handler.onRequestSent) {
this.handler.onRequestSent() this.handler.onRequestSent()
@@ -22256,12 +22104,7 @@ class RetryHandler {
this.retryCount += 1 this.retryCount += 1
if (statusCode >= 300) { if (statusCode >= 300) {
// Only expose a response if no earlier attempt has reached the caller. if (this.retryOpts.statusCodes.includes(statusCode) === false) {
// Otherwise abort this attempt so the error settles the existing body
// instead of replacing it with a new response.
if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) {
this.headersSent = true
this.checkpointResponseEnd(headers, resume)
return this.handler.onHeaders( return this.handler.onHeaders(
statusCode, statusCode,
rawHeaders, rawHeaders,
@@ -22330,15 +22173,8 @@ class RetryHandler {
const { start, size, end = size - 1 } = contentRange const { start, size, end = size - 1 } = contentRange
if (this.start !== start || (this.end != null && this.end !== end)) { assert(this.start === start, 'content-range mismatch')
this.abort( assert(this.end == null || this.end === end, 'content-range mismatch')
new RequestRetryError('Content-Range mismatch', statusCode, {
headers,
data: { count: this.retryCount }
})
)
return false
}
this.resume = resume this.resume = resume
return true return true
@@ -22350,7 +22186,6 @@ class RetryHandler {
const range = parseRangeHeader(headers['content-range']) const range = parseRangeHeader(headers['content-range'])
if (range == null) { if (range == null) {
this.headersSent = true
return this.handler.onHeaders( return this.handler.onHeaders(
statusCode, statusCode,
rawHeaders, rawHeaders,
@@ -22389,7 +22224,6 @@ class RetryHandler {
) )
this.resume = resume this.resume = resume
this.headersSent = true
this.etag = headers.etag != null ? headers.etag : null this.etag = headers.etag != null ? headers.etag : null
// Weak etags are not useful for comparison nor cache // Weak etags are not useful for comparison nor cache
@@ -22429,7 +22263,7 @@ class RetryHandler {
} }
onError (err) { onError (err) {
if (this.aborted || isDisturbed(this.opts.body) || (this.headersSent && this.resume == null)) { if (this.aborted || isDisturbed(this.opts.body)) {
return this.handler.onError(err) return this.handler.onError(err)
} }
@@ -26887,49 +26721,6 @@ const COLON = 0x3A
*/ */
const SPACE = 0x20 const SPACE = 0x20
const DATA = Buffer.from('data')
const EVENT = Buffer.from('event')
const ID = Buffer.from('id')
const RETRY = Buffer.from('retry')
function isASCIINumberBytes (buffer, start) {
if (start >= buffer.length) {
return false
}
for (let i = start; i < buffer.length; i++) {
if (buffer[i] < 0x30 || buffer[i] > 0x39) {
return false
}
}
return true
}
function isValidLastEventIdBytes (buffer, start) {
for (let i = start; i < buffer.length; i++) {
if (buffer[i] === 0x00) {
return false
}
}
return true
}
function isFieldName (line, length, field) {
if (length !== field.length) {
return false
}
for (let i = 0; i < length; i++) {
if (line[i] !== field[i]) {
return false
}
}
return true
}
/** /**
* @typedef {object} EventSourceStreamEvent * @typedef {object} EventSourceStreamEvent
* @type {object} * @type {object}
@@ -26970,14 +26761,11 @@ class EventSourceStream extends Transform {
eventEndCheck = false eventEndCheck = false
/** /**
* @type {Buffer[]} * @type {Buffer}
*/ */
chunks = [] buffer = null
chunkIndex = 0
pos = 0 pos = 0
lineChunkIndex = 0
linePos = 0
event = { event = {
data: undefined, data: undefined,
@@ -27016,20 +26804,92 @@ class EventSourceStream extends Transform {
return return
} }
this.chunks.push(chunk) // Cache the chunk in the buffer, as the data might not be complete while
// processing it
// TODO: Investigate if there is a more performant way to handle
// incoming chunks
// see: https://github.com/nodejs/undici/issues/2630
if (this.buffer) {
this.buffer = Buffer.concat([this.buffer, chunk])
} else {
this.buffer = chunk
}
// Strip leading byte-order-mark if we opened the stream and started // Strip leading byte-order-mark if we opened the stream and started
// the processing of the incoming data // the processing of the incoming data
if (this.checkBOM) { if (this.checkBOM) {
if (this.handleBOM()) { switch (this.buffer.length) {
callback() case 1:
return // Check if the first byte is the same as the first byte of the BOM
if (this.buffer[0] === BOM[0]) {
// If it is, we need to wait for more data
callback()
return
}
// Set the checkBOM flag to false as we don't need to check for the
// BOM anymore
this.checkBOM = false
// The buffer only contains one byte so we need to wait for more data
callback()
return
case 2:
// Check if the first two bytes are the same as the first two bytes
// of the BOM
if (
this.buffer[0] === BOM[0] &&
this.buffer[1] === BOM[1]
) {
// If it is, we need to wait for more data, because the third byte
// is needed to determine if it is the BOM or not
callback()
return
}
// Set the checkBOM flag to false as we don't need to check for the
// BOM anymore
this.checkBOM = false
break
case 3:
// Check if the first three bytes are the same as the first three
// bytes of the BOM
if (
this.buffer[0] === BOM[0] &&
this.buffer[1] === BOM[1] &&
this.buffer[2] === BOM[2]
) {
// If it is, we can drop the buffered data, as it is only the BOM
this.buffer = Buffer.alloc(0)
// Set the checkBOM flag to false as we don't need to check for the
// BOM anymore
this.checkBOM = false
// Await more data
callback()
return
}
// If it is not the BOM, we can start processing the data
this.checkBOM = false
break
default:
// The buffer is longer than 3 bytes, so we can drop the BOM if it is
// present
if (
this.buffer[0] === BOM[0] &&
this.buffer[1] === BOM[1] &&
this.buffer[2] === BOM[2]
) {
// Remove the BOM from the buffer
this.buffer = this.buffer.subarray(3)
}
// Set the checkBOM flag to false as we don't need to check for the
this.checkBOM = false
break
} }
} }
while (this.hasCurrentByte()) { while (this.pos < this.buffer.length) {
const byte = this.currentByte()
// If the previous line ended with an end-of-line, we need to check // If the previous line ended with an end-of-line, we need to check
// if the next character is also an end-of-line. // if the next character is also an end-of-line.
if (this.eventEndCheck) { if (this.eventEndCheck) {
@@ -27042,9 +26902,10 @@ class EventSourceStream extends Transform {
if (this.crlfCheck) { if (this.crlfCheck) {
// If the current character is a line feed, we can remove it // If the current character is a line feed, we can remove it
// from the buffer and reset the crlfCheck flag // from the buffer and reset the crlfCheck flag
if (byte === LF) { if (this.buffer[this.pos] === LF) {
this.buffer = this.buffer.subarray(this.pos + 1)
this.pos = 0
this.crlfCheck = false this.crlfCheck = false
this.consumeCurrentByte()
// It is possible that the line feed is not the end of the // It is possible that the line feed is not the end of the
// event. We need to check if the next character is an // event. We need to check if the next character is an
@@ -27060,17 +26921,19 @@ class EventSourceStream extends Transform {
this.crlfCheck = false this.crlfCheck = false
} }
if (byte === LF || byte === CR) { if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
// If the current character is a carriage return, we need to // If the current character is a carriage return, we need to
// set the crlfCheck flag to true, as we need to check if the // set the crlfCheck flag to true, as we need to check if the
// next character is a line feed so we can remove it from the // next character is a line feed so we can remove it from the
// buffer // buffer
if (byte === CR) { if (this.buffer[this.pos] === CR) {
this.crlfCheck = true this.crlfCheck = true
} }
this.consumeCurrentByte() this.buffer = this.buffer.subarray(this.pos + 1)
if (this.hasPendingEvent()) { this.pos = 0
if (
this.event.data !== undefined || this.event.event || this.event.id || this.event.retry) {
this.processEvent(this.event) this.processEvent(this.event)
} }
this.clearEvent() this.clearEvent()
@@ -27084,18 +26947,22 @@ class EventSourceStream extends Transform {
// If the current character is an end-of-line, we can process the // If the current character is an end-of-line, we can process the
// line // line
if (byte === LF || byte === CR) { if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
// If the current character is a carriage return, we need to // If the current character is a carriage return, we need to
// set the crlfCheck flag to true, as we need to check if the // set the crlfCheck flag to true, as we need to check if the
// next character is a line feed // next character is a line feed
if (byte === CR) { if (this.buffer[this.pos] === CR) {
this.crlfCheck = true this.crlfCheck = true
} }
// In any case, we can process the line as we reached an // In any case, we can process the line as we reached an
// end-of-line character // end-of-line character
this.parseLine(this.readLine(), this.event) this.parseLine(this.buffer.subarray(0, this.pos), this.event)
this.consumeCurrentByte()
// Remove the processed line from the buffer
this.buffer = this.buffer.subarray(this.pos + 1)
// Reset the position as we removed the processed line from the buffer
this.pos = 0
// A line was processed and this could be the end of the event. We need // A line was processed and this could be the end of the event. We need
// to check if the next line is empty to determine if the event is // to check if the next line is empty to determine if the event is
// finished. // finished.
@@ -27103,7 +26970,7 @@ class EventSourceStream extends Transform {
continue continue
} }
this.advanceCursor() this.pos++
} }
callback() callback()
@@ -27128,53 +26995,64 @@ class EventSourceStream extends Transform {
return return
} }
let fieldLength = line.length let field = ''
let valueStart = line.length let value = ''
// If the line contains a U+003A COLON character (:) // If the line contains a U+003A COLON character (:)
if (colonPosition !== -1) { if (colonPosition !== -1) {
fieldLength = colonPosition // Collect the characters on the line before the first U+003A COLON
// character (:), and let field be that string.
// TODO: Investigate if there is a more performant way to extract the
// field
// see: https://github.com/nodejs/undici/issues/2630
field = line.subarray(0, colonPosition).toString('utf8')
// Collect the characters on the line after the first U+003A COLON // Collect the characters on the line after the first U+003A COLON
// character (:), and let value be that string. // character (:), and let value be that string.
// If value starts with a U+0020 SPACE character, remove it from value. // If value starts with a U+0020 SPACE character, remove it from value.
valueStart = colonPosition + 1 let valueStart = colonPosition + 1
if (line[valueStart] === SPACE) { if (line[valueStart] === SPACE) {
++valueStart ++valueStart
} }
// TODO: Investigate if there is a more performant way to extract the
// value
// see: https://github.com/nodejs/undici/issues/2630
value = line.subarray(valueStart).toString('utf8')
// Otherwise, the string is not empty but does not contain a U+003A COLON
// character (:)
} else {
// Process the field using the steps described below, using the whole
// line as the field name, and the empty string as the field value.
field = line.toString('utf8')
value = ''
} }
if (isFieldName(line, fieldLength, DATA)) { // Modify the event with the field name and value. The value is also
const value = line.toString('utf8', valueStart) // decoded as UTF-8
switch (field) {
if (event.data === undefined) { case 'data':
event.data = value if (event[field] === undefined) {
} else { event[field] = value
event.data += `\n${value}` } else {
} event[field] += `\n${value}`
return }
} break
case 'retry':
if (isFieldName(line, fieldLength, RETRY)) { if (isASCIINumber(value)) {
if (isASCIINumberBytes(line, valueStart)) { event[field] = value
event.retry = line.toString('utf8', valueStart) }
} break
return case 'id':
} if (isValidLastEventId(value)) {
event[field] = value
if (isFieldName(line, fieldLength, ID)) { }
if (isValidLastEventIdBytes(line, valueStart)) { break
event.id = line.toString('utf8', valueStart) case 'event':
} if (value.length > 0) {
return event[field] = value
} }
break
if (isFieldName(line, fieldLength, EVENT)) {
const value = line.toString('utf8', valueStart)
if (value.length > 0) {
event.event = value
}
} }
} }
@@ -27204,152 +27082,13 @@ class EventSourceStream extends Transform {
} }
clearEvent () { clearEvent () {
this.event.data = undefined this.event = {
this.event.event = undefined data: undefined,
this.event.id = undefined event: undefined,
this.event.retry = undefined id: undefined,
} retry: undefined
hasPendingEvent () {
return this.event.data !== undefined ||
this.event.event !== undefined ||
this.event.id !== undefined ||
this.event.retry !== undefined
}
hasCurrentByte () {
return this.chunkIndex < this.chunks.length &&
this.pos < this.chunks[this.chunkIndex].length
}
currentByte () {
return this.chunks[this.chunkIndex][this.pos]
}
consumeCurrentByte () {
this.advanceCursor()
this.syncLineStartToCursor()
}
advanceCursor () {
this.pos++
while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) {
this.chunkIndex++
this.pos = 0
} }
} }
syncLineStartToCursor () {
this.lineChunkIndex = this.chunkIndex
this.linePos = this.pos
this.dropConsumedChunks()
}
dropConsumedChunks () {
while (this.lineChunkIndex > 0) {
this.chunks.shift()
this.lineChunkIndex--
this.chunkIndex--
}
if (this.chunkIndex === this.chunks.length) {
this.chunks.length = 0
this.chunkIndex = 0
this.pos = 0
this.lineChunkIndex = 0
this.linePos = 0
}
}
readLine () {
if (this.lineChunkIndex === this.chunkIndex) {
return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos)
}
const chunks = []
let length = 0
for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) {
const chunk = this.chunks[i]
const start = i === this.lineChunkIndex ? this.linePos : 0
const end = i === this.chunkIndex ? this.pos : chunk.length
const slice = chunk.subarray(start, end)
length += slice.length
chunks.push(slice)
}
return Buffer.concat(chunks, length)
}
peekBufferedByte (offset) {
let chunkIndex = this.lineChunkIndex
let pos = this.linePos
while (chunkIndex < this.chunks.length) {
const chunk = this.chunks[chunkIndex]
const remaining = chunk.length - pos
if (offset < remaining) {
return chunk[pos + offset]
}
offset -= remaining
chunkIndex++
pos = 0
}
}
discardLeadingBytes (count) {
while (count > 0 && this.lineChunkIndex < this.chunks.length) {
const chunk = this.chunks[this.lineChunkIndex]
const remaining = chunk.length - this.linePos
if (count < remaining) {
this.linePos += count
count = 0
} else {
count -= remaining
this.lineChunkIndex++
this.linePos = 0
}
}
this.chunkIndex = this.lineChunkIndex
this.pos = this.linePos
this.dropConsumedChunks()
}
handleBOM () {
const first = this.peekBufferedByte(0)
const second = this.peekBufferedByte(1)
const third = this.peekBufferedByte(2)
if (second === undefined) {
if (first === BOM[0]) {
return true
}
this.checkBOM = false
return true
}
if (third === undefined) {
if (first === BOM[0] && second === BOM[1]) {
return true
}
this.checkBOM = false
return false
}
if (first === BOM[0] && second === BOM[1] && third === BOM[2]) {
this.discardLeadingBytes(3)
}
this.checkBOM = false
return !this.hasCurrentByte()
}
} }
module.exports = { module.exports = {
@@ -38617,7 +38356,7 @@ function establishWebSocketConnection (url, protocols, client, ws, onEstablish,
// is specified, the server needs to include the same field and one of // is specified, the server needs to include the same field and one of
// the selected subprotocol values in its response for the connection to // the selected subprotocol values in its response for the connection to
// be established. // be established.
if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { if (!requestProtocols.includes(secProtocol)) {
failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.') failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.')
return return
} }
@@ -39378,12 +39117,7 @@ class PerMessageDeflate {
if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) {
callback(new MessageSizeExceededError()) callback(new MessageSizeExceededError())
// The inflater may still hold buffered input that can emit a late
// zlib error. Remove the data listener, then deterministically stop
// the stream so a subsequent 'error' cannot fire without a listener
// (which would terminate the process as an unhandled error event).
this.#inflate.removeAllListeners() this.#inflate.removeAllListeners()
this.#inflate.destroy()
this.#inflate = null this.#inflate = null
return return
} }
+186 -452
View File
@@ -15982,77 +15982,11 @@ class Request {
} }
} }
/** onUpgrade (statusCode, headers, socket) {
* @param {number|null} statusCode
* @param {Buffer[]|null} headers
* @param {import('node:stream').Duplex} socket
* @param {string} [statusText]
*/
onUpgrade (statusCode, headers, socket, statusText = '') {
this.onFinally()
assert(!this.aborted) assert(!this.aborted)
assert(!this.completed) assert(!this.completed)
if (statusCode !== null) { return this[kHandler].onUpgrade(statusCode, headers, socket)
this.#publishUpgradeHeaders(statusCode, headers, statusText)
}
const result = this[kHandler].onUpgrade(statusCode, headers, socket)
if (!this.aborted) {
this.completed = true
if (statusCode !== null) {
this.#publishUpgradeTrailers()
}
}
return result
}
/**
* @param {number} statusCode
* @param {import('node:http2').IncomingHttpHeaders} headers
* @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders
* @param {string} [statusText]
*/
onUpgradeResponse (statusCode, headers, parseHeaders, statusText = '') {
assert(!this.aborted)
assert(this.completed)
if (channels.headers.hasSubscribers) {
this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText)
}
this.#publishUpgradeTrailers()
}
/**
* @param {Error} error
*/
onUpgradeError (error) {
assert(!this.aborted)
assert(this.completed)
if (channels.error.hasSubscribers) {
channels.error.publish({ request: this, error })
}
}
/**
* @param {number} statusCode
* @param {Buffer[]} headers
* @param {string} statusText
*/
#publishUpgradeHeaders (statusCode, headers, statusText) {
if (channels.headers.hasSubscribers) {
channels.headers.publish({ request: this, response: { statusCode, headers, statusText } })
}
}
#publishUpgradeTrailers () {
if (channels.trailers.hasSubscribers) {
channels.trailers.publish({ request: this, trailers: [] })
}
} }
onComplete (trailers) { onComplete (trailers) {
@@ -17951,7 +17885,7 @@ class Parser {
} }
onUpgrade (head) { onUpgrade (head) {
const { upgrade, client, socket, headers, statusCode, statusText } = this const { upgrade, client, socket, headers, statusCode } = this
assert(upgrade) assert(upgrade)
assert(client[kSocket] === socket) assert(client[kSocket] === socket)
@@ -17986,10 +17920,9 @@ class Parser {
client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade')) client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade'))
try { try {
request.onUpgrade(statusCode, headers, socket, statusText) request.onUpgrade(statusCode, headers, socket)
} catch (error) { } catch (err) {
util.errorRequest(client, request, error) util.destroy(socket, err)
util.destroy(socket, error)
} }
client[kResume]() client[kResume]()
@@ -18396,7 +18329,7 @@ async function connectH1 (client, socket) {
function clearIdleSocketValidation (socket) { function clearIdleSocketValidation (socket) {
if (socket[kIdleSocketValidationTimeout]) { if (socket[kIdleSocketValidationTimeout]) {
clearImmediate(socket[kIdleSocketValidationTimeout]) clearTimeout(socket[kIdleSocketValidationTimeout])
socket[kIdleSocketValidationTimeout] = null socket[kIdleSocketValidationTimeout] = null
} }
@@ -18405,23 +18338,15 @@ function clearIdleSocketValidation (socket) {
function scheduleIdleSocketValidation (client, socket) { function scheduleIdleSocketValidation (client, socket) {
socket[kIdleSocketValidation] = 1 socket[kIdleSocketValidation] = 1
// Yield to the check phase (after poll) so unsolicited bytes / FIN / RST socket[kIdleSocketValidationTimeout] = setTimeout(() => {
// already pending on this idle keep-alive socket are processed before the
// next request is written (GHSA-35p6-xmwp-9g52).
//
// setTimeout(0) pays Node's ~1ms timer floor on every sequential reuse
// (#5493). setImmediate avoids that, but an *unref'd* Immediate lets poll
// block for ~500ms when the event loop is otherwise idle (#5600 / #5606).
// A ref'd Immediate both keeps the pending request alive and makes poll
// return immediately — the hybrid those issues asked for.
socket[kIdleSocketValidationTimeout] = setImmediate(() => {
socket[kIdleSocketValidationTimeout] = null socket[kIdleSocketValidationTimeout] = null
socket[kIdleSocketValidation] = 2 socket[kIdleSocketValidation] = 2
if (client[kSocket] === socket && !socket.destroyed) { if (client[kSocket] === socket && !socket.destroyed) {
client[kResume]() client[kResume]()
} }
}) }, 0)
socket[kIdleSocketValidationTimeout].unref?.()
} }
/** /**
@@ -18570,22 +18495,12 @@ function writeH1 (client, request) {
const socket = client[kSocket] const socket = client[kSocket]
clearIdleSocketValidation(socket) clearIdleSocketValidation(socket)
/** const abort = (err) => {
* @param {Error} [error] if (request.aborted || request.completed) {
*/
const abort = (error) => {
if (request.aborted) {
return return
} }
if (request.completed) { util.errorRequest(client, request, err || new RequestAbortedError())
if (request.upgrade || request.method === 'CONNECT') {
util.destroy(socket, new InformationalError('aborted'))
}
return
}
util.errorRequest(client, request, error || new RequestAbortedError())
util.destroy(body) util.destroy(body)
util.destroy(socket, new InformationalError('aborted')) util.destroy(socket, new InformationalError('aborted'))
@@ -19042,7 +18957,6 @@ module.exports = connectH1
const assert = __nccwpck_require__(4589) const assert = __nccwpck_require__(4589)
const { errorMonitor } = __nccwpck_require__(8474)
const { pipeline } = __nccwpck_require__(7075) const { pipeline } = __nccwpck_require__(7075)
const util = __nccwpck_require__(3440) const util = __nccwpck_require__(3440)
const { const {
@@ -19119,15 +19033,6 @@ function parseH2Headers (headers) {
return result return result
} }
/**
* @param {import('node:http2').IncomingHttpHeaders} headers
* @returns {Buffer[]}
*/
function parseH2ResponseHeaders (headers) {
const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers
return parseH2Headers(realHeaders)
}
async function connectH2 (client, socket) { async function connectH2 (client, socket) {
client[kSocket] = socket client[kSocket] = socket
@@ -19348,32 +19253,22 @@ function writeH2 (client, request) {
headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ''}` headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ''}`
headers[HTTP2_HEADER_METHOD] = method headers[HTTP2_HEADER_METHOD] = method
/** const abort = (err) => {
* @param {Error} [error] if (request.aborted || request.completed) {
*/
const abort = (error) => {
if (request.aborted) {
return return
} }
if (request.completed) { err = err || new RequestAbortedError()
if (method === 'CONNECT' && stream != null) {
util.destroy(stream, error || new RequestAbortedError())
}
return
}
error = error || new RequestAbortedError() util.errorRequest(client, request, err)
util.errorRequest(client, request, error)
if (stream != null) { if (stream != null) {
util.destroy(stream, error) util.destroy(stream, err)
} }
// We do not destroy the socket as we can continue using the session // We do not destroy the socket as we can continue using the session
// the stream get's destroyed and the session remains to create new streams // the stream get's destroyed and the session remains to create new streams
util.destroy(body, error) util.destroy(body, err)
client[kQueue][client[kRunningIdx]++] = null client[kQueue][client[kRunningIdx]++] = null
client[kResume]() client[kResume]()
} }
@@ -19392,57 +19287,25 @@ function writeH2 (client, request) {
if (method === 'CONNECT') { if (method === 'CONNECT') {
session.ref() session.ref()
// We are already connected, streams are pending, first request
// will create a new stream. We trigger a request to create the stream and wait until
// `ready` event is triggered
// We disabled endStream to allow the user to write to the stream // We disabled endStream to allow the user to write to the stream
stream = session.request(headers, { endStream: false, signal }) stream = session.request(headers, { endStream: false, signal })
let upgradeResponseFinished = false
/** if (stream.id && !stream.pending) {
* @param {import('node:http2').IncomingHttpHeaders} headers request.onUpgrade(null, null, stream)
*/ ++session[kOpenStreams]
const onResponse = (headers) => {
upgradeResponseFinished = true
stream.off(errorMonitor, onUpgradeError)
request.onUpgradeResponse(Number(headers[HTTP2_HEADER_STATUS]), headers, parseH2ResponseHeaders)
}
/**
* @param {Error} error
*/
const onUpgradeError = (error) => {
upgradeResponseFinished = true
stream.off('response', onResponse)
request.onUpgradeError(error)
}
const onReady = () => {
try {
request.onUpgrade(null, null, stream)
} catch (error) {
stream.off('response', onResponse)
abort(error)
return
}
if (request.aborted) {
return
}
stream.off('error', abort)
stream.once(errorMonitor, onUpgradeError)
client[kQueue][client[kRunningIdx]++] = null client[kQueue][client[kRunningIdx]++] = null
} else {
stream.once('ready', () => {
request.onUpgrade(null, null, stream)
++session[kOpenStreams]
client[kQueue][client[kRunningIdx]++] = null
})
} }
stream.once('response', onResponse)
stream.once('error', abort)
++session[kOpenStreams]
onReady()
stream.once('close', () => { stream.once('close', () => {
if (!upgradeResponseFinished && request.completed) {
stream.off('response', onResponse)
stream.off(errorMonitor, onUpgradeError)
request.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`))
}
session[kOpenStreams] -= 1 session[kOpenStreams] -= 1
if (session[kOpenStreams] === 0) session.unref() if (session[kOpenStreams] === 0) session.unref()
}) })
@@ -22141,7 +22004,6 @@ class RetryHandler {
this.end = null this.end = null
this.etag = null this.etag = null
this.resume = null this.resume = null
this.headersSent = false
// Handle possible onConnect duplication // Handle possible onConnect duplication
this.handler.onConnect(reason => { this.handler.onConnect(reason => {
@@ -22154,20 +22016,6 @@ class RetryHandler {
}) })
} }
checkpointResponseEnd (headers, resume) {
if (this.end == null && this.opts.method !== 'HEAD') {
const contentLength = headers['content-length']
this.end = contentLength != null ? Number(contentLength) - 1 : null
assert(
this.end == null || Number.isFinite(this.end),
'invalid content-length'
)
}
this.resume = this.end != null ? resume : null
}
onRequestSent () { onRequestSent () {
if (this.handler.onRequestSent) { if (this.handler.onRequestSent) {
this.handler.onRequestSent() this.handler.onRequestSent()
@@ -22256,12 +22104,7 @@ class RetryHandler {
this.retryCount += 1 this.retryCount += 1
if (statusCode >= 300) { if (statusCode >= 300) {
// Only expose a response if no earlier attempt has reached the caller. if (this.retryOpts.statusCodes.includes(statusCode) === false) {
// Otherwise abort this attempt so the error settles the existing body
// instead of replacing it with a new response.
if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) {
this.headersSent = true
this.checkpointResponseEnd(headers, resume)
return this.handler.onHeaders( return this.handler.onHeaders(
statusCode, statusCode,
rawHeaders, rawHeaders,
@@ -22330,15 +22173,8 @@ class RetryHandler {
const { start, size, end = size - 1 } = contentRange const { start, size, end = size - 1 } = contentRange
if (this.start !== start || (this.end != null && this.end !== end)) { assert(this.start === start, 'content-range mismatch')
this.abort( assert(this.end == null || this.end === end, 'content-range mismatch')
new RequestRetryError('Content-Range mismatch', statusCode, {
headers,
data: { count: this.retryCount }
})
)
return false
}
this.resume = resume this.resume = resume
return true return true
@@ -22350,7 +22186,6 @@ class RetryHandler {
const range = parseRangeHeader(headers['content-range']) const range = parseRangeHeader(headers['content-range'])
if (range == null) { if (range == null) {
this.headersSent = true
return this.handler.onHeaders( return this.handler.onHeaders(
statusCode, statusCode,
rawHeaders, rawHeaders,
@@ -22389,7 +22224,6 @@ class RetryHandler {
) )
this.resume = resume this.resume = resume
this.headersSent = true
this.etag = headers.etag != null ? headers.etag : null this.etag = headers.etag != null ? headers.etag : null
// Weak etags are not useful for comparison nor cache // Weak etags are not useful for comparison nor cache
@@ -22429,7 +22263,7 @@ class RetryHandler {
} }
onError (err) { onError (err) {
if (this.aborted || isDisturbed(this.opts.body) || (this.headersSent && this.resume == null)) { if (this.aborted || isDisturbed(this.opts.body)) {
return this.handler.onError(err) return this.handler.onError(err)
} }
@@ -26887,49 +26721,6 @@ const COLON = 0x3A
*/ */
const SPACE = 0x20 const SPACE = 0x20
const DATA = Buffer.from('data')
const EVENT = Buffer.from('event')
const ID = Buffer.from('id')
const RETRY = Buffer.from('retry')
function isASCIINumberBytes (buffer, start) {
if (start >= buffer.length) {
return false
}
for (let i = start; i < buffer.length; i++) {
if (buffer[i] < 0x30 || buffer[i] > 0x39) {
return false
}
}
return true
}
function isValidLastEventIdBytes (buffer, start) {
for (let i = start; i < buffer.length; i++) {
if (buffer[i] === 0x00) {
return false
}
}
return true
}
function isFieldName (line, length, field) {
if (length !== field.length) {
return false
}
for (let i = 0; i < length; i++) {
if (line[i] !== field[i]) {
return false
}
}
return true
}
/** /**
* @typedef {object} EventSourceStreamEvent * @typedef {object} EventSourceStreamEvent
* @type {object} * @type {object}
@@ -26970,14 +26761,11 @@ class EventSourceStream extends Transform {
eventEndCheck = false eventEndCheck = false
/** /**
* @type {Buffer[]} * @type {Buffer}
*/ */
chunks = [] buffer = null
chunkIndex = 0
pos = 0 pos = 0
lineChunkIndex = 0
linePos = 0
event = { event = {
data: undefined, data: undefined,
@@ -27016,20 +26804,92 @@ class EventSourceStream extends Transform {
return return
} }
this.chunks.push(chunk) // Cache the chunk in the buffer, as the data might not be complete while
// processing it
// TODO: Investigate if there is a more performant way to handle
// incoming chunks
// see: https://github.com/nodejs/undici/issues/2630
if (this.buffer) {
this.buffer = Buffer.concat([this.buffer, chunk])
} else {
this.buffer = chunk
}
// Strip leading byte-order-mark if we opened the stream and started // Strip leading byte-order-mark if we opened the stream and started
// the processing of the incoming data // the processing of the incoming data
if (this.checkBOM) { if (this.checkBOM) {
if (this.handleBOM()) { switch (this.buffer.length) {
callback() case 1:
return // Check if the first byte is the same as the first byte of the BOM
if (this.buffer[0] === BOM[0]) {
// If it is, we need to wait for more data
callback()
return
}
// Set the checkBOM flag to false as we don't need to check for the
// BOM anymore
this.checkBOM = false
// The buffer only contains one byte so we need to wait for more data
callback()
return
case 2:
// Check if the first two bytes are the same as the first two bytes
// of the BOM
if (
this.buffer[0] === BOM[0] &&
this.buffer[1] === BOM[1]
) {
// If it is, we need to wait for more data, because the third byte
// is needed to determine if it is the BOM or not
callback()
return
}
// Set the checkBOM flag to false as we don't need to check for the
// BOM anymore
this.checkBOM = false
break
case 3:
// Check if the first three bytes are the same as the first three
// bytes of the BOM
if (
this.buffer[0] === BOM[0] &&
this.buffer[1] === BOM[1] &&
this.buffer[2] === BOM[2]
) {
// If it is, we can drop the buffered data, as it is only the BOM
this.buffer = Buffer.alloc(0)
// Set the checkBOM flag to false as we don't need to check for the
// BOM anymore
this.checkBOM = false
// Await more data
callback()
return
}
// If it is not the BOM, we can start processing the data
this.checkBOM = false
break
default:
// The buffer is longer than 3 bytes, so we can drop the BOM if it is
// present
if (
this.buffer[0] === BOM[0] &&
this.buffer[1] === BOM[1] &&
this.buffer[2] === BOM[2]
) {
// Remove the BOM from the buffer
this.buffer = this.buffer.subarray(3)
}
// Set the checkBOM flag to false as we don't need to check for the
this.checkBOM = false
break
} }
} }
while (this.hasCurrentByte()) { while (this.pos < this.buffer.length) {
const byte = this.currentByte()
// If the previous line ended with an end-of-line, we need to check // If the previous line ended with an end-of-line, we need to check
// if the next character is also an end-of-line. // if the next character is also an end-of-line.
if (this.eventEndCheck) { if (this.eventEndCheck) {
@@ -27042,9 +26902,10 @@ class EventSourceStream extends Transform {
if (this.crlfCheck) { if (this.crlfCheck) {
// If the current character is a line feed, we can remove it // If the current character is a line feed, we can remove it
// from the buffer and reset the crlfCheck flag // from the buffer and reset the crlfCheck flag
if (byte === LF) { if (this.buffer[this.pos] === LF) {
this.buffer = this.buffer.subarray(this.pos + 1)
this.pos = 0
this.crlfCheck = false this.crlfCheck = false
this.consumeCurrentByte()
// It is possible that the line feed is not the end of the // It is possible that the line feed is not the end of the
// event. We need to check if the next character is an // event. We need to check if the next character is an
@@ -27060,17 +26921,19 @@ class EventSourceStream extends Transform {
this.crlfCheck = false this.crlfCheck = false
} }
if (byte === LF || byte === CR) { if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
// If the current character is a carriage return, we need to // If the current character is a carriage return, we need to
// set the crlfCheck flag to true, as we need to check if the // set the crlfCheck flag to true, as we need to check if the
// next character is a line feed so we can remove it from the // next character is a line feed so we can remove it from the
// buffer // buffer
if (byte === CR) { if (this.buffer[this.pos] === CR) {
this.crlfCheck = true this.crlfCheck = true
} }
this.consumeCurrentByte() this.buffer = this.buffer.subarray(this.pos + 1)
if (this.hasPendingEvent()) { this.pos = 0
if (
this.event.data !== undefined || this.event.event || this.event.id || this.event.retry) {
this.processEvent(this.event) this.processEvent(this.event)
} }
this.clearEvent() this.clearEvent()
@@ -27084,18 +26947,22 @@ class EventSourceStream extends Transform {
// If the current character is an end-of-line, we can process the // If the current character is an end-of-line, we can process the
// line // line
if (byte === LF || byte === CR) { if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
// If the current character is a carriage return, we need to // If the current character is a carriage return, we need to
// set the crlfCheck flag to true, as we need to check if the // set the crlfCheck flag to true, as we need to check if the
// next character is a line feed // next character is a line feed
if (byte === CR) { if (this.buffer[this.pos] === CR) {
this.crlfCheck = true this.crlfCheck = true
} }
// In any case, we can process the line as we reached an // In any case, we can process the line as we reached an
// end-of-line character // end-of-line character
this.parseLine(this.readLine(), this.event) this.parseLine(this.buffer.subarray(0, this.pos), this.event)
this.consumeCurrentByte()
// Remove the processed line from the buffer
this.buffer = this.buffer.subarray(this.pos + 1)
// Reset the position as we removed the processed line from the buffer
this.pos = 0
// A line was processed and this could be the end of the event. We need // A line was processed and this could be the end of the event. We need
// to check if the next line is empty to determine if the event is // to check if the next line is empty to determine if the event is
// finished. // finished.
@@ -27103,7 +26970,7 @@ class EventSourceStream extends Transform {
continue continue
} }
this.advanceCursor() this.pos++
} }
callback() callback()
@@ -27128,53 +26995,64 @@ class EventSourceStream extends Transform {
return return
} }
let fieldLength = line.length let field = ''
let valueStart = line.length let value = ''
// If the line contains a U+003A COLON character (:) // If the line contains a U+003A COLON character (:)
if (colonPosition !== -1) { if (colonPosition !== -1) {
fieldLength = colonPosition // Collect the characters on the line before the first U+003A COLON
// character (:), and let field be that string.
// TODO: Investigate if there is a more performant way to extract the
// field
// see: https://github.com/nodejs/undici/issues/2630
field = line.subarray(0, colonPosition).toString('utf8')
// Collect the characters on the line after the first U+003A COLON // Collect the characters on the line after the first U+003A COLON
// character (:), and let value be that string. // character (:), and let value be that string.
// If value starts with a U+0020 SPACE character, remove it from value. // If value starts with a U+0020 SPACE character, remove it from value.
valueStart = colonPosition + 1 let valueStart = colonPosition + 1
if (line[valueStart] === SPACE) { if (line[valueStart] === SPACE) {
++valueStart ++valueStart
} }
// TODO: Investigate if there is a more performant way to extract the
// value
// see: https://github.com/nodejs/undici/issues/2630
value = line.subarray(valueStart).toString('utf8')
// Otherwise, the string is not empty but does not contain a U+003A COLON
// character (:)
} else {
// Process the field using the steps described below, using the whole
// line as the field name, and the empty string as the field value.
field = line.toString('utf8')
value = ''
} }
if (isFieldName(line, fieldLength, DATA)) { // Modify the event with the field name and value. The value is also
const value = line.toString('utf8', valueStart) // decoded as UTF-8
switch (field) {
if (event.data === undefined) { case 'data':
event.data = value if (event[field] === undefined) {
} else { event[field] = value
event.data += `\n${value}` } else {
} event[field] += `\n${value}`
return }
} break
case 'retry':
if (isFieldName(line, fieldLength, RETRY)) { if (isASCIINumber(value)) {
if (isASCIINumberBytes(line, valueStart)) { event[field] = value
event.retry = line.toString('utf8', valueStart) }
} break
return case 'id':
} if (isValidLastEventId(value)) {
event[field] = value
if (isFieldName(line, fieldLength, ID)) { }
if (isValidLastEventIdBytes(line, valueStart)) { break
event.id = line.toString('utf8', valueStart) case 'event':
} if (value.length > 0) {
return event[field] = value
} }
break
if (isFieldName(line, fieldLength, EVENT)) {
const value = line.toString('utf8', valueStart)
if (value.length > 0) {
event.event = value
}
} }
} }
@@ -27204,152 +27082,13 @@ class EventSourceStream extends Transform {
} }
clearEvent () { clearEvent () {
this.event.data = undefined this.event = {
this.event.event = undefined data: undefined,
this.event.id = undefined event: undefined,
this.event.retry = undefined id: undefined,
} retry: undefined
hasPendingEvent () {
return this.event.data !== undefined ||
this.event.event !== undefined ||
this.event.id !== undefined ||
this.event.retry !== undefined
}
hasCurrentByte () {
return this.chunkIndex < this.chunks.length &&
this.pos < this.chunks[this.chunkIndex].length
}
currentByte () {
return this.chunks[this.chunkIndex][this.pos]
}
consumeCurrentByte () {
this.advanceCursor()
this.syncLineStartToCursor()
}
advanceCursor () {
this.pos++
while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) {
this.chunkIndex++
this.pos = 0
} }
} }
syncLineStartToCursor () {
this.lineChunkIndex = this.chunkIndex
this.linePos = this.pos
this.dropConsumedChunks()
}
dropConsumedChunks () {
while (this.lineChunkIndex > 0) {
this.chunks.shift()
this.lineChunkIndex--
this.chunkIndex--
}
if (this.chunkIndex === this.chunks.length) {
this.chunks.length = 0
this.chunkIndex = 0
this.pos = 0
this.lineChunkIndex = 0
this.linePos = 0
}
}
readLine () {
if (this.lineChunkIndex === this.chunkIndex) {
return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos)
}
const chunks = []
let length = 0
for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) {
const chunk = this.chunks[i]
const start = i === this.lineChunkIndex ? this.linePos : 0
const end = i === this.chunkIndex ? this.pos : chunk.length
const slice = chunk.subarray(start, end)
length += slice.length
chunks.push(slice)
}
return Buffer.concat(chunks, length)
}
peekBufferedByte (offset) {
let chunkIndex = this.lineChunkIndex
let pos = this.linePos
while (chunkIndex < this.chunks.length) {
const chunk = this.chunks[chunkIndex]
const remaining = chunk.length - pos
if (offset < remaining) {
return chunk[pos + offset]
}
offset -= remaining
chunkIndex++
pos = 0
}
}
discardLeadingBytes (count) {
while (count > 0 && this.lineChunkIndex < this.chunks.length) {
const chunk = this.chunks[this.lineChunkIndex]
const remaining = chunk.length - this.linePos
if (count < remaining) {
this.linePos += count
count = 0
} else {
count -= remaining
this.lineChunkIndex++
this.linePos = 0
}
}
this.chunkIndex = this.lineChunkIndex
this.pos = this.linePos
this.dropConsumedChunks()
}
handleBOM () {
const first = this.peekBufferedByte(0)
const second = this.peekBufferedByte(1)
const third = this.peekBufferedByte(2)
if (second === undefined) {
if (first === BOM[0]) {
return true
}
this.checkBOM = false
return true
}
if (third === undefined) {
if (first === BOM[0] && second === BOM[1]) {
return true
}
this.checkBOM = false
return false
}
if (first === BOM[0] && second === BOM[1] && third === BOM[2]) {
this.discardLeadingBytes(3)
}
this.checkBOM = false
return !this.hasCurrentByte()
}
} }
module.exports = { module.exports = {
@@ -38617,7 +38356,7 @@ function establishWebSocketConnection (url, protocols, client, ws, onEstablish,
// is specified, the server needs to include the same field and one of // is specified, the server needs to include the same field and one of
// the selected subprotocol values in its response for the connection to // the selected subprotocol values in its response for the connection to
// be established. // be established.
if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { if (!requestProtocols.includes(secProtocol)) {
failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.') failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.')
return return
} }
@@ -39378,12 +39117,7 @@ class PerMessageDeflate {
if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) {
callback(new MessageSizeExceededError()) callback(new MessageSizeExceededError())
// The inflater may still hold buffered input that can emit a late
// zlib error. Remove the data listener, then deterministically stop
// the stream so a subsequent 'error' cannot fire without a listener
// (which would terminate the process as an unhandled error event).
this.#inflate.removeAllListeners() this.#inflate.removeAllListeners()
this.#inflate.destroy()
this.#inflate = null this.#inflate = null
return return
} }
+68 -198
View File
@@ -23,8 +23,8 @@
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
"@jest/globals": "^30.4.1", "@jest/globals": "^30.4.1",
"@types/node": "^24.10.1", "@types/node": "^24.10.1",
"@types/semver": "^7.8.0", "@types/semver": "^7.7.0",
"@typescript-eslint/eslint-plugin": "^8.62.0", "@typescript-eslint/eslint-plugin": "^8.70.1",
"@typescript-eslint/parser": "^8.70.0", "@typescript-eslint/parser": "^8.70.0",
"@vercel/ncc": "^0.45.0", "@vercel/ncc": "^0.45.0",
"eslint": "^10.5.0", "eslint": "^10.5.0",
@@ -34,7 +34,7 @@
"globals": "^17.7.0", "globals": "^17.7.0",
"jest": "^30.4.2", "jest": "^30.4.2",
"prettier": "^3.8.4", "prettier": "^3.8.4",
"ts-jest": "^29.4.14", "ts-jest": "^29.4.11",
"typescript": "^6.0.3" "typescript": "^6.0.3"
}, },
"engines": { "engines": {
@@ -1791,9 +1791,9 @@
} }
}, },
"node_modules/@types/semver": { "node_modules/@types/semver": {
"version": "7.8.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -1822,17 +1822,17 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.62.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.70.1.tgz",
"integrity": "sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==", "integrity": "sha512-nDNrUQ/4ruSNYbu749TRY7cfrzPtoLHEXSNBI8aaNY32LlZCajixqRf3FqcKC4p5Cam4VOHYx/t+i5+nKXvrqA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.12.2", "@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.62.0", "@typescript-eslint/scope-manager": "8.70.1",
"@typescript-eslint/type-utils": "8.62.0", "@typescript-eslint/type-utils": "8.70.1",
"@typescript-eslint/utils": "8.62.0", "@typescript-eslint/utils": "8.70.1",
"@typescript-eslint/visitor-keys": "8.62.0", "@typescript-eslint/visitor-keys": "8.70.1",
"ignore": "^7.0.5", "ignore": "^7.0.5",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
"ts-api-utils": "^2.5.0" "ts-api-utils": "^2.5.0"
@@ -1845,22 +1845,22 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.62.0", "@typescript-eslint/parser": "^8.70.1",
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0" "typescript": ">=4.8.4 <6.1.0"
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.70.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.1.tgz",
"integrity": "sha512-zYvrmj9Yxd63UGaXw+kdt6A0F0s0qveJyuatIM77bYC2DE4pgmg7a50u8LR7PRtXd0x+h+Tl3eXabGm06SWd3Q==", "integrity": "sha512-nO974WLllwhSFWQXnMLj6nDGa8f0khKEz1JzpPJ1u7Vm/4X1X6ZHajpoknU4bb41vJyMB0HHVyS2GqdhWfIXZw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.70.0", "@typescript-eslint/scope-manager": "8.70.1",
"@typescript-eslint/types": "8.70.0", "@typescript-eslint/types": "8.70.1",
"@typescript-eslint/typescript-estree": "8.70.0", "@typescript-eslint/typescript-estree": "8.70.1",
"@typescript-eslint/visitor-keys": "8.70.0", "@typescript-eslint/visitor-keys": "8.70.1",
"debug": "^4.4.3" "debug": "^4.4.3"
}, },
"engines": { "engines": {
@@ -1875,145 +1875,15 @@
"typescript": ">=4.8.4 <6.1.0" "typescript": ">=4.8.4 <6.1.0"
} }
}, },
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/project-service": {
"version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.0.tgz",
"integrity": "sha512-hFHbTNqhU9G+2eKFXCBVb1tjFT/LceiJ4+HfLO4pTpDI0KHi6iajpcFFkaSQ9gXmCh7n82A0PthaayEdN6mspQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.70.0",
"@typescript-eslint/types": "^8.70.0",
"debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": {
"version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.0.tgz",
"integrity": "sha512-8nP3Kwh5hlgZ4FicGvmznAmJe8UL4sdU8tLukrPaMuQmDuk4Y8xYfzu/aYZW4xT2JCgc7H/TpDI5cGlxcWJSqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.70.0",
"@typescript-eslint/visitor-keys": "8.70.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.0.tgz",
"integrity": "sha512-adnkeeNq9Sq1sUf4+FRVc0KdgYghzsgFpZSQVZVvY0LCuUuN0FnQgyGzCJeC4fW1cdXseBAjU2EOqUIjbNcZUw==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": {
"version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.0.tgz",
"integrity": "sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": {
"version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.0.tgz",
"integrity": "sha512-d9NmHMPEKQ7QCLLm1jI3zmoQBwT5KwFYjXBJ9ymZfKCUU+5rmTRykKAFvH5Qn/ZCds3CEAFS9OC9M/jkl0X2bA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.70.0",
"@typescript-eslint/tsconfig-utils": "8.70.0",
"@typescript-eslint/types": "8.70.0",
"@typescript-eslint/visitor-keys": "8.70.0",
"debug": "^4.4.3",
"minimatch": "^10.2.2",
"semver": "^7.7.3",
"tinyglobby": "^0.2.15",
"ts-api-utils": "^2.5.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": {
"version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.0.tgz",
"integrity": "sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.70.0",
"eslint-visitor-keys": "^5.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@typescript-eslint/project-service": { "node_modules/@typescript-eslint/project-service": {
"version": "8.62.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.1.tgz",
"integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==", "integrity": "sha512-62xOgboPfwc3/IgPSX/W6oQR3ZbF04194FPGUGH8HL8iLFHbt/456/8Ph1wLNUgVF+s94FlHoipBsz+v7+LMnA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.62.0", "@typescript-eslint/tsconfig-utils": "^8.70.1",
"@typescript-eslint/types": "^8.62.0", "@typescript-eslint/types": "^8.70.1",
"debug": "^4.4.3" "debug": "^4.4.3"
}, },
"engines": { "engines": {
@@ -2028,14 +1898,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.62.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.1.tgz",
"integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==", "integrity": "sha512-Pa0EeSeAusQc1WbjQMac+YfenewYTBu0KjgYvkUKwhXaHUKbFog23Dm/rp0DX/6tyYOQ3Xl1a+3EcFNZynGHCw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.62.0", "@typescript-eslint/types": "8.70.1",
"@typescript-eslint/visitor-keys": "8.62.0" "@typescript-eslint/visitor-keys": "8.70.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2046,9 +1916,9 @@
} }
}, },
"node_modules/@typescript-eslint/tsconfig-utils": { "node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.62.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.1.tgz",
"integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==", "integrity": "sha512-jumze1fPI+sDOaM2TWGQdn39PDxTr7TZGeuyLkAbNyx2vtMT3uRnVKChN0hfht5V2TugphJzF6bYXvBcE09qqg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2063,15 +1933,15 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.62.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.70.1.tgz",
"integrity": "sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==", "integrity": "sha512-7zKTnyvaVWqzLZHPFQtX1hVHqgkMC+WebPWakNCSyrQVbIP1AM0L0TlBZtACldIRb6PptI8Odk+jyZ5kP3B1VA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.62.0", "@typescript-eslint/types": "8.70.1",
"@typescript-eslint/typescript-estree": "8.62.0", "@typescript-eslint/typescript-estree": "8.70.1",
"@typescript-eslint/utils": "8.62.0", "@typescript-eslint/utils": "8.70.1",
"debug": "^4.4.3", "debug": "^4.4.3",
"ts-api-utils": "^2.5.0" "ts-api-utils": "^2.5.0"
}, },
@@ -2088,9 +1958,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.62.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.1.tgz",
"integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", "integrity": "sha512-Dm1ypdhhrGCTyyehxElhgJ6kgk8MVCv5qXdoOVqPr1uqk42jX8KjrZqhROvdShczA8qrDoYiOWn1ykWlx2k81Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2102,16 +1972,16 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.62.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.1.tgz",
"integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==", "integrity": "sha512-TU8PwyGN0PQJUcE96mw8eCQ44SmxGdQlJmlWakHaHQ15eIuuvye5yNtmh/i6oS88jzXVQB71xdNkbkB/fMwL0g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/project-service": "8.62.0", "@typescript-eslint/project-service": "8.70.1",
"@typescript-eslint/tsconfig-utils": "8.62.0", "@typescript-eslint/tsconfig-utils": "8.70.1",
"@typescript-eslint/types": "8.62.0", "@typescript-eslint/types": "8.70.1",
"@typescript-eslint/visitor-keys": "8.62.0", "@typescript-eslint/visitor-keys": "8.70.1",
"debug": "^4.4.3", "debug": "^4.4.3",
"minimatch": "^10.2.2", "minimatch": "^10.2.2",
"semver": "^7.7.3", "semver": "^7.7.3",
@@ -2130,16 +2000,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.62.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.70.1.tgz",
"integrity": "sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==", "integrity": "sha512-Esgul8MsnKnRLdYU2Eb2cRV9bS5HJYtKj1ByJnOzzG2M58DGdSUQ1jUuILxipqcpB2h9WLrbD5GijIWUjX/Tqw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.9.1", "@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.62.0", "@typescript-eslint/scope-manager": "8.70.1",
"@typescript-eslint/types": "8.62.0", "@typescript-eslint/types": "8.70.1",
"@typescript-eslint/typescript-estree": "8.62.0" "@typescript-eslint/typescript-estree": "8.70.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2154,13 +2024,13 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.62.0", "version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.1.tgz",
"integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==", "integrity": "sha512-Vwj9lUIW5Xq3wQ9w6gv3R86g1hMK8f2zNOdGTAgeXUMMXFK78G9ruCjjqutHMNJc0+CH7LYRnHeUB9IT8wFmcw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.62.0", "@typescript-eslint/types": "8.70.1",
"eslint-visitor-keys": "^5.0.0" "eslint-visitor-keys": "^5.0.0"
}, },
"engines": { "engines": {
@@ -6023,9 +5893,9 @@
} }
}, },
"node_modules/ts-jest": { "node_modules/ts-jest": {
"version": "29.4.14", "version": "29.4.11",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.14.tgz", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.11.tgz",
"integrity": "sha512-+943G6wCX5E3VpzTQhBGBFntCmdT+QAkTvUlp03edTONFBvqskuXPhpyX16xdUotO4P5HQKyppldSWjocoltLQ==", "integrity": "sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -6035,7 +5905,7 @@
"json5": "^2.2.3", "json5": "^2.2.3",
"lodash.memoize": "^4.1.2", "lodash.memoize": "^4.1.2",
"make-error": "^1.3.6", "make-error": "^1.3.6",
"semver": "^7.8.5", "semver": "^7.8.0",
"type-fest": "^4.41.0", "type-fest": "^4.41.0",
"yargs-parser": "^21.1.1" "yargs-parser": "^21.1.1"
}, },
@@ -6046,7 +5916,7 @@
"node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"@babel/core": ">=7.0.0-beta.0 <9", "@babel/core": ">=7.0.0-beta.0 <8",
"@jest/transform": "^29.0.0 || ^30.0.0", "@jest/transform": "^29.0.0 || ^30.0.0",
"@jest/types": "^29.0.0 || ^30.0.0", "@jest/types": "^29.0.0 || ^30.0.0",
"babel-jest": "^29.0.0 || ^30.0.0", "babel-jest": "^29.0.0 || ^30.0.0",
@@ -6168,9 +6038,9 @@
} }
}, },
"node_modules/undici": { "node_modules/undici": {
"version": "6.29.0", "version": "6.28.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.29.0.tgz", "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
"integrity": "sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==", "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=18.17" "node": ">=18.17"
+3 -3
View File
@@ -46,8 +46,8 @@
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
"@jest/globals": "^30.4.1", "@jest/globals": "^30.4.1",
"@types/node": "^24.10.1", "@types/node": "^24.10.1",
"@types/semver": "^7.8.0", "@types/semver": "^7.7.0",
"@typescript-eslint/eslint-plugin": "^8.62.0", "@typescript-eslint/eslint-plugin": "^8.70.1",
"@typescript-eslint/parser": "^8.70.0", "@typescript-eslint/parser": "^8.70.0",
"@vercel/ncc": "^0.45.0", "@vercel/ncc": "^0.45.0",
"eslint": "^10.5.0", "eslint": "^10.5.0",
@@ -57,7 +57,7 @@
"globals": "^17.7.0", "globals": "^17.7.0",
"jest": "^30.4.2", "jest": "^30.4.2",
"prettier": "^3.8.4", "prettier": "^3.8.4",
"ts-jest": "^29.4.14", "ts-jest": "^29.4.11",
"typescript": "^6.0.3" "typescript": "^6.0.3"
} }
} }