diff --git a/.gitignore b/.gitignore index 80c8400..87123fc 100644 --- a/.gitignore +++ b/.gitignore @@ -122,4 +122,6 @@ dist .trae .workbuddy __pycache__ -.catpawai \ No newline at end of file +.catpawai +build/ios/DerivedData +/output \ No newline at end of file diff --git a/build/replace/src/app/lib/install-src.js b/build/replace/src/app/lib/install-src.js new file mode 100644 index 0000000..8f89b0a --- /dev/null +++ b/build/replace/src/app/lib/install-src.js @@ -0,0 +1,31 @@ +// install-src.js +// Determines the Android APK architecture identifier at runtime. +// Used to match the correct release asset when checking/downloading upgrades. +// +// The Android APK splits produce four flavors: +// arm64-v8a -> Node.js os.arch() === 'arm64' +// armeabi-v7a -> Node.js os.arch() === 'arm' +// x86_64 -> Node.js os.arch() === 'x64' +// universal -> (ignored; the device CPU resolves to one of the above) +// +// We resolve at runtime from os.arch() so the same bundled code works for +// every split without a build-time injection step: the APK the user installed +// only contains the native libraries for its target ABI, so os.arch() always +// reflects the ABI that is actually running on device. + +import os from 'os' + +const archMap = { + arm64: 'arm64-v8a', + arm: 'armeabi-v7a', + x64: 'x86_64', + // 32-bit x86 is virtually nonexistent on Android; treat it as x86_64 so + // upgrade matching still resolves to a real asset. + ia32: 'x86_64', + x32: 'x86_64' +} + +const arch = os.arch() +const installSrc = 'electerm-ios-' + (archMap[arch] || 'arm64-v8a') + +export default installSrc diff --git a/build/replace/src/app/lib/view.js b/build/replace/src/app/lib/view.js index b4a33f7..65caa57 100644 --- a/build/replace/src/app/lib/view.js +++ b/build/replace/src/app/lib/view.js @@ -27,14 +27,14 @@ const mandatoryGuardrails = [ '6. If a request violates these policies, decline politely, state the reason in one sentence, and offer a safe alternative when possible. Do not lecture beyond that.' ].join('\n') -const defaultAIPreset = { - baseURLAI: 'https://ai.electerm.org/api/ai', - apiPathAI: '/chat/completions', - modelAI: 'mistral-small-latest', - authHeaderNameAI: 'Authorization: Bearer', - id: 'ai.electerm.org', - nameAI: 'ai.electerm.org(default free)' -} +// const defaultAIPreset = { +// baseURLAI: 'https://ai.electerm.org/api/ai', +// apiPathAI: '/chat/completions', +// modelAI: 'mistral-small-latest', +// authHeaderNameAI: 'Authorization: Bearer', +// id: 'ai.electerm.org', +// nameAI: 'ai.electerm.org(default free)' +// } function buildServer () { return `http://${process.env.HOST}:${process.env.PORT}` @@ -66,7 +66,6 @@ export async function index (req, res) { home, version: packInfo.version, siteName: packInfo.name, - defaultAIPreset, fsFunctions, isWebApp: true, versionFile: 'version-android.html', @@ -82,7 +81,32 @@ export async function index (req, res) { hideLocalTerminal: true, AIDisclamer: 'AI generated content is for reference only', mandatoryGuardrails, - enableAIFlag: true + enableAIFlag: true, + syncTypes: ['github', 'custom', 'webdav'], + AITermOfUse: `About the AI feature / AI 功能说明 + +When you use the AI feature, your input (such as text, commands, terminal output, or other data you send to the model) is transmitted to the third-party LLM provider you configure. That provider may collect, store, and use it according to their own privacy policy. electerm does not control, and is not responsible for, how third-party LLM providers handle your data. + +Please review the privacy policy of the LLM provider you choose, and avoid sending sensitive or confidential information when using AI features. + +使用 AI 功能时,你输入的内容(如文本、命令、终端输出或发送给模型的其他数据)会被传输给你所配置的第三方大模型服务商。该服务商可能根据其自身隐私政策收集、存储并使用这些内容。electerm 无法控制,也不对第三方服务商如何处理你的数据负责。 + +请仔细阅读所选服务商的隐私政策,并在使用 AI 功能时避免发送敏感或机密信息。 + +For full details, see the privacy notice: +https://github.com/electerm/electerm/wiki/privacy-notice-ios`, + SyncTermOfUse: `About data sync / 数据同步说明 + +When you sync your data (such as bookmarks, connection profiles, and notes) using GitHub Gist, Gitee Gist, WebDAV, or a custom sync server, your data is stored in accounts and services you control. This data is private to you and not publicly displayed; electerm does not collect, host, or have access to it. Data handling for these services is governed by the respective provider's privacy policy. + +Please review the privacy policy of the sync service you choose. + +当你使用 GitHub Gist、Gitee Gist、WebDAV 或自定义同步服务器进行同步时,你的数据(如书签、连接配置、笔记等)存储在你自己掌控的账户与服务中,仅你本人可见,electerm 不收集、不托管、也无法访问这些数据。这些服务的数据处理由其服务商隐私政策决定。 + +请仔细阅读所选同步服务的隐私政策。 + +For full details, see the privacy notice: +https://github.com/electerm/electerm/wiki/privacy-notice-ios` } const { ENABLE_AUTH diff --git a/build/replace/src/client/entry-web/basic.js b/build/replace/src/client/entry-web/basic.js new file mode 100644 index 0000000..f6193e6 --- /dev/null +++ b/build/replace/src/client/entry-web/basic.js @@ -0,0 +1,109 @@ +/** + * init app data then write main script to html body + */ +import '../electerm-react/css/basic.styl' +import '../web-components/style-overide.styl' +import '../electerm-react/css/mobile.styl' +import '../web-components/web-api.js' +import '../web-components/web-pre.js' +import { get as _get } from 'lodash-es' + +// iOS WKWebView has no requestIdleCallback. bookmark-form's save path wraps +// addItem/editItem in runIdle() -> window.requestIdleCallback; without this +// polyfill every save silently throws "undefined is not a function" and the +// bookmark never reaches the store (connect/test paths don't use runIdle, +// which is why those buttons still work). Semantics follow the spec draft: +// call the callback ASAP with a deadline, support options.timeout, return a +// cancellable id. +if (typeof window.requestIdleCallback !== 'function') { + window.requestIdleCallback = function (cb, options) { + const start = Date.now() + return setTimeout(function () { + cb({ + didTimeout: false, + timeRemaining: function () { + return Math.max(0, 50 - (Date.now() - start)) + } + }) + }, options && options.timeout ? 1 : 0) + } + window.cancelIdleCallback = function (id) { + clearTimeout(id) + } +} + +const { isDev, version, cdn } = window.et + +window.et.buildWsUrl = ( + host, + port, + tokenElecterm, + id, + type = 'terminals', + extra = '' +) => { + const ss = isDev ? window.et.server : window.location.href + const s = ss + ? ss.replace(/https?:\/\//, '').replace(/\/$/, '') + : `${host}:${port}` + const pre = ss.startsWith('https') ? 'wss' : 'ws' + return `${pre}://${s}/${type}/${id}?token=${tokenElecterm}${extra}` +} + +async function loadWorker () { + return new Promise((resolve) => { + const url = !isDev ? cdn + `/js/worker-${version}.js` : cdn + '/js/worker.js' + window.worker = new window.Worker(url) + function onInit (e) { + if (!e || !e.data) { + return false + } + const { + action + } = e.data + if (action === 'worker-init') { + window.worker.removeEventListener('message', onInit) + resolve(1) + } + } + window.worker.addEventListener('message', onInit) + }) +} + +async function load () { + window.capitalizeFirstLetter = (string) => { + return string.charAt(0).toUpperCase() + string.slice(1) + } + function loadScript () { + const rcs = document.createElement('script') + const url = !isDev ? cdn + `/js/electerm-${version}.js` : cdn + '/js/electerm.js' + rcs.src = url + rcs.type = 'module' + rcs.onload = () => { + const loadingEl = document.getElementById('content-loading') + if (loadingEl) { + document.body.removeChild(loadingEl) + } + } + document.body.appendChild(rcs) + } + window.getLang = (lang = window.store?.config.language || 'en_us') => { + return _get(window.langMap, `[${lang}].lang`) + } + window.translate = txt => { + const lang = window.getLang() + const str = _get(lang, `[${txt}]`) || txt + return window.capitalizeFirstLetter(str) + } + await loadWorker() + if (!window.et.isDev) { + window.worker.postMessage({ + action: 'init-url', + url: window.location.href + }) + } + loadScript() +} + +// window.addEventListener('load', load) +load() diff --git a/package-lock.json b/package-lock.json index 862d472..8f983f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "electerm-ios", - "version": "5.2.0", + "version": "5.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "electerm-ios", - "version": "5.2.0", + "version": "5.3.0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -15,7 +15,7 @@ "@electerm/ftp-srv": "1.0.5", "@electerm/nedb": "^2.0.0", "@electerm/ssh2": "1.22.0", - "@xterm/headless": "6.1.0-beta.301", + "@xterm/headless": "6.1.0-beta.292", "axios": "1.18.1", "basic-ftp": "6.0.1", "dayjs": "^1.11.21", @@ -56,21 +56,21 @@ }, "devDependencies": { "@ant-design/icons": "^6.2.5", - "@electerm/electerm-react": "^5.2.0", + "@electerm/electerm-react": "^5.3.0", "@electerm/electerm-resource": "2.3.0", "@fontsource/maple-mono": "^5.2.6", "@novnc/novnc": "^1.7.0", "@types/node": "22.9.3", "@vitejs/plugin-react": "5.2.0", - "@xterm/addon-attach": "0.13.0-beta.301", - "@xterm/addon-fit": "0.12.0-beta.299", - "@xterm/addon-image": "0.10.0-beta.299", - "@xterm/addon-ligatures": "0.11.0-beta.299", - "@xterm/addon-search": "0.17.0-beta.299", - "@xterm/addon-unicode11": "0.10.0-beta.299", - "@xterm/addon-web-links": "0.13.0-beta.299", - "@xterm/addon-webgl": "0.20.0-beta.298", - "@xterm/xterm": "6.1.0-beta.302", + "@xterm/addon-attach": "0.13.0-beta.292", + "@xterm/addon-fit": "0.12.0-beta.292", + "@xterm/addon-image": "0.10.0-beta.292", + "@xterm/addon-ligatures": "0.11.0-beta.292", + "@xterm/addon-search": "0.17.0-beta.292", + "@xterm/addon-unicode11": "0.10.0-beta.292", + "@xterm/addon-web-links": "0.13.0-beta.292", + "@xterm/addon-webgl": "0.20.0-beta.291", + "@xterm/xterm": "6.1.0-beta.292", "antd": "^6.5.1", "classnames": "2.5.1", "cross-env": "7.0.3", @@ -499,9 +499,9 @@ "license": "MIT" }, "node_modules/@electerm/electerm-react": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@electerm/electerm-react/-/electerm-react-5.2.0.tgz", - "integrity": "sha512-t/jqP7Sckzru3/vAx+vbyLIvWpGYPzCZB6lfgtX4ZvT6lEZbpd8MazlmKPAAltksTbARgauii+ApYefN0LD1wg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@electerm/electerm-react/-/electerm-react-5.3.0.tgz", + "integrity": "sha512-QB4QhhBeG0sjC0y4KuAZoYoyXTI9qg26AJzGgtD5u+WAhKqgeWBpojjJwQ6ajxLsVhW996mVVfXhGVyWbgVqNw==", "dev": true, "license": "MIT", "engines": { @@ -3129,39 +3129,39 @@ } }, "node_modules/@xterm/addon-attach": { - "version": "0.13.0-beta.301", - "resolved": "https://registry.npmjs.org/@xterm/addon-attach/-/addon-attach-0.13.0-beta.301.tgz", - "integrity": "sha512-SBYvevWBTlIkIBksblA9sMDcCGHtzviU2blddR8SiAIZMlbFTA0oXflHu2vVrlzqoorD3t0xKnknklXfG/6sOA==", + "version": "0.13.0-beta.292", + "resolved": "https://registry.npmjs.org/@xterm/addon-attach/-/addon-attach-0.13.0-beta.292.tgz", + "integrity": "sha512-Yxxs5n61bhvbStTjLVX7o+b3pHVn0KydqPr3J86JykQeYwRqFBZKzAcQp2wjf/f5Eo5I6GIw8c647KuWyJk5YA==", "dev": true, "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^6.1.0-beta.301" + "@xterm/xterm": "^6.1.0-beta.292" } }, "node_modules/@xterm/addon-fit": { - "version": "0.12.0-beta.299", - "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.12.0-beta.299.tgz", - "integrity": "sha512-LnofeCMLCf4e3eHN6qz27OdDgcNVh/L2oMqCHHgKraNTCGyKmf1BFWQczFF4PEg63LQvNFiItK62YOQhzDyHMw==", + "version": "0.12.0-beta.292", + "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.12.0-beta.292.tgz", + "integrity": "sha512-SIuWR0KM2IpmumVqL4L43aOUeTEUeN82ItyrUFHGFtfj3veoAIbPapxJPj7O0tYngfiiHZqqm1+XsZp/Fc8LLA==", "dev": true, "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^6.1.0-beta.301" + "@xterm/xterm": "^6.1.0-beta.292" } }, "node_modules/@xterm/addon-image": { - "version": "0.10.0-beta.299", - "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.10.0-beta.299.tgz", - "integrity": "sha512-odxXWWAKh2KRIUgXTvQejzkzlvIbpV3aepkkS6uaQKUVYf9HUqWEhECUsUvm2pMgZtqLqGuhmynw/qvKWmHrBQ==", + "version": "0.10.0-beta.292", + "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.10.0-beta.292.tgz", + "integrity": "sha512-kFhxNiZ5eU1acMYvp/aS0wYs2wJ3j/ueq54FSNnWwnchirOuAVQxxdlFdxlZFHVLSas7rijqaRN1dniN+30HGQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^6.1.0-beta.301" + "@xterm/xterm": "^6.1.0-beta.292" } }, "node_modules/@xterm/addon-ligatures": { - "version": "0.11.0-beta.299", - "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.11.0-beta.299.tgz", - "integrity": "sha512-+LQqYRdsrBeVLsqizO6whEpHlSUKjJWp53mf4m+9ynDTAXu2YcGB33h4etby8lDLUsh/vXeLZPW4U2rZWK1ILg==", + "version": "0.11.0-beta.292", + "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.11.0-beta.292.tgz", + "integrity": "sha512-C9DaNn/E1SJh+gULgtT8Js2fz/8QIJ1LvmDXsMMayzvrL72g1kvFOYZSXAcmYveID3eIOIQKyecStfvFR7HU6A==", "dev": true, "license": "MIT", "dependencies": { @@ -3172,7 +3172,7 @@ "node": ">8.0.0" }, "peerDependencies": { - "@xterm/xterm": "^6.1.0-beta.301" + "@xterm/xterm": "^6.1.0-beta.292" } }, "node_modules/@xterm/addon-ligatures/node_modules/lru-cache": { @@ -3186,58 +3186,58 @@ } }, "node_modules/@xterm/addon-search": { - "version": "0.17.0-beta.299", - "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.17.0-beta.299.tgz", - "integrity": "sha512-We4bbjOuLY9oZD5WN93P6STqwlJg3Q7ECSE4UIuzEmWG009yEu4di5HPW/8u7UERUdrg0+8Ds+wGWrDR0687jw==", + "version": "0.17.0-beta.292", + "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.17.0-beta.292.tgz", + "integrity": "sha512-F12brJvBETblxh7NGu9RmHwcavcJJvd9RWjPID+WZg9mJcFucDjZTOSrWZyWRPCn/+8NWadsFAQynFFmBMo2Ng==", "dev": true, "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^6.1.0-beta.301" + "@xterm/xterm": "^6.1.0-beta.292" } }, "node_modules/@xterm/addon-unicode11": { - "version": "0.10.0-beta.299", - "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.10.0-beta.299.tgz", - "integrity": "sha512-BShRMWsKqoHs9fm0L96zjC4Du5L19bvmdZffm5LPKLbVWUAZj7cjjbpXuFU9FsITIJlvjTqeNfq1vulv60zRDA==", + "version": "0.10.0-beta.292", + "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.10.0-beta.292.tgz", + "integrity": "sha512-2Qw4ET+eq+rP07khdPkjwZd60+QZ8i5zI2iiVZGlghSvRtuujgrhXeYf1B5Pu4KNpmrOnZERLOyeoH/VW5xV4g==", "dev": true, "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^6.1.0-beta.301" + "@xterm/xterm": "^6.1.0-beta.292" } }, "node_modules/@xterm/addon-web-links": { - "version": "0.13.0-beta.299", - "resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.13.0-beta.299.tgz", - "integrity": "sha512-br9eKXtyRVcYelnmnjgZChlMTV+ut0gnwIVSCabxDw1zCe247R7bIgGeWOz9dYmrfA61JM4FdfjLWhdsKydXzg==", + "version": "0.13.0-beta.292", + "resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.13.0-beta.292.tgz", + "integrity": "sha512-1k3i3N8Jm0ZU9oQD5X9WNiWOMRkHFkgFZT9ZoUNHteBksrUbWGVnjZLXxRBfhvYUPYD5pzwrq/i6OtQzggJRXA==", "dev": true, "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^6.1.0-beta.301" + "@xterm/xterm": "^6.1.0-beta.292" } }, "node_modules/@xterm/addon-webgl": { - "version": "0.20.0-beta.298", - "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.20.0-beta.298.tgz", - "integrity": "sha512-65jZWGSV3nu2jVyc/r2H31Q+oXnDX8IhcSquREVlDjqmfOINXhAufBj2zcK6BCgYT0jrdx7y64VFgVcQ3vAkRA==", + "version": "0.20.0-beta.291", + "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.20.0-beta.291.tgz", + "integrity": "sha512-gH7r5g8f2NWMhBtaeApuwLQTJmX4uq7zT0okjeNWkFAD0nxzbUPB+kt6sogZZ5K90XYPt2OLu/bhuvF6DmKqOQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^6.1.0-beta.301" + "@xterm/xterm": "^6.1.0-beta.292" } }, "node_modules/@xterm/headless": { - "version": "6.1.0-beta.301", - "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-6.1.0-beta.301.tgz", - "integrity": "sha512-ApQUwq3BlHA8xlOeBKnC+1l+g95JHVl9bg7EujtUBZA9aKtweyOF9PEd/1larB0c4UF5XAf9lWjj+ICNZNR/1w==", + "version": "6.1.0-beta.292", + "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-6.1.0-beta.292.tgz", + "integrity": "sha512-Es2xZ95wJb8n3hIfTfEh4AYzf7wXVQX1dVdA6idFFjRm26p+x6LZEgurXD6ZPwwsbXSfJXcAuzhYQruSw9Ccgg==", "license": "MIT", "workspaces": [ "addons/*" ] }, "node_modules/@xterm/xterm": { - "version": "6.1.0-beta.302", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.1.0-beta.302.tgz", - "integrity": "sha512-yTlcgFDNe0ZE7U1RA1JX9oZkVOE8gKvLLh55tMHrS3/ZHkJCOWHlC0mFt3GYyWChSQ1XF+VY0iIme7ZktSaMRA==", + "version": "6.1.0-beta.292", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.1.0-beta.292.tgz", + "integrity": "sha512-17zqK5tM/l6qeD7McF42OrEJ6w3XqJ2vFVKdWqu0cYLzdFqMWAHp2oFNc8Fj5DmqDSl1E1FZEg6IFflDllTvLA==", "dev": true, "license": "MIT", "workspaces": [ diff --git a/package.json b/package.json index 27f4c1c..3c81a0e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electerm-ios", - "version": "5.2.0", + "version": "5.3.0", "description": "electerm for iOS — a free and open-source ssh/sftp/telnet/RDP/VNC/Spice/ftp client, built on the electerm-web codebase with Capacitor.", "main": "src/app/app.js", "type": "module", @@ -25,7 +25,7 @@ }, "license": "MIT", "languageRepo": "https://github.com/electerm/electerm-locales", - "privacyNoticeLink": "https://github.com/electerm/electerm/wiki/privacy-notice", + "privacyNoticeLink": "https://github.com/electerm/electerm/wiki/privacy-notice-ios", "knownIssuesLink": "https://github.com/electerm/electerm/wiki/Know-issues", "sponsorLink": "https://electerm.org/sponsor-electerm.html", "repository": { @@ -48,21 +48,21 @@ "preferGlobal": true, "devDependencies": { "@ant-design/icons": "^6.2.5", - "@electerm/electerm-react": "^5.2.0", + "@electerm/electerm-react": "^5.3.0", "@electerm/electerm-resource": "2.3.0", "@fontsource/maple-mono": "^5.2.6", "@novnc/novnc": "^1.7.0", "@types/node": "22.9.3", "@vitejs/plugin-react": "5.2.0", - "@xterm/addon-attach": "0.13.0-beta.301", - "@xterm/addon-fit": "0.12.0-beta.299", - "@xterm/addon-image": "0.10.0-beta.299", - "@xterm/addon-ligatures": "0.11.0-beta.299", - "@xterm/addon-search": "0.17.0-beta.299", - "@xterm/addon-unicode11": "0.10.0-beta.299", - "@xterm/addon-web-links": "0.13.0-beta.299", - "@xterm/addon-webgl": "0.20.0-beta.298", - "@xterm/xterm": "6.1.0-beta.302", + "@xterm/addon-attach": "0.13.0-beta.292", + "@xterm/addon-fit": "0.12.0-beta.292", + "@xterm/addon-image": "0.10.0-beta.292", + "@xterm/addon-ligatures": "0.11.0-beta.292", + "@xterm/addon-search": "0.17.0-beta.292", + "@xterm/addon-unicode11": "0.10.0-beta.292", + "@xterm/addon-web-links": "0.13.0-beta.292", + "@xterm/addon-webgl": "0.20.0-beta.291", + "@xterm/xterm": "6.1.0-beta.292", "antd": "^6.5.1", "classnames": "2.5.1", "cross-env": "7.0.3", @@ -91,7 +91,7 @@ "@electerm/ftp-srv": "1.0.5", "@electerm/nedb": "^2.0.0", "@electerm/ssh2": "1.22.0", - "@xterm/headless": "6.1.0-beta.301", + "@xterm/headless": "6.1.0-beta.292", "axios": "1.18.1", "basic-ftp": "6.0.1", "dayjs": "^1.11.21",