refactor: replace axios with fetch API and update related types (#1666)

This commit is contained in:
João Lucas de Oliveira Lopes
2025-09-27 23:52:43 -03:00
committed by GitHub
parent cfe7a2b2b3
commit fb12f6d9d3
13 changed files with 97 additions and 124 deletions
-1
View File
@@ -43,7 +43,6 @@
"@cacheable/node-cache": "^1.4.0", "@cacheable/node-cache": "^1.4.0",
"@hapi/boom": "^9.1.3", "@hapi/boom": "^9.1.3",
"async-mutex": "^0.5.0", "async-mutex": "^0.5.0",
"axios": "^1.6.0",
"libsignal": "git+https://github.com/whiskeysockets/libsignal-node", "libsignal": "git+https://github.com/whiskeysockets/libsignal-node",
"lru-cache": "^11.1.0", "lru-cache": "^11.1.0",
"music-metadata": "^11.7.0", "music-metadata": "^11.7.0",
+2 -2
View File
@@ -57,7 +57,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
logger, logger,
linkPreviewImageThumbnailWidth, linkPreviewImageThumbnailWidth,
generateHighQualityLinkPreview, generateHighQualityLinkPreview,
options: axiosOptions, options: httpRequestOptions,
patchMessageBeforeSending, patchMessageBeforeSending,
cachedGroupMetadata, cachedGroupMetadata,
enableRecentMessageCache, enableRecentMessageCache,
@@ -1077,7 +1077,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
thumbnailWidth: linkPreviewImageThumbnailWidth, thumbnailWidth: linkPreviewImageThumbnailWidth,
fetchOpts: { fetchOpts: {
timeout: 3_000, timeout: 3_000,
...(axiosOptions || {}) ...(httpRequestOptions || {})
}, },
logger, logger,
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
+1 -2
View File
@@ -1,4 +1,3 @@
import type { AxiosRequestConfig } from 'axios'
import type { Readable } from 'stream' import type { Readable } from 'stream'
import type { URL } from 'url' import type { URL } from 'url'
import { proto } from '../../WAProto/index.js' import { proto } from '../../WAProto/index.js'
@@ -335,7 +334,7 @@ export type MediaGenerationOptions = {
mediaUploadTimeoutMs?: number mediaUploadTimeoutMs?: number
options?: AxiosRequestConfig options?: RequestInit
backgroundColor?: string backgroundColor?: string
+2 -3
View File
@@ -1,4 +1,3 @@
import type { AxiosRequestConfig } from 'axios'
import type { Agent } from 'https' import type { Agent } from 'https'
import type { URL } from 'url' import type { URL } from 'url'
import { proto } from '../../WAProto/index.js' import { proto } from '../../WAProto/index.js'
@@ -131,8 +130,8 @@ export type SocketConfig = {
snapshot: boolean snapshot: boolean
} }
/** options for axios */ /** options for HTTP fetch requests */
options: AxiosRequestConfig<{}> options: RequestInit
/** /**
* fetch a message from your store * fetch a message from your store
* implement this so that messages failed to send * implement this so that messages failed to send
+7
View File
@@ -0,0 +1,7 @@
declare global {
interface RequestInit {
dispatcher?: any
}
}
export {}
+4 -5
View File
@@ -1,5 +1,4 @@
import { Boom } from '@hapi/boom' import { Boom } from '@hapi/boom'
import type { AxiosRequestConfig } from 'axios'
import { proto } from '../../WAProto/index.js' import { proto } from '../../WAProto/index.js'
import type { import type {
BaileysEventEmitter, BaileysEventEmitter,
@@ -303,7 +302,7 @@ export const decodeSyncdPatch = async (
return result return result
} }
export const extractSyncdPatches = async (result: BinaryNode, options: AxiosRequestConfig<{}>) => { export const extractSyncdPatches = async (result: BinaryNode, options: RequestInit) => {
const syncNode = getBinaryNodeChild(result, 'sync') const syncNode = getBinaryNodeChild(result, 'sync')
const collectionNodes = getBinaryNodeChildren(syncNode, 'collection') const collectionNodes = getBinaryNodeChildren(syncNode, 'collection')
@@ -355,7 +354,7 @@ export const extractSyncdPatches = async (result: BinaryNode, options: AxiosRequ
return final return final
} }
export const downloadExternalBlob = async (blob: proto.IExternalBlobReference, options: AxiosRequestConfig<{}>) => { export const downloadExternalBlob = async (blob: proto.IExternalBlobReference, options: RequestInit) => {
const stream = await downloadContentFromMessage(blob, 'md-app-state', { options }) const stream = await downloadContentFromMessage(blob, 'md-app-state', { options })
const bufferArray: Buffer[] = [] const bufferArray: Buffer[] = []
for await (const chunk of stream) { for await (const chunk of stream) {
@@ -365,7 +364,7 @@ export const downloadExternalBlob = async (blob: proto.IExternalBlobReference, o
return Buffer.concat(bufferArray) return Buffer.concat(bufferArray)
} }
export const downloadExternalPatch = async (blob: proto.IExternalBlobReference, options: AxiosRequestConfig<{}>) => { export const downloadExternalPatch = async (blob: proto.IExternalBlobReference, options: RequestInit) => {
const buffer = await downloadExternalBlob(blob, options) const buffer = await downloadExternalBlob(blob, options)
const syncData = decodeAndHydrate(proto.SyncdMutations, buffer) const syncData = decodeAndHydrate(proto.SyncdMutations, buffer)
return syncData return syncData
@@ -424,7 +423,7 @@ export const decodePatches = async (
syncds: proto.ISyncdPatch[], syncds: proto.ISyncdPatch[],
initial: LTHashState, initial: LTHashState,
getAppStateSyncKey: FetchAppStateSyncKey, getAppStateSyncKey: FetchAppStateSyncKey,
options: AxiosRequestConfig<{}>, options: RequestInit,
minimumVersionNumber?: number, minimumVersionNumber?: number,
logger?: ILogger, logger?: ILogger,
validateMacs = true validateMacs = true
+20 -10
View File
@@ -1,5 +1,4 @@
import { Boom } from '@hapi/boom' import { Boom } from '@hapi/boom'
import axios, { type AxiosRequestConfig } from 'axios'
import { createHash, randomBytes } from 'crypto' import { createHash, randomBytes } from 'crypto'
import { proto } from '../../WAProto/index.js' import { proto } from '../../WAProto/index.js'
const baileysVersion = [2, 3000, 1023223821] const baileysVersion = [2, 3000, 1023223821]
@@ -225,16 +224,21 @@ export const bindWaitForConnectionUpdate = (ev: BaileysEventEmitter) => bindWait
* utility that fetches latest baileys version from the master branch. * utility that fetches latest baileys version from the master branch.
* Use to ensure your WA connection is always on the latest version * Use to ensure your WA connection is always on the latest version
*/ */
export const fetchLatestBaileysVersion = async (options: AxiosRequestConfig<{}> = {}) => { export const fetchLatestBaileysVersion = async (options: RequestInit = {}) => {
const URL = 'https://raw.githubusercontent.com/WhiskeySockets/Baileys/master/src/Defaults/index.ts' const URL = 'https://raw.githubusercontent.com/WhiskeySockets/Baileys/master/src/Defaults/index.ts'
try { try {
const result = await axios.get<string>(URL, { const response = await fetch(URL, {
...options, dispatcher: options.dispatcher,
responseType: 'text' method: 'GET',
headers: options.headers
}) })
if (!response.ok) {
throw new Boom(`Failed to fetch latest Baileys version: ${response.statusText}`, { statusCode: response.status })
}
const text = await response.text()
// Extract version from line 7 (const version = [...]) // Extract version from line 7 (const version = [...])
const lines = result.data.split('\n') const lines = text.split('\n')
const versionLine = lines[6] // Line 7 (0-indexed) const versionLine = lines[6] // Line 7 (0-indexed)
const versionMatch = versionLine!.match(/const version = \[(\d+),\s*(\d+),\s*(\d+)\]/) const versionMatch = versionLine!.match(/const version = \[(\d+),\s*(\d+),\s*(\d+)\]/)
@@ -261,12 +265,18 @@ export const fetchLatestBaileysVersion = async (options: AxiosRequestConfig<{}>
* A utility that fetches the latest web version of whatsapp. * A utility that fetches the latest web version of whatsapp.
* Use to ensure your WA connection is always on the latest version * Use to ensure your WA connection is always on the latest version
*/ */
export const fetchLatestWaWebVersion = async (options: AxiosRequestConfig<{}>) => { export const fetchLatestWaWebVersion = async (options: RequestInit = {}) => {
try { try {
const { data } = await axios.get('https://web.whatsapp.com/sw.js', { const response = await fetch('https://web.whatsapp.com/sw.js', {
...options, dispatcher: options.dispatcher,
responseType: 'json' method: 'GET',
headers: options.headers
}) })
if (!response.ok) {
throw new Boom(`Failed to fetch sw.js: ${response.statusText}`, { statusCode: response.status })
}
const data = await response.text()
const regex = /\\?"client_revision\\?":\s*(\d+)/ const regex = /\\?"client_revision\\?":\s*(\d+)/
const match = data.match(regex) const match = data.match(regex)
+2 -3
View File
@@ -1,4 +1,3 @@
import type { AxiosRequestConfig } from 'axios'
import { promisify } from 'util' import { promisify } from 'util'
import { inflate } from 'zlib' import { inflate } from 'zlib'
import { proto } from '../../WAProto/index.js' import { proto } from '../../WAProto/index.js'
@@ -11,7 +10,7 @@ import { decodeAndHydrate } from './proto-utils'
const inflatePromise = promisify(inflate) const inflatePromise = promisify(inflate)
export const downloadHistory = async (msg: proto.Message.IHistorySyncNotification, options: AxiosRequestConfig<{}>) => { export const downloadHistory = async (msg: proto.Message.IHistorySyncNotification, options: RequestInit) => {
const stream = await downloadContentFromMessage(msg, 'md-msg-hist', { options }) const stream = await downloadContentFromMessage(msg, 'md-msg-hist', { options })
const bufferArray: Buffer[] = [] const bufferArray: Buffer[] = []
for await (const chunk of stream) { for await (const chunk of stream) {
@@ -96,7 +95,7 @@ export const processHistoryMessage = (item: proto.IHistorySync) => {
export const downloadAndProcessHistorySyncNotification = async ( export const downloadAndProcessHistorySyncNotification = async (
msg: proto.Message.IHistorySyncNotification, msg: proto.Message.IHistorySyncNotification,
options: AxiosRequestConfig<{}> options: RequestInit
) => { ) => {
const historyMsg = await downloadHistory(msg, options) const historyMsg = await downloadHistory(msg, options)
return processHistoryMessage(historyMsg) return processHistoryMessage(historyMsg)
+2 -3
View File
@@ -1,4 +1,3 @@
import type { AxiosRequestConfig } from 'axios'
import type { WAMediaUploadFunction, WAUrlInfo } from '../Types' import type { WAMediaUploadFunction, WAUrlInfo } from '../Types'
import type { ILogger } from './logger' import type { ILogger } from './logger'
import { prepareWAMessageMedia } from './messages' import { prepareWAMessageMedia } from './messages'
@@ -19,7 +18,7 @@ export type URLGenerationOptions = {
/** Timeout in ms */ /** Timeout in ms */
timeout: number timeout: number
proxyUrl?: string proxyUrl?: string
headers?: AxiosRequestConfig<{}>['headers'] headers?: HeadersInit
} }
uploadImage?: WAMediaUploadFunction uploadImage?: WAMediaUploadFunction
logger?: ILogger logger?: ILogger
@@ -70,7 +69,7 @@ export const getUrlInfo = async (
return false return false
} }
}, },
headers: opts.fetchOpts as {} headers: opts.fetchOpts?.headers as {}
}) })
if (info && 'title' in info && info.title) { if (info && 'title' in info && info.title) {
const [image] = info.images const [image] = info.images
+49 -28
View File
@@ -1,5 +1,4 @@
import { Boom } from '@hapi/boom' import { Boom } from '@hapi/boom'
import axios, { type AxiosRequestConfig } from 'axios'
import { exec } from 'child_process' import { exec } from 'child_process'
import * as Crypto from 'crypto' import * as Crypto from 'crypto'
import { once } from 'events' import { once } from 'events'
@@ -301,7 +300,7 @@ export const toBuffer = async (stream: Readable) => {
return Buffer.concat(chunks) return Buffer.concat(chunks)
} }
export const getStream = async (item: WAMediaUpload, opts?: AxiosRequestConfig) => { export const getStream = async (item: WAMediaUpload, opts?: RequestInit & { maxContentLength?: number }) => {
if (Buffer.isBuffer(item)) { if (Buffer.isBuffer(item)) {
return { stream: toReadable(item), type: 'buffer' } as const return { stream: toReadable(item), type: 'buffer' } as const
} }
@@ -362,15 +361,24 @@ export async function generateThumbnail(
} }
} }
export const getHttpStream = async (url: string | URL, options: AxiosRequestConfig & { isStream?: true } = {}) => { export const getHttpStream = async (url: string | URL, options: RequestInit & { isStream?: true } = {}) => {
const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' }) const response = await fetch(url.toString(), {
return fetched.data as Readable dispatcher: options.dispatcher,
method: 'GET',
headers: options.headers as HeadersInit
})
if (!response.ok) {
throw new Boom(`Failed to fetch stream from ${url}`, { statusCode: response.status, data: { url } })
}
// @ts-ignore Node18+ Readable.fromWeb exists
return Readable.fromWeb(response.body as any)
} }
type EncryptedStreamOptions = { type EncryptedStreamOptions = {
saveOriginalFileIfRequired?: boolean saveOriginalFileIfRequired?: boolean
logger?: ILogger logger?: ILogger
opts?: AxiosRequestConfig opts?: RequestInit
} }
export const encryptedStream = async ( export const encryptedStream = async (
@@ -412,7 +420,11 @@ export const encryptedStream = async (
for await (const data of stream) { for await (const data of stream) {
fileLength += data.length fileLength += data.length
if (type === 'remote' && opts?.maxContentLength && fileLength + data.length > opts.maxContentLength) { if (
type === 'remote' &&
(opts as any)?.maxContentLength &&
fileLength + data.length > (opts as any).maxContentLength
) {
throw new Boom(`content length exceeded when encrypting "${type}"`, { throw new Boom(`content length exceeded when encrypting "${type}"`, {
data: { media, type } data: { media, type }
}) })
@@ -486,7 +498,7 @@ const toSmallestChunkSize = (num: number) => {
export type MediaDownloadOptions = { export type MediaDownloadOptions = {
startByte?: number startByte?: number
endByte?: number endByte?: number
options?: AxiosRequestConfig<{}> options?: RequestInit
} }
export const getUrlFromDirectPath = (directPath: string) => `https://${DEF_HOST}${directPath}` export const getUrlFromDirectPath = (directPath: string) => `https://${DEF_HOST}${directPath}`
@@ -532,8 +544,13 @@ export const downloadEncryptedContent = async (
const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined
const headers: AxiosRequestConfig['headers'] = { const headersInit = options?.headers ? options.headers : undefined
...(options?.headers || {}), const headers: Record<string, string> = {
...(headersInit
? Array.isArray(headersInit)
? Object.fromEntries(headersInit)
: (headersInit as Record<string, string>)
: {}),
Origin: DEFAULT_ORIGIN Origin: DEFAULT_ORIGIN
} }
if (startChunk || endChunk) { if (startChunk || endChunk) {
@@ -546,9 +563,7 @@ export const downloadEncryptedContent = async (
// download the message // download the message
const fetched = await getHttpStream(downloadUrl, { const fetched = await getHttpStream(downloadUrl, {
...(options || {}), ...(options || {}),
headers, headers
maxBodyLength: Infinity,
maxContentLength: Infinity
}) })
let remainingBytes = Buffer.from([]) let remainingBytes = Buffer.from([])
@@ -645,21 +660,31 @@ export const getWAUploadToServer = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let result: any let result: any
try { try {
const body = await axios.post(url, createReadStream(filePath), { const stream = createReadStream(filePath)
...options, const response = await fetch(url, {
maxRedirects: 0, dispatcher: fetchAgent,
method: 'POST',
body: stream as any,
headers: { headers: {
...(options.headers || {}), ...(() => {
const hdrs = options?.headers
if (!hdrs) return {}
return Array.isArray(hdrs) ? Object.fromEntries(hdrs) : (hdrs as Record<string, string>)
})(),
'Content-Type': 'application/octet-stream', 'Content-Type': 'application/octet-stream',
Origin: DEFAULT_ORIGIN Origin: DEFAULT_ORIGIN
}, },
httpsAgent: fetchAgent, // Note: custom agents/proxy require undici Agent; omitted here.
timeout: timeoutMs, signal: timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined
responseType: 'json',
maxBodyLength: Infinity,
maxContentLength: Infinity
}) })
result = body.data let parsed: any = undefined
try {
parsed = await response.json()
} catch {
parsed = undefined
}
result = parsed
if (result?.url || result?.directPath) { if (result?.url || result?.directPath) {
urls = { urls = {
@@ -675,13 +700,9 @@ export const getWAUploadToServer = (
throw new Error(`upload failed, reason: ${JSON.stringify(result)}`) throw new Error(`upload failed, reason: ${JSON.stringify(result)}`)
} }
} catch (error: any) { } catch (error: any) {
if (axios.isAxiosError(error)) {
result = error.response?.data
}
const isLast = hostname === hosts[uploadInfo.hosts.length - 1]?.hostname const isLast = hostname === hosts[uploadInfo.hosts.length - 1]?.hostname
logger.warn( logger.warn(
{ trace: error.stack, uploadResult: result }, { trace: error?.stack, uploadResult: result },
`Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}` `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`
) )
} }
+6 -6
View File
@@ -1,5 +1,4 @@
import { Boom } from '@hapi/boom' import { Boom } from '@hapi/boom'
import axios from 'axios'
import { randomBytes } from 'crypto' import { randomBytes } from 'crypto'
import { promises as fs } from 'fs' import { promises as fs } from 'fs'
import { type Transform } from 'stream' import { type Transform } from 'stream'
@@ -455,9 +454,10 @@ export const generateWAMessageContent = async (
if (options.getProfilePicUrl) { if (options.getProfilePicUrl) {
const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview') const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview')
if (pfpUrl) { if (pfpUrl) {
const resp = await axios.get(pfpUrl, { responseType: 'arraybuffer' }) const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher })
if (resp.status === 200) { if (resp.ok) {
m.groupInviteMessage.jpegThumbnail = resp.data const buf = Buffer.from(await resp.arrayBuffer())
m.groupInviteMessage.jpegThumbnail = buf
} }
} }
} }
@@ -933,8 +933,8 @@ export const downloadMediaMessage = async <Type extends 'buffer' | 'stream'>(
const result = await downloadMsg().catch(async error => { const result = await downloadMsg().catch(async error => {
if ( if (
ctx && ctx &&
axios.isAxiosError(error) && // check if the message requires a reupload typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
REUPLOAD_REQUIRED_STATUS.includes(error.response?.status!) REUPLOAD_REQUIRED_STATUS.includes(error.status as number)
) { ) {
ctx.logger.info({ key: message.key }, 'sending reupload media request...') ctx.logger.info({ key: message.key }, 'sending reupload media request...')
// request reupload // request reupload
+1 -2
View File
@@ -1,4 +1,3 @@
import type { AxiosRequestConfig } from 'axios'
import { proto } from '../../WAProto/index.js' import { proto } from '../../WAProto/index.js'
import type { import type {
AuthenticationCreds, AuthenticationCreds,
@@ -28,7 +27,7 @@ type ProcessMessageContext = {
keyStore: SignalKeyStoreWithTransaction keyStore: SignalKeyStoreWithTransaction
ev: BaileysEventEmitter ev: BaileysEventEmitter
logger?: ILogger logger?: ILogger
options: AxiosRequestConfig<{}> options: RequestInit
signalRepository: SignalRepositoryWithLIDStore signalRepository: SignalRepositoryWithLIDStore
} }
+1 -59
View File
@@ -2874,13 +2874,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"asynckit@npm:^0.4.0":
version: 0.4.0
resolution: "asynckit@npm:0.4.0"
checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d
languageName: node
linkType: hard
"atomic-sleep@npm:^1.0.0": "atomic-sleep@npm:^1.0.0":
version: 1.0.0 version: 1.0.0
resolution: "atomic-sleep@npm:1.0.0" resolution: "atomic-sleep@npm:1.0.0"
@@ -2904,17 +2897,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"axios@npm:^1.6.0":
version: 1.10.0
resolution: "axios@npm:1.10.0"
dependencies:
follow-redirects: "npm:^1.15.6"
form-data: "npm:^4.0.0"
proxy-from-env: "npm:^1.1.0"
checksum: 10c0/2239cb269cc789eac22f5d1aabd58e1a83f8f364c92c2caa97b6f5cbb4ab2903d2e557d9dc670b5813e9bcdebfb149e783fb8ab3e45098635cd2f559b06bd5d8
languageName: node
linkType: hard
"babel-jest@npm:30.0.5": "babel-jest@npm:30.0.5":
version: 30.0.5 version: 30.0.5
resolution: "babel-jest@npm:30.0.5" resolution: "babel-jest@npm:30.0.5"
@@ -3008,7 +2990,6 @@ __metadata:
"@typescript-eslint/parser": "npm:^8" "@typescript-eslint/parser": "npm:^8"
"@whiskeysockets/eslint-config": "npm:^1.0.0" "@whiskeysockets/eslint-config": "npm:^1.0.0"
async-mutex: "npm:^0.5.0" async-mutex: "npm:^0.5.0"
axios: "npm:^1.6.0"
conventional-changelog-cli: "npm:^2.2.2" conventional-changelog-cli: "npm:^2.2.2"
esbuild-register: "npm:^3.6.0" esbuild-register: "npm:^3.6.0"
eslint: "npm:^9" eslint: "npm:^9"
@@ -3590,15 +3571,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"combined-stream@npm:^1.0.8":
version: 1.0.8
resolution: "combined-stream@npm:1.0.8"
dependencies:
delayed-stream: "npm:~1.0.0"
checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5
languageName: node
linkType: hard
"compare-func@npm:^2.0.0": "compare-func@npm:^2.0.0":
version: 2.0.0 version: 2.0.0
resolution: "compare-func@npm:2.0.0" resolution: "compare-func@npm:2.0.0"
@@ -4137,13 +4109,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"delayed-stream@npm:~1.0.0":
version: 1.0.0
resolution: "delayed-stream@npm:1.0.0"
checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19
languageName: node
linkType: hard
"deprecation@npm:^2.0.0": "deprecation@npm:^2.0.0":
version: 2.3.1 version: 2.3.1
resolution: "deprecation@npm:2.3.1" resolution: "deprecation@npm:2.3.1"
@@ -5153,16 +5118,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"follow-redirects@npm:^1.15.6":
version: 1.15.9
resolution: "follow-redirects@npm:1.15.9"
peerDependenciesMeta:
debug:
optional: true
checksum: 10c0/5829165bd112c3c0e82be6c15b1a58fa9dcfaede3b3c54697a82fe4a62dd5ae5e8222956b448d2f98e331525f05d00404aba7d696de9e761ef6e42fdc780244f
languageName: node
linkType: hard
"for-each@npm:^0.3.3, for-each@npm:^0.3.5": "for-each@npm:^0.3.3, for-each@npm:^0.3.5":
version: 0.3.5 version: 0.3.5
resolution: "for-each@npm:0.3.5" resolution: "for-each@npm:0.3.5"
@@ -5189,19 +5144,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"form-data@npm:^4.0.0":
version: 4.0.4
resolution: "form-data@npm:4.0.4"
dependencies:
asynckit: "npm:^0.4.0"
combined-stream: "npm:^1.0.8"
es-set-tostringtag: "npm:^2.1.0"
hasown: "npm:^2.0.2"
mime-types: "npm:^2.1.12"
checksum: 10c0/373525a9a034b9d57073e55eab79e501a714ffac02e7a9b01be1c820780652b16e4101819785e1e18f8d98f0aee866cc654d660a435c378e16a72f2e7cac9695
languageName: node
linkType: hard
"formdata-polyfill@npm:^4.0.10": "formdata-polyfill@npm:^4.0.10":
version: 4.0.10 version: 4.0.10
resolution: "formdata-polyfill@npm:4.0.10" resolution: "formdata-polyfill@npm:4.0.10"
@@ -7734,7 +7676,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"mime-types@npm:2.1.35, mime-types@npm:^2.1.12": "mime-types@npm:2.1.35":
version: 2.1.35 version: 2.1.35
resolution: "mime-types@npm:2.1.35" resolution: "mime-types@npm:2.1.35"
dependencies: dependencies: