modify:api 接口优化

This commit is contained in:
ECRZ
2026-01-06 11:01:47 +08:00
parent ba478d70cc
commit dc32f18539
5 changed files with 617 additions and 0 deletions

3
.gitignore vendored
View File

@@ -32,3 +32,6 @@ build/
# 临时文件
tmp/
temp/
# Token 缓存文件(敏感信息)
.token-cache.json

171
commonApi.js Normal file
View File

@@ -0,0 +1,171 @@
const axios = require('axios');
const login = require('./loginApi.js');
/**
* 钢材价格数据采集服务
* 从德钢云平台获取价格数据
*/
class SteelPriceCollector {
constructor() {
this.baseURL = 'https://xdwlgyl.yciccloud.com';
this.pageId = 'PG-D615-D8E2-2FD84B8D';
this.menuId = 'MK-A8B8-109E-13D34116';
}
/**
* 构建请求配置(先获取 Token
* @param {Object} params - 查询参数
* @param {string} params.startDate - 开始日期 (YYYY-MM-DD)
* @param {string} params.endDate - 结束日期 (YYYY-MM-DD)
* @param {number} params.page - 页码默认1
* @param {number} params.pageSize - 每页大小默认1000
* @returns {Promise<Object>} Axios请求配置
*/
async _buildConfig(params = {}) {
const {
startDate = new Date().toISOString().split('T')[0],
endDate = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
page = 1,
pageSize = 10
} = params;
// 先获取 Token
console.log('🔐 正在获取 Token...');
const tokenResult = await login.getToken();
if (!tokenResult.success) {
throw new Error(`Token 获取失败: ${tokenResult.error}`);
}
const tokenId = tokenResult.data;
console.log('✅ Token 获取成功:', tokenId);
// 构建查询条件对象
const searchParams = {
_PIRCE_DATE_DATE_START_: startDate,
_PIRCE_DATE_DATE_END_: endDate,
PARTSNAME_NAME: null,
_PARTSNAME_NAME_ADVANCE_SEARCH_: null,
_PARTSNAME_NAME_IS_LIKE_: '1',
GOODS_MATERIAL: null,
_GOODS_MATERIAL_ADVANCE_SEARCH_: null,
_GOODS_MATERIAL_IS_LIKE_: '1',
GOODS_SPEC: null,
_GOODS_SPEC_ADVANCE_SEARCH_: null,
_GOODS_SPEC_IS_LIKE_: '1',
PRODUCTAREA_NAME: null,
_PRODUCTAREA_NAME_ADVANCE_SEARCH_: null,
_PRODUCTAREA_NAME_IS_LIKE_: '1',
PNTREE_NAME: null,
_PNTREE_NAME_ADVANCE_SEARCH_: null,
_PNTREE_NAME_IS_LIKE_: '1',
OPERATOR_NAME: null,
_OPERATOR_NAME_ADVANCE_SEARCH_: null,
PR_PRICE_REGION: null,
_PR_PRICE_REGION_ADVANCE_SEARCH_: null,
OPERATOR_CODE: null,
PRICE_ID: null,
_orderFields_: []
};
// 构建URL编码的请求体
const requestData = new URLSearchParams({
pageId: this.pageId,
pageSize: pageSize.toString(),
page: page.toString(),
isPageNoChange: '0',
ctrlId: 'mainTable',
json: JSON.stringify(searchParams),
searchBoxId: 'searchForm',
groupSumFields: JSON.stringify([])
});
// 使用获取到的 Token 构建 Cookie
const cookie = `SameSite=Lax; HWWAFSESTIME=1767596069712; HWWAFSESID=e2b2773ee2641b98e5; SameSite=Lax; SYS-A7EE-D0E8-BE614B80=1108@${tokenId}; JSESSIONID=2389858DBE6A7EDAF695C767A764995B; SameSite=Lax`;
return {
method: 'POST',
url: `${this.baseURL}/gdpaas/mainpage/findPage.htm?_p_=${this.pageId}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'X-Requested-With': 'XMLHttpRequest',
'Pageid': 'PG_D615_D8E2_2FD84B8D',
'Menuid': this.menuId,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Referer': `${this.baseURL}/gdpaas/home/index.htm`,
'Origin': this.baseURL,
'Accept-Language': 'zh-CN,zh;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Dest': 'empty',
'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
'Sec-Ch-Ua-Mobile': '?0',
'Sec-Ch-Ua-Platform': '"Windows"',
'cookie': cookie
},
data: requestData.toString()
};
}
/**
* 获取钢材价格数据
* @param {Object} params - 查询参数
* @returns {Promise<Object>} 响应数据
*/
async fetchPrices(params = {}) {
try {
const config = await this._buildConfig(params);
const response = await axios.request(config);
// 验证响应数据
if (!response.data) {
throw new Error('响应数据为空');
}
return {
success: true,
data: response.data,
timestamp: new Date().toISOString()
};
} catch (error) {
return {
success: false,
error: error.message,
timestamp: new Date().toISOString()
};
}
}
}
/**
* 导出单例实例
*/
module.exports = new SteelPriceCollector();
/**
* 如果直接运行此文件,执行示例请求
*/
if (require.main === module) {
const collector = require('./commonApi.js');
// 示例:获取最近一年的价格数据
collector.fetchPrices({
startDate: '2025-01-06',
endDate: '2026-01-06',
page: 1,
pageSize: 1
})
.then(result => {
if (result.success) {
console.log('✅ 数据获取成功');
console.log('📅 时间:', result.timestamp);
console.log('📊 数据预览:', JSON.stringify(result.data, null, 2));
} else {
console.error('❌ 数据获取失败:', result.error);
}
})
.catch(error => {
console.error('💥 未捕获的错误:', error);
});
}

348
loginApi.js Normal file
View File

@@ -0,0 +1,348 @@
const axios = require("axios");
const fs = require('fs');
const path = require('path');
/**
* Token 缓存信息
* @typedef {Object} TokenCache
* @property {string} token - Token 值
* @property {string} expiresAt - 过期时间 (ISO 字符串)
*/
/**
* 外部 Token 获取服务
* 支持文件持久化和自动过期更新
* @class ExternalToken
*/
class ExternalToken {
constructor() {
/**
* Token 文件存储路径
* @type {string}
* @private
*/
this._tokenFilePath = path.join(__dirname, '.token-cache.json');
/**
* Token 有效期(毫秒),默认 30 分钟
* @type {number}
* @private
*/
this._tokenValidityMs = 30 * 60 * 1000;
/**
* 是否正在刷新 Token防止并发重复请求
* @type {Promise|null}
* @private
*/
this._refreshingPromise = null;
/**
* 内存中的 Token 缓存
* @type {TokenCache|null}
* @private
*/
this._memoryCache = null;
// 初始化时从文件加载 Token
this._loadTokenFromFile();
}
/**
* 从文件加载 Token
* @private
*/
_loadTokenFromFile() {
try {
if (fs.existsSync(this._tokenFilePath)) {
const data = fs.readFileSync(this._tokenFilePath, 'utf-8');
const cache = JSON.parse(data);
// 验证数据结构
if (cache.token && cache.expiresAt) {
this._memoryCache = {
token: cache.token,
expiresAt: new Date(cache.expiresAt)
};
const isExpired = this._isTokenExpired();
console.log(`📂 从文件加载 Token ${isExpired ? '(已过期)' : '(有效)'}`);
console.log(` 过期时间: ${this._memoryCache.expiresAt.toLocaleString('zh-CN')}`);
} else {
console.warn('⚠️ Token 文件格式无效,将重新获取');
this._memoryCache = null;
}
} else {
console.log('📄 Token 文件不存在,将创建新文件');
}
} catch (error) {
console.error('❌ 读取 Token 文件失败:', error.message);
this._memoryCache = null;
}
}
/**
* 保存 Token 到文件
* @param {string} token - Token 值
* @private
*/
_saveTokenToFile(token) {
try {
const expiresAt = new Date(Date.now() + this._tokenValidityMs);
const cache = {
token,
expiresAt: expiresAt.toISOString(),
updatedAt: new Date().toISOString()
};
fs.writeFileSync(this._tokenFilePath, JSON.stringify(cache, null, 2), 'utf-8');
console.log(`💾 Token 已保存到文件: ${this._tokenFilePath}`);
console.log(` 过期时间: ${expiresAt.toLocaleString('zh-CN')}`);
} catch (error) {
console.error('❌ 保存 Token 文件失败:', error.message);
}
}
/**
* 删除 Token 文件
* @private
*/
_deleteTokenFile() {
try {
if (fs.existsSync(this._tokenFilePath)) {
fs.unlinkSync(this._tokenFilePath);
console.log('🗑️ Token 文件已删除');
}
} catch (error) {
console.error('❌ 删除 Token 文件失败:', error.message);
}
}
/**
* 检查 Token 是否过期
* @returns {boolean}
* @private
*/
_isTokenExpired() {
if (!this._memoryCache) {
return true;
}
const now = new Date();
return now >= this._memoryCache.expiresAt;
}
/**
* 清除 Token 缓存(内存和文件)
*/
clearTokenCache() {
this._memoryCache = null;
this._deleteTokenFile();
console.log('🗑️ Token 缓存已清除');
}
/**
* 设置 Token 有效期
* @param {number} minutes - 有效期(分钟)
*/
setTokenValidity(minutes) {
this._tokenValidityMs = minutes * 60 * 1000;
console.log(`⏱️ Token 有效期已设置为 ${minutes} 分钟`);
}
/**
* 获取新的登录 Token
* @returns {Promise<string>} Token 值
* @throws {Error} 当获取失败时抛出错误
* @private
*/
async _fetchNewToken() {
const config = {
method: 'POST',
url: 'https://xdwlgyl.yciccloud.com/gdpaas/login/doLogin.htm',
headers: {
'host': 'xdwlgyl.yciccloud.com',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
'accept': 'application/json, text/javascript, */*; q=0.01',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'x-requested-with': 'XMLHttpRequest',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'sec-ch-ua-platform': '"Windows"',
'origin': 'https://xdwlgyl.yciccloud.com',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'referer': 'https://xdwlgyl.yciccloud.com/gdpaas/login/index.htm',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
'cookie': 'SYS-A7EE-D0E8-BE614B80=1108%405b2bc1b4b8be40dfb104b1f5c84c1245;SameSite=Lax;HWWAFSESTIME=1767662772583;HWWAFSESID=7817173569731ea415;JSESSIONID=7AF7F82CBD7C1FFC6CBCAF67CFD22AC6',
'Connection': 'keep-alive'
},
data: 'userId=15758339512&pwd=4E71002969FCD46813B869E931AEDF4B&randCode=&langId='
};
try {
console.log('🔄 正在请求新 Token...');
const response = await axios.request(config);
// 安全地提取 tokenId
const tokenId = response?.data?.data?.user?.exts?.tokenId;
if (!tokenId) {
throw new Error('响应中未找到 tokenId');
}
console.log('✅ 新 Token 获取成功:', tokenId);
// 保存到内存和文件
const expiresAt = new Date(Date.now() + this._tokenValidityMs);
this._memoryCache = { token: tokenId, expiresAt };
this._saveTokenToFile(tokenId);
return tokenId;
} catch (error) {
const errorMsg = error.response?.data || error.message;
console.error('❌ Token 获取失败:', errorMsg);
throw new Error(`Token 获取失败: ${errorMsg}`);
}
}
/**
* 获取登录 Token支持文件持久化和自动过期更新
* @param {boolean} forceRefresh - 是否强制刷新 Token
* @returns {Promise<{success: boolean, data?: string, error?: string, timestamp: string, cached?: boolean, source?: string}>}
*/
async getToken(forceRefresh = false) {
try {
// 如果未强制刷新且 Token 未过期,直接返回缓存
if (!forceRefresh && !this._isTokenExpired()) {
const source = this._memoryCache ? '文件缓存' : '内存缓存';
console.log(`♻️ 使用${source}的 Token`);
return {
success: true,
data: this._memoryCache.token,
timestamp: new Date().toISOString(),
cached: true,
source
};
}
// 如果正在刷新,等待刷新完成(防止并发请求)
if (this._refreshingPromise) {
console.log('⏳ Token 刷新中,等待完成...');
await this._refreshingPromise;
return {
success: true,
data: this._memoryCache.token,
timestamp: new Date().toISOString(),
cached: false,
source: '新获取'
};
}
// 开始刷新 Token
this._refreshingPromise = this._fetchNewToken();
const token = await this._refreshingPromise;
// 清除刷新标记
this._refreshingPromise = null;
return {
success: true,
data: token,
timestamp: new Date().toISOString(),
cached: false,
source: '新获取'
};
} catch (error) {
this._refreshingPromise = null;
return {
success: false,
error: error.message,
timestamp: new Date().toISOString()
};
}
}
/**
* 获取当前缓存的 Token不检查过期
* @returns {string|null}
*/
getCachedToken() {
return this._memoryCache?.token || null;
}
/**
* 获取 Token 过期时间
* @returns {Date|null}
*/
getTokenExpiresAt() {
return this._memoryCache?.expiresAt || null;
}
/**
* 检查 Token 是否即将过期(剩余时间少于 5 分钟)
* @returns {boolean}
*/
isTokenExpiringSoon() {
if (!this._memoryCache) {
return true;
}
const now = new Date();
const timeLeft = this._memoryCache.expiresAt - now;
const fiveMinutes = 5 * 60 * 1000;
return timeLeft < fiveMinutes;
}
/**
* 获取 Token 剩余有效时间(秒)
* @returns {number|null} 剩余秒数,如果 Token 不存在或已过期返回 null
*/
getTokenRemainingTime() {
if (!this._memoryCache) {
return null;
}
const now = new Date();
const timeLeft = Math.max(0, this._memoryCache.expiresAt - now);
return Math.floor(timeLeft / 1000);
}
/**
* 获取 Token 文件路径
* @returns {string}
*/
getTokenFilePath() {
return this._tokenFilePath;
}
}
/**
* 导出单例实例
*/
module.exports = new ExternalToken();
/**
* 如果直接运行此文件,执行示例请求
*/
if (require.main === module) {
const collector = require('./loginApi.js');
collector.getToken()
.then(result => {
if (result.success) {
console.log('✅ 数据获取成功');
console.log('📅 时间:', result.timestamp);
console.log('📊 数据预览:', JSON.stringify(result.data, null, 2));
} else {
console.error('❌ 数据获取失败:', result.error);
}
})
.catch(error => {
console.error('💥 未捕获的错误:', error);
});
}

View File

@@ -20,6 +20,7 @@
"author": "",
"license": "MIT",
"dependencies": {
"axios": "^1.13.2",
"cors": "^2.8.5",
"dotenv": "^17.2.3",
"express": "^5.2.1",

94
pnpm-lock.yaml generated
View File

@@ -8,6 +8,9 @@ importers:
.:
dependencies:
axios:
specifier: ^1.13.2
version: 1.13.2
cors:
specifier: ^2.8.5
version: 2.8.5
@@ -63,10 +66,16 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
aws-ssl-profiles@1.1.2:
resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==}
engines: {node: '>= 6.0.0'}
axios@1.13.2:
resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -96,6 +105,10 @@ packages:
call-me-maybe@1.0.2:
resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
commander@6.2.0:
resolution: {integrity: sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==}
engines: {node: '>= 6'}
@@ -144,6 +157,10 @@ packages:
supports-color:
optional: true
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
denque@2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'}
@@ -183,6 +200,10 @@ packages:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
@@ -202,6 +223,19 @@ packages:
resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
engines: {node: '>= 18.0.0'}
follow-redirects@1.15.11:
resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
forwarded@0.2.0:
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
engines: {node: '>= 0.6'}
@@ -239,6 +273,10 @@ packages:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
@@ -302,10 +340,18 @@ packages:
resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
engines: {node: '>=18'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-db@1.54.0:
resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
mime-types@3.0.2:
resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
engines: {node: '>=18'}
@@ -376,6 +422,9 @@ packages:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
qs@6.14.1:
resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==}
engines: {node: '>=0.6'}
@@ -522,8 +571,18 @@ snapshots:
argparse@2.0.1: {}
asynckit@0.4.0: {}
aws-ssl-profiles@1.1.2: {}
axios@1.13.2:
dependencies:
follow-redirects: 1.15.11
form-data: 4.0.5
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
balanced-match@1.0.2: {}
basic-auth@2.0.1:
@@ -563,6 +622,10 @@ snapshots:
call-me-maybe@1.0.2: {}
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
commander@6.2.0: {}
commander@9.5.0:
@@ -591,6 +654,8 @@ snapshots:
dependencies:
ms: 2.1.3
delayed-stream@1.0.0: {}
denque@2.1.0: {}
depd@2.0.0: {}
@@ -619,6 +684,13 @@ snapshots:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.2
escape-html@1.0.3: {}
esutils@2.0.3: {}
@@ -669,6 +741,16 @@ snapshots:
transitivePeerDependencies:
- supports-color
follow-redirects@1.15.11: {}
form-data@4.0.5:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
hasown: 2.0.2
mime-types: 2.1.35
forwarded@0.2.0: {}
fresh@2.0.0: {}
@@ -712,6 +794,10 @@ snapshots:
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.1.0
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
@@ -761,8 +847,14 @@ snapshots:
merge-descriptors@2.0.0: {}
mime-db@1.52.0: {}
mime-db@1.54.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
mime-types@3.0.2:
dependencies:
mime-db: 1.54.0
@@ -834,6 +926,8 @@ snapshots:
forwarded: 0.2.0
ipaddr.js: 1.9.1
proxy-from-env@1.1.0: {}
qs@6.14.1:
dependencies:
side-channel: 1.1.0