├── app ├── lib │ ├── testUrlByDNS.js │ ├── sudoCallSetHosts.js │ ├── sudoCallResetHosts.js │ ├── resetHosts.js │ ├── setHosts.js │ ├── host2ips.js │ ├── loadHostsInfo.js │ ├── testUrl.js │ ├── sudoUtils.js │ ├── getBestHosts.js │ └── raceIps.js ├── .prettierrc ├── shims │ └── performance.js ├── package.json ├── build.js ├── build-bun.js ├── index.js ├── bun.lock └── package-lock.json ├── logo.png ├── FigmaNetOK演示2.gif ├── FigmaNetOK-CLI演示.gif ├── FigmaNetOK-CLI演示2.gif ├── .gitignore └── readme.md /app/lib/testUrlByDNS.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Moonvy/Figma-Net-OK/HEAD/logo.png -------------------------------------------------------------------------------- /FigmaNetOK演示2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Moonvy/Figma-Net-OK/HEAD/FigmaNetOK演示2.gif -------------------------------------------------------------------------------- /FigmaNetOK-CLI演示.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Moonvy/Figma-Net-OK/HEAD/FigmaNetOK-CLI演示.gif -------------------------------------------------------------------------------- /FigmaNetOK-CLI演示2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Moonvy/Figma-Net-OK/HEAD/FigmaNetOK-CLI演示2.gif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .idea 3 | node_modules 4 | __debug__ 5 | yarn-error.log 6 | .DS_Store 7 | tsconfig.tsbuildinfo 8 | -------------------------------------------------------------------------------- /app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "tabWidth": 4, 4 | "bracketSpacing": true, 5 | "semi": false 6 | } 7 | -------------------------------------------------------------------------------- /app/lib/sudoCallSetHosts.js: -------------------------------------------------------------------------------- 1 | const { sudoExecScript } = require("./sudoUtils") 2 | 3 | function sudoCallSetHosts(hosts) { 4 | sudoExecScript("setHosts.js", hosts) 5 | } 6 | 7 | module.exports = sudoCallSetHosts 8 | -------------------------------------------------------------------------------- /app/lib/sudoCallResetHosts.js: -------------------------------------------------------------------------------- 1 | const { sudoExecScript } = require("./sudoUtils") 2 | 3 | function sudoCallResetHosts(hosts) { 4 | sudoExecScript("resetHosts.js", hosts) 5 | } 6 | 7 | module.exports = sudoCallResetHosts 8 | -------------------------------------------------------------------------------- /app/shims/performance.js: -------------------------------------------------------------------------------- 1 | // 关闭弃用警告 2 | process.noDeprecation = true; 3 | 4 | // Polyfill for Node.js v12 which doesn't have global performance 5 | if (typeof performance === 'undefined') { 6 | try { 7 | const { performance: perf } = require('perf_hooks'); 8 | globalThis.performance = perf; 9 | } catch (e) { 10 | // Fallback if perf_hooks is not available 11 | globalThis.performance = { 12 | now: function() { 13 | const [sec, nsec] = process.hrtime(); 14 | return sec * 1000 + nsec / 1000000; 15 | } 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "figma-net-ok", 3 | "version": "2.5.0", 4 | "description": "", 5 | "main": "index.js", 6 | "bin": "index.js", 7 | "scripts": { 8 | "build": "bun run build.js && npx cosynode dist ../dist --name FigmaNetOK -n 12", 9 | "build:bun": "bun run build-bun.js", 10 | "run": "node ./index.js", 11 | "zip": "cd .. && zip -q -r ./dist/[Windows]FigmaNetOK_v$npm_package_version.zip ./dist/windows/ && zip -q -r ./dist/[MacOS]FigmaNetOK_v$npm_package_version.zip ./dist/macos/" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "axios": "^1.13.2", 17 | "chalk": "^4.1.2", 18 | "dns-lookup": "^0.1.0", 19 | "hostile": "^1.3.3", 20 | "nslookup": "^1.1.1", 21 | "ora": "^5.4.1", 22 | "ping": "^0.4.1", 23 | "prompts": "^2.4.2", 24 | "sudo-prompt": "^9.2.1" 25 | }, 26 | "devDependencies": { 27 | "esbuild": "0.27.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/build.js: -------------------------------------------------------------------------------- 1 | import { rmSync, mkdirSync, readFileSync } from "fs"; 2 | import { build } from "esbuild"; 3 | 4 | // 读取 package.json 中的版本号 5 | const pkg = JSON.parse(readFileSync("./package.json", "utf-8")); 6 | const VERSION = pkg.version; 7 | 8 | console.log(`Building version: ${VERSION}`); 9 | 10 | // 清空 dist 目录 11 | const distDir = "./dist"; 12 | const outputDir = "../dist"; 13 | 14 | rmSync(distDir, { recursive: true, force: true }); 15 | rmSync(outputDir, { recursive: true, force: true }); 16 | mkdirSync(distDir, { recursive: true }); 17 | mkdirSync(outputDir, { recursive: true }); 18 | 19 | // 打包主入口 20 | await build({ 21 | entryPoints: ["./index.js"], 22 | outfile: "./dist/index.js", 23 | bundle: true, 24 | platform: "node", 25 | target: "node12", 26 | format: "cjs", 27 | minify: true, 28 | inject: ["./shims/performance.js"], 29 | define: { 30 | __VERSION__: JSON.stringify(VERSION), 31 | }, 32 | }); 33 | 34 | // 打包需要单独调用的脚本(用于 sudo 提权执行) 35 | // 输出到 dist/lib 目录,保持与源码目录结构一致 36 | await build({ 37 | entryPoints: ["./lib/setHosts.js", "./lib/resetHosts.js"], 38 | outdir: "./dist/lib", 39 | bundle: true, 40 | platform: "node", 41 | target: "node12", 42 | format: "cjs", 43 | minify: true, 44 | inject: ["./shims/performance.js"], 45 | }); 46 | 47 | console.log("Build completed!"); 48 | -------------------------------------------------------------------------------- /app/lib/resetHosts.js: -------------------------------------------------------------------------------- 1 | const hostile = require("hostile") 2 | const chalk = require("chalk") 3 | const { promisify } = require("util") 4 | 5 | /** 6 | * 重置 hosts 7 | * @param {string[]} hosts 8 | */ 9 | async function resetHosts(hosts) { 10 | console.log("\n") 11 | console.log(chalk.blue("Hosts 文件位置:" + hostile.HOSTS)) 12 | let removeHost = await promisify(hostile.remove) 13 | let getHost = await promisify(hostile.get) 14 | 15 | try { 16 | for (const host of hosts) { 17 | await remove(host) 18 | } 19 | console.log(chalk.green("重置完成")) 20 | } catch (e) { 21 | if (e.message.includes("EACCES")) { 22 | console.error(chalk.yellow("没有权限。修改 Hosts 需要管理员权限,请以管理员权限运行本程序")) 23 | } 24 | } 25 | 26 | async function remove(host) { 27 | var lines = await getHost(false) 28 | for (const item of lines) { 29 | if (item[1] === host) { 30 | await removeHost(item[0], host) 31 | console.log("清除", chalk.greenBright(`${host} (${item[0]})`)) 32 | } 33 | } 34 | } 35 | } 36 | 37 | let cmd = process.argv[2] 38 | 39 | try { 40 | let hosts = JSON.parse(Buffer.from(cmd, "base64").toString()) 41 | resetHosts(hosts) 42 | } catch (e) { 43 | console.error(chalk.yellow("调用 resetHosts 参数错误。"), process.argv, e) 44 | } 45 | 46 | module.exports = resetHosts 47 | -------------------------------------------------------------------------------- /app/lib/setHosts.js: -------------------------------------------------------------------------------- 1 | const hostile = require("hostile") 2 | const chalk = require("chalk") 3 | const { promisify } = require("util") 4 | 5 | async function setHosts(hosts) { 6 | console.log("\n") 7 | console.log(chalk.blue("Hosts 文件位置:" + hostile.HOSTS)) 8 | 9 | let setHost = await promisify(hostile.set) 10 | let removeHost = await promisify(hostile.remove) 11 | 12 | try { 13 | for (const host of hosts) { 14 | if (host.remove) { 15 | console.log(chalk.yellow("清除"), chalk.yellow(host.ip)) 16 | await removeHost(host.ip) 17 | } else { 18 | console.log(chalk.blue("设置"), chalk.blue(host.ip), chalk.blue(host.hostname)) 19 | await setHost(host.ip, host.hostname) 20 | } 21 | } 22 | console.log(chalk.green("设置完成")) 23 | } catch (e) { 24 | if (e.message.includes("EACCES")) { 25 | console.error(chalk.yellow("没有权限。修改 Hosts 需要管理员权限,请以管理员权限运行本程序")) 26 | } 27 | } 28 | } 29 | 30 | // console.log(process.argv) 31 | let cmd = process.argv[2] 32 | 33 | try { 34 | let hosts = JSON.parse(Buffer.from(cmd, "base64").toString()) 35 | setHosts(hosts) 36 | } catch (e) { 37 | console.error(chalk.yellow("调用 setHosts 参数错误。"), process.argv, e) 38 | } 39 | 40 | // setHosts([{ ip: "127.0.0.1", hostname: "peercdn.com" }]) 41 | 42 | module.exports = setHosts 43 | -------------------------------------------------------------------------------- /app/build-bun.js: -------------------------------------------------------------------------------- 1 | import { rmSync, mkdirSync, readFileSync } from "fs"; 2 | import { $ } from "bun"; 3 | 4 | // 读取 package.json 中的版本号 5 | const pkg = JSON.parse(readFileSync("./package.json", "utf-8")); 6 | const VERSION = pkg.version; 7 | 8 | console.log(`Building version: ${VERSION}`); 9 | 10 | // 清空 dist 目录 11 | const distDir = "./dist"; 12 | const outputDir = "../dist"; 13 | 14 | rmSync(distDir, { recursive: true, force: true }); 15 | rmSync(outputDir, { recursive: true, force: true }); 16 | mkdirSync(distDir, { recursive: true }); 17 | mkdirSync(outputDir, { recursive: true }); 18 | 19 | // 定义目标平台 20 | const targets = [ 21 | { name: "macos-x64", target: "bun-darwin-x64" }, 22 | { name: "windows-x64", target: "bun-windows-x64" }, 23 | ]; 24 | 25 | // 使用 Bun 打包成二进制文件 26 | for (const { name, target } of targets) { 27 | const isWindows = name.startsWith("windows"); 28 | const outputPath = `${outputDir}/${name}/FigmaNetOK${isWindows ? ".exe" : ""}`; 29 | 30 | console.log(`\n📦 Building for ${name}...`); 31 | 32 | try { 33 | await $`bun build ./index.js --compile --target=${target} --outfile=${outputPath} --minify --bytecode --define:__VERSION__=${JSON.stringify(JSON.stringify(VERSION))}`; 34 | console.log(`✅ Built: ${outputPath}`); 35 | 36 | // 对 Windows 可执行文件使用 UPX 压缩 37 | if (isWindows) { 38 | console.log(`🗜️ Compressing ${name} with UPX...`); 39 | try { 40 | await $`upx --best --lzma ${outputPath}`; 41 | console.log(`✅ Compressed: ${outputPath}`); 42 | } catch (upxError) { 43 | console.warn(`⚠️ UPX compression failed (make sure UPX is installed): ${upxError.message}`); 44 | } 45 | } 46 | } catch (error) { 47 | console.error(`❌ Failed to build for ${name}:`, error.message); 48 | } 49 | } 50 | 51 | console.log("\n🎉 Build completed!"); 52 | -------------------------------------------------------------------------------- /app/lib/host2ips.js: -------------------------------------------------------------------------------- 1 | const nslookup = require("nslookup") 2 | 3 | // Spinner 消息队列,确保每条消息有足够展示时间 4 | const spinnerQueue = [] 5 | let isProcessingQueue = false 6 | let queueFinishResolvers = [] // 用于通知等待者队列已清空 7 | const MIN_DISPLAY_TIME = 150 // 每条消息最少展示 150ms 8 | 9 | async function processSpinnerQueue() { 10 | if (isProcessingQueue) return 11 | isProcessingQueue = true 12 | 13 | while (spinnerQueue.length > 0) { 14 | const message = spinnerQueue.shift() 15 | spinner.start(message) 16 | await new Promise((resolve) => setTimeout(resolve, MIN_DISPLAY_TIME)) 17 | } 18 | 19 | isProcessingQueue = false 20 | // 通知所有等待者队列已清空 21 | queueFinishResolvers.forEach((resolve) => resolve()) 22 | queueFinishResolvers = [] 23 | } 24 | 25 | function queueSpinnerMessage(message) { 26 | spinnerQueue.push(message) 27 | processSpinnerQueue() 28 | } 29 | 30 | /** 等待 spinner 队列处理完成 */ 31 | function waitForSpinnerQueue() { 32 | if (!isProcessingQueue && spinnerQueue.length === 0) { 33 | return Promise.resolve() 34 | } 35 | return new Promise((resolve) => { 36 | queueFinishResolvers.push(resolve) 37 | }) 38 | } 39 | 40 | /** 通过 DNS 解析域名的 IP, 返回 IP 列表 */ 41 | async function host2ips(hostname, dnsServer, serverName) { 42 | queueSpinnerMessage(`DNS [${hostname}] by ${serverName}${dnsServer ? ` (${dnsServer})` : ''} `) 43 | let re = await dnsLookup(hostname, dnsServer) 44 | 45 | return re 46 | } 47 | 48 | function dnsLookup(name, server) { 49 | return new Promise((resolve, reject) => { 50 | const lookup = nslookup(name) 51 | if (server) { 52 | lookup.server(server) // 指定 DNS 服务器,不指定则使用系统默认 53 | } 54 | lookup.timeout(3 * 1000) // default is 3 * 1000 ms 55 | lookup.end(function (err, addrs) { 56 | if (err) { 57 | resolve([]) 58 | } else { 59 | // console.log({addrs}) 60 | // console.log(` DNS(${name} by ${server}):`, addrs) 61 | resolve(addrs.filter((x) => x && /./.test(x))) 62 | } 63 | }) 64 | }) 65 | } 66 | 67 | module.exports = host2ips 68 | module.exports.waitForSpinnerQueue = waitForSpinnerQueue 69 | -------------------------------------------------------------------------------- /app/lib/loadHostsInfo.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const os = require("os") 3 | const path = require("path") 4 | 5 | /** 6 | * 获取系统 hosts 文件路径 7 | * @returns {string} hosts 文件路径 8 | */ 9 | function getHostsPath() { 10 | if (os.platform() === "win32") { 11 | return path.join(process.env.SystemRoot || "C:\\Windows", "System32", "drivers", "etc", "hosts") 12 | } 13 | return "/etc/hosts" 14 | } 15 | 16 | /** 17 | * 解析 hosts 文件内容 18 | * @param {string} content hosts 文件内容 19 | * @returns {Array<{ip: string, hostname: string, line: number, raw: string}>} 解析后的条目 20 | */ 21 | function parseHostsContent(content) { 22 | const lines = content.split(/\r?\n/) 23 | const entries = [] 24 | 25 | lines.forEach((line, index) => { 26 | // 去除注释和空白 27 | const trimmed = line.trim() 28 | if (!trimmed || trimmed.startsWith("#")) { 29 | return 30 | } 31 | 32 | // 解析 IP 和主机名 33 | const parts = trimmed.split(/\s+/) 34 | if (parts.length >= 2) { 35 | const ip = parts[0] 36 | // 一行可能有多个主机名 37 | for (let i = 1; i < parts.length; i++) { 38 | const hostname = parts[i] 39 | // 遇到注释就停止 40 | if (hostname.startsWith("#")) break 41 | entries.push({ 42 | ip, 43 | hostname, 44 | line: index + 1, 45 | raw: line, 46 | }) 47 | } 48 | } 49 | }) 50 | 51 | return entries 52 | } 53 | 54 | /** 55 | * 读取并检查系统 hosts 文件中的 Figma 相关配置 56 | * @returns {{ 57 | * hostsPath: string, 58 | * figmaEntries: Array<{ip: string, hostname: string, line: number, raw: string}>, 59 | * hasFigmaConfig: boolean, 60 | * error: string | null 61 | * }} 62 | */ 63 | function loadHostsInfo() { 64 | const hostsPath = getHostsPath() 65 | const result = { 66 | hostsPath, 67 | figmaEntries: [], 68 | hasFigmaConfig: false, 69 | error: null, 70 | } 71 | 72 | try { 73 | const content = fs.readFileSync(hostsPath, "utf-8") 74 | const allEntries = parseHostsContent(content) 75 | 76 | // 过滤 Figma 相关条目 (域名包含 figma) 77 | result.figmaEntries = allEntries.filter((entry) => 78 | entry.hostname.toLowerCase().includes("figma") 79 | ) 80 | result.hasFigmaConfig = result.figmaEntries.length > 0 81 | } catch (err) { 82 | result.error = err.message 83 | } 84 | 85 | return result 86 | } 87 | 88 | module.exports = loadHostsInfo 89 | module.exports.getHostsPath = getHostsPath 90 | module.exports.parseHostsContent = parseHostsContent -------------------------------------------------------------------------------- /app/lib/testUrl.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | const http = require("http") 3 | const https = require("https") 4 | 5 | const staticLookup = (ip, v) => (hostname, opts, cb) => { 6 | // 处理两种调用方式: lookup(hostname, cb) 或 lookup(hostname, opts, cb) 7 | if (typeof opts === 'function') { 8 | cb = opts 9 | opts = {} 10 | } 11 | // 确保 ip 有效 12 | if (!ip) { 13 | cb(new Error(`Invalid IP address: ${ip}`)) 14 | return 15 | } 16 | // 处理 all: true 的情况,需要返回数组 17 | if (opts && opts.all) { 18 | cb(null, [{ address: ip, family: v || 4 }]) 19 | } else { 20 | cb(null, ip, v || 4) 21 | } 22 | } 23 | 24 | const createAgents = (ip) => ({ 25 | httpAgent: new http.Agent({ lookup: staticLookup(ip) }), 26 | httpsAgent: new https.Agent({ lookup: staticLookup(ip) }), 27 | }) 28 | 29 | function testUrl(url, ip, timeout = 5500) { 30 | return new Promise((resolve) => { 31 | let t0 = performance.now() 32 | const agents = createAgents(ip) 33 | axios 34 | .get(url, { 35 | httpAgent: agents.httpAgent, 36 | httpsAgent: agents.httpsAgent, 37 | timeout, 38 | }) 39 | .then((r) => { 40 | let t1 = performance.now() 41 | let t = t1 - t0 42 | // console.log(`[testUrl ok]`, { ip, url, time: t.toFixed(2) }) 43 | resolve(t) 44 | }) 45 | .catch((e) => { 46 | // console.error("[testUrl err]", { ip, url }, e) 47 | resolve(Infinity) 48 | }) 49 | }) 50 | } 51 | 52 | function testUrlNative(url, ip, timeout = 5500) { 53 | return new Promise((resolve) => { 54 | const t0 = performance.now() 55 | const parsedUrl = new URL(url) 56 | const isHttps = parsedUrl.protocol === 'https:' 57 | const lib = isHttps ? https : http 58 | const agent = isHttps 59 | ? new https.Agent({ lookup: staticLookup(ip) }) 60 | : new http.Agent({ lookup: staticLookup(ip) }) 61 | 62 | const req = lib.get(url, { agent, timeout }, (res) => { 63 | // 消费响应数据以完成请求 64 | res.on('data', () => {}) 65 | res.on('end', () => { 66 | const t1 = performance.now() 67 | const t = t1 - t0 68 | // console.log(`[testUrlNative ok]`, { ip, url, time: t.toFixed(2) }) 69 | resolve(t) 70 | }) 71 | }) 72 | 73 | req.on('error', (e) => { 74 | // console.error("[testUrlNative err]", { ip, url }, e) 75 | resolve(Infinity) 76 | }) 77 | 78 | req.on('timeout', () => { 79 | req.destroy() 80 | resolve(Infinity) 81 | }) 82 | }) 83 | } 84 | 85 | module.exports = { testUrl, testUrlNative } 86 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # FigmaNetOK 2 2 | 3 |

4 | 5 |

6 | 7 | 让 Figma 网络速度访问速度更快的方法(尤其是在 🇨🇳 中国) 8 | 9 | - 不使用翻墙 10 | - 仅更改本地 Hosts 配置 11 | - **🔥 2.0 以上版可自动一键修改 Hosts 配置** 12 | 13 | Figma 有不同的服务器,通常你的系统会自动选择 Figma 的服务地址,有些时候因为运营商、Figma 服务状态、DNS 设置等等原因,自动选择的 Figma 服务地址可能不是最好的(有时候可能速度相差 10 倍),所以这个工具能帮你测试在你的环境下所有 Figma 服务地址的真实速度(不是 ping 而是真实连接速度),这样你就可以通过修改 Hosts 的办法指定一个最快的 Figma 服务地址 14 | 15 |

16 | 17 |

18 | 19 | 20 | ## 使用 21 | 22 | ### 下载 (v2.3.0) 23 | 24 | - [发布页](https://github.com/Moonvy/Figma-Net-OK/releases) 25 | - [Windows](https://moonvy.lanzouy.com/i26BY0kja7cj) 26 | - [MacOS](https://moonvy.lanzouy.com/iEqmT0kja5oj) 27 | 28 | #### MacOS 下无法启动的问题 29 | 30 | - **授权设置** 31 | 前往系统偏好设置 > 安全性与隐私 > 允许访问,如果仍然提示无法打开可再次打开允许访问授权 32 | 33 | #### Windows 下无 Hosts 写入权限的问题 34 | 35 | - **解决办法** 36 | [使用手动修改 Hosts 的方式](https://baike.baidu.com/item/hosts/10474546) 37 | 38 | 39 | 40 | 41 | ### 使用步骤 42 | 43 | 1. 解压并运行文件「**FigmaNetOK**」 44 | 2. 测速中,等待一会 45 | 3. 得到最佳线路的 Hosts 配置 46 | - 你可以授予管理员权限一键修改 Hosts 47 | - 也可以把复制运行结果,手动去修改 Hosts 文件 48 | 49 | 50 | 4. 重启 Figma 客户端或浏览器,就完成了 51 | 52 | ### 命令行参数 53 | 54 | 支持通过命令行参数直接执行操作,无需进入交互模式: 55 | 56 | ```bash 57 | FigmaNetOK [选项] 58 | ``` 59 | 60 | | 参数 | 简写 | 说明 | 61 | |------|------|------| 62 | | `--change` | `-C` | 运行快速测试,并自动设置 hosts | 63 | | `--change-all` | `-CA` | 运行全部测试,并自动设置 hosts | 64 | | `--reset` | `-R` | 重置 hosts(清除 Figma 相关配置) | 65 | | `--help` | `-h` | 显示帮助信息 | 66 | 67 | **示例:** 68 | 69 | ```bash 70 | # 快速测试并设置 hosts 71 | ./FigmaNetOK --change 72 | 73 | # 全面测试并设置 hosts 74 | ./FigmaNetOK -CA 75 | 76 | # 重置 hosts 配置 77 | ./FigmaNetOK -R 78 | ``` 79 | 80 | 不带参数运行时会进入交互模式。 81 | 82 | 83 | 84 | 85 | ## 常见问题 86 | 87 | ### 如何确定 Hosts 是否生效 88 | 89 | - **浏览器检查** 90 | 91 | 1. 浏览器窗口右上角「更多」 > 更多工具 > 开发者工具 92 | 2. 刷新网页 93 | 3. 找到参数:Network/state/Remote Addrese:X.X.X.X:XX 和你添加的 Hosts 对比,是相同的,代表已经使用成功 94 |

95 | 96 |

97 | 98 | - **Figma 客户端检查** 99 | 100 | 1. Figma 客户端:右键菜单 > Plugins(插件) > Development(开发) > Open console(控制台) 101 | 2. 刷新页面(在标签上,右键 Reload Tab ) 102 | 3. 找到参数:Network/state/Remote Addrese:X.X.X.X:XX 和你添加的 Hosts 对比,是相同的,代表已经使用成功 103 |

104 | 105 |

106 | 107 | ### 刷新浏览器的 DNS 缓存 108 | 109 | 有些情况下修改 Host 后,因为浏览器有缓存所以没有立即生效,这时候可以手动刷新浏览器缓存 110 | 111 | - **Google Chrome** 112 | 在地址栏输入以下地址 `chrome://net-internals/#dns` 回车,点击 Clear host cache 即可 113 | - **Microsoft Edge** 114 | 在地址栏输入以下地址 `edge://net-internals/#dns` 回车,点击 Clear host cache 即可 115 | - **Safari** 116 | 菜单栏 “Safari 浏览器” –> “偏好设置…” –> “高级”,“在菜单栏中显示 “开发” 菜单。 117 | 此时,点击菜单栏 ”开发“ –> ”清空缓存“ 即可。 118 | 119 | > [参考](https://sysin.org/blog/clear-browser-dns-cache/?__cf_chl_managed_tk__=pmd_qS0UzxTZ9PfLZXDgeWWyQolML5wgzVPc.nF.3ABD_qs-1629715174-0-gqNtZGzNAtCjcnBszQiR) 120 | 121 | 122 | 123 | ### 手动修改 Hosts 124 | 125 | FigmaNetOK 2.0 以后的版本可以支持自动修改 Hosts 了,你不再需要手动去修改 Hosts 文件了。不过如果想要更多了解 Hosts 文件,可以参考以下内容: 126 | 127 | - [「SwitchHosts」](https://swh.app/zh)修改和管理 Hosts 很方便(Mac、Win、Linux 都支持) 128 | - [手动修改 Hosts](https://baike.baidu.com/item/hosts/10474546) 129 | -------------------------------------------------------------------------------- /app/lib/sudoUtils.js: -------------------------------------------------------------------------------- 1 | var sudo = require("sudo-prompt") 2 | var os = require("os") 3 | var fs = require("fs") 4 | const chalk = require("chalk") 5 | const { resolve } = require("path") 6 | 7 | // 智能获取脚本路径(兼容开发和打包环境) 8 | function getScriptPath(scriptName) { 9 | // 开发时:__dirname 是 lib/,脚本在同目录 10 | let scriptPath = resolve(__dirname, scriptName) 11 | if (fs.existsSync(scriptPath)) { 12 | return scriptPath 13 | } 14 | // 打包后:__dirname 是 res/,脚本在 lib/ 子目录 15 | scriptPath = resolve(__dirname, "lib", scriptName) 16 | if (fs.existsSync(scriptPath)) { 17 | return scriptPath 18 | } 19 | // 回退 20 | return resolve(__dirname, scriptName) 21 | } 22 | 23 | // 智能获取 node 可执行文件路径 24 | function getNodePath() { 25 | const paths = ["./node", "./node.exe", "../node", "../node.exe"] 26 | for (const p of paths) { 27 | const nodePath = resolve(__dirname, p) 28 | if (fs.existsSync(nodePath)) return nodePath 29 | } 30 | return "node" 31 | } 32 | 33 | // 检测是否在受限目录中运行 34 | function checkRestrictedDir() { 35 | const isMac = os.platform() === "darwin" 36 | const isWin = os.platform() === "win32" 37 | 38 | if (isMac) { 39 | const sandboxPatterns = ["com.tencent.xinWeChat", "com.tencent.qq", "WeChat", "Library/Containers"] 40 | if (sandboxPatterns.some((p) => __dirname.includes(p))) { 41 | return "微信/QQ 下载目录" 42 | } 43 | } else if (isWin) { 44 | const tempPatterns = ["\\Temp\\", "\\AppData\\Local\\Temp", "\\Temporary"] 45 | if (tempPatterns.some((p) => __dirname.includes(p))) { 46 | return "临时目录(可能是从压缩包直接运行)" 47 | } 48 | } 49 | return null 50 | } 51 | 52 | // 处理 sudo 执行错误 53 | function handleSudoError(error, sudoCmd) { 54 | const isMac = os.platform() === "darwin" 55 | const restrictedReason = checkRestrictedDir() 56 | 57 | // 先输出原始错误,再显示用户友好提示 58 | console.error(error) 59 | 60 | if (restrictedReason) { 61 | console.error(chalk.red(`\n ⚠️ 检测到程序在受限目录中运行(${restrictedReason})\n`)) 62 | console.error(chalk.yellow(" 程序无法在此位置正常获取权限。\n")) 63 | console.error(chalk.green(" 解决方法:请将整个程序文件夹移动到以下位置后重新运行:")) 64 | console.error(chalk.cyan(" • 桌面 (Desktop)")) 65 | console.error(chalk.cyan(" • 下载 (Downloads)")) 66 | console.error(chalk.cyan(" • 或其他普通目录\n")) 67 | } else if (error.message.includes("EPERM")) { 68 | if (isMac) { 69 | console.error( 70 | chalk.red(`\n 无法获取权限,可以尝试手动复制以下命令在「终端」粘贴后中执行:\n\n`), 71 | chalk.green("sudo " + sudoCmd), 72 | "\n\n" 73 | ) 74 | } else { 75 | console.error(chalk.red("\n 无法获取权限,请手动修改 Hosts 文件 \n ")) 76 | } 77 | } else { 78 | console.error(chalk.red("\n 无法获取权限,请手动修改 Hosts 文件 \n ")) 79 | } 80 | } 81 | 82 | // 执行需要管理员权限的脚本 83 | function sudoExecScript(scriptName, data, callback) { 84 | const nodePath = getNodePath() 85 | const scriptPath = resolve(getScriptPath(scriptName)) 86 | const cmd = Buffer.from(JSON.stringify(data)).toString("base64") 87 | 88 | console.log(chalk.yellow("\n 请求管理员权限 \n ")) 89 | 90 | const sudoCmd = `"${nodePath}" "${scriptPath}" ${cmd}` 91 | sudo.exec(sudoCmd, { name: "FigmaNetOK" }, function (error, stdout, stderr) { 92 | if (error) { 93 | handleSudoError(error, sudoCmd) 94 | } 95 | console.log(stdout) 96 | if (callback) callback(error, stdout, stderr) 97 | }) 98 | } 99 | 100 | module.exports = { 101 | getScriptPath, 102 | getNodePath, 103 | checkRestrictedDir, 104 | handleSudoError, 105 | sudoExecScript, 106 | } 107 | -------------------------------------------------------------------------------- /app/lib/getBestHosts.js: -------------------------------------------------------------------------------- 1 | const ora = require("ora") 2 | const chalk = require("chalk") 3 | const host2ips = require("./host2ips") 4 | const { waitForSpinnerQueue } = require("./host2ips") 5 | const raceIps = require("./raceIps") 6 | 7 | const DNSServers = [ 8 | // --- 本地 DNS --- 9 | { ip: null, name: "本地 DNS (系统默认)", fast: true }, 10 | 11 | // --- 国内主流互联网巨头 --- 12 | { ip: "223.5.5.5", name: "阿里 DNS", fast: true }, 13 | { ip: "223.6.6.6", name: "阿里 DNS (备用)", fast: true }, 14 | { ip: "119.29.29.29", name: "腾讯 DNS (DNSPod)", fast: true }, 15 | { ip: "119.28.28.28", name: "腾讯 DNS (备用)"}, 16 | { ip: "180.184.1.1", name: "字节跳动 DNS (火山引擎)", fast: true }, 17 | { ip: "180.184.2.2", name: "字节跳动 DNS (备用)"}, 18 | { ip: "180.76.76.76", name: "百度 DNS" }, 19 | 20 | // --- 专业/机构 DNS --- 21 | { ip: "114.114.114.114", name: "114 DNS", fast: true }, 22 | { ip: "1.2.4.8", name: "CNNIC SDNS" }, 23 | { ip: "210.2.4.8", name: "CNNIC SDNS (备用)" }, 24 | { ip: "101.226.4.6", name: "360 安全 DNS" }, 25 | { ip: "101.6.6.6", name: "清华大学 TUNA DNS" }, 26 | 27 | // --- 海外主流 DNS (国内访问视网络情况而定) --- 28 | { ip: "8.8.8.8", name: "Google DNS" }, 29 | { ip: "8.8.4.4", name: "Google DNS (备用)" }, 30 | { ip: "1.1.1.1", name: "Cloudflare DNS" }, 31 | { ip: "1.0.0.1", name: "Cloudflare DNS (备用)" }, 32 | { ip: "9.9.9.9", name: "Quad9 DNS" }, 33 | { ip: "4.2.2.1", name: "Level3 DNS" }, 34 | 35 | // --- 运营商通用 DNS --- 36 | // --- 中国电信 (China Telecom) --- 37 | { ip: "202.96.128.86", name: "上海电信" }, 38 | { ip: "202.106.0.20", name: "北京电信" }, 39 | 40 | // --- 中国联通 (China Unicom) --- 41 | { ip: "202.106.196.115", name: "北京联通" }, 42 | { ip: "210.22.84.3", name: "上海联通"}, 43 | 44 | // --- 中国移动 (China Mobile) --- 45 | { ip: "211.136.192.6", name: "中国移动" }, 46 | { ip: "211.136.112.50", name: "上海移动" }, 47 | { ip: "211.136.17.107", name: "北京移动" }, 48 | ] 49 | 50 | const Hostnames = [ 51 | { 52 | hostname: "s3-alpha-sig.figma.com", 53 | testUrl: "https://s3-alpha.figma.com/profile/9b3f693e-0677-4743-89ff-822b9f6b72be", 54 | }, 55 | { 56 | hostname: "www.figma.com", 57 | testUrl: "https://www.figma.com/api/statsig/bootstrap?", 58 | }, 59 | { 60 | hostname: "static.figma.com", 61 | testUrl: "https://static.figma.com/app/icon/1/icon-192.png", 62 | }, 63 | ] 64 | 65 | module.exports = async function getBestHosts(mode) { 66 | let dnsList = DNSServers.filter((x) => (mode === "fast" ? x.fast : true)) 67 | global.spinner = ora("🐌").start() 68 | 69 | let bestHost = [] 70 | 71 | let i = 0 72 | let len = Hostnames.length 73 | for (const host of Hostnames) { 74 | i++ 75 | let nowP = chalk.gray(`[${i}/${len}] `) 76 | // 并行请求不同 DNS 服务商 77 | let ips = ( 78 | await Promise.all( 79 | dnsList.map((dnsServer) => 80 | // 单个 DNS 解析失败直接忽略 81 | host2ips(host.hostname, dnsServer.ip, dnsServer.name).catch(() => []) 82 | ) 83 | ) 84 | ).flat() 85 | 86 | // 等待 spinner 队列清空 87 | await waitForSpinnerQueue() 88 | 89 | // 去重 90 | ips = Array.from(new Set(ips)) 91 | spinner.info(`${nowP}${chalk.blueBright(host.hostname)}`.padEnd(50) + ` 找到 ${ips.length} 个服务器`) 92 | 93 | let bestIp = await raceIps(host.testUrl, ips) 94 | 95 | spinner.info( 96 | `${nowP}${chalk.greenBright(host.hostname)}`.padEnd(50) + 97 | ` 最佳服务器: ${bestIp.ip}`.padEnd(22) + 98 | `- ${bestIp.ipInfo} - ${Math.round(bestIp.time)}ms` + 99 | "\n" 100 | ) 101 | 102 | if (bestIp.ip && bestIp.time) { 103 | bestHost.push({ hostname: host.hostname, ip: bestIp.ip }) 104 | } 105 | } 106 | 107 | spinner.succeed(`完毕`) 108 | 109 | console.log(chalk.green("\n\n在此时对于你最佳的 Host 配置是:\n")) 110 | console.log(bestHost.map((x) => `${x.ip}`.padEnd(15) + ` ${x.hostname}`).join("\n")) 111 | console.log("\n\n") 112 | 113 | return bestHost 114 | } 115 | -------------------------------------------------------------------------------- /app/lib/raceIps.js: -------------------------------------------------------------------------------- 1 | const { testUrl, testUrlNative } = require("./testUrl") 2 | const axios = require("axios") 3 | 4 | /** 测速多个 ip */ 5 | module.exports = async function reacIps(url, ips, { concurrency = 10, timeout = 5500, trials = 3 } = {}) { 6 | const uniqueIps = Array.from(new Set(ips)) 7 | if (!uniqueIps.length) { 8 | return { ip: null, time: null, ipInfo: "无可用服务器" } 9 | } 10 | 11 | const shuffledIps = shuffle(uniqueIps) 12 | spinner.start(`🐌 对 ${shuffledIps.length} 个服务器进行并行测速... `) 13 | 14 | const total = shuffledIps.length 15 | let completed = 0 16 | const tasks = shuffledIps.map((ip) => async () => { 17 | const times = [] 18 | for (let i = 0; i < trials; i += 1) { 19 | times.push(await testUrlNative(url, ip, timeout)) 20 | } 21 | 22 | const time = averageFinite(times) 23 | completed += 1 24 | spinner.start(`🐌 [${completed}/${total}] ${ip} \t ${Math.round(time)}ms`) 25 | return { ip, time } 26 | }) 27 | 28 | const results = await runWithConcurrency(tasks, concurrency) 29 | const bestIp = results 30 | .filter((x) => Number.isFinite(x.time)) 31 | .reduce((best, cur) => (!best || cur.time < best.time ? cur : best), null) 32 | 33 | if (!bestIp || !bestIp.ip) { 34 | return { ip: null, time: null, ipInfo: "无可用服务器" } 35 | } 36 | 37 | bestIp.ipInfo = await getIpInfo(bestIp.ip) 38 | return bestIp 39 | } 40 | 41 | function shuffle(arr) { 42 | const res = arr.slice() 43 | for (let i = res.length - 1; i > 0; i -= 1) { 44 | const j = Math.floor(Math.random() * (i + 1)) 45 | ;[res[i], res[j]] = [res[j], res[i]] 46 | } 47 | return res 48 | } 49 | 50 | function averageFinite(arr) { 51 | const finite = arr.filter((x) => Number.isFinite(x)) 52 | if (!finite.length) return Infinity 53 | const sum = finite.reduce((s, v) => s + v, 0) 54 | return sum / finite.length 55 | } 56 | 57 | async function runWithConcurrency(tasks, concurrency) { 58 | const results = [] 59 | let index = 0 60 | 61 | const worker = async () => { 62 | while (index < tasks.length) { 63 | const current = tasks[index] 64 | index += 1 65 | results.push(await current()) 66 | } 67 | } 68 | 69 | const workers = Array.from({ length: Math.min(concurrency, tasks.length) }, worker) 70 | await Promise.all(workers) 71 | return results 72 | } 73 | 74 | async function getIpInfo(ip) { 75 | try { 76 | let re = await axios.get(`https://api.ip.sb/geoip/${ip}`, { 77 | timeout: 2000, 78 | }) 79 | let data = re.data 80 | return translateLocation(data?.country, data?.city) 81 | } catch (e) { 82 | // console.error("ipInfo", e, e.response?.data) 83 | return `未知地区` 84 | } 85 | } 86 | 87 | // ----------- 88 | // 常见国家/地区英文名转中文映射表 89 | const countryMap = { 90 | "United States": "美国", 91 | USA: "美国", 92 | China: "中国", 93 | "Hong Kong": "香港", 94 | Taiwan: "台湾", 95 | Japan: "日本", 96 | "South Korea": "韩国", 97 | Korea: "韩国", 98 | Singapore: "新加坡", 99 | Germany: "德国", 100 | France: "法国", 101 | "United Kingdom": "英国", 102 | UK: "英国", 103 | Netherlands: "荷兰", 104 | Australia: "澳大利亚", 105 | Canada: "加拿大", 106 | Russia: "俄罗斯", 107 | India: "印度", 108 | Brazil: "巴西", 109 | Ireland: "爱尔兰", 110 | Sweden: "瑞典", 111 | Finland: "芬兰", 112 | Norway: "挪威", 113 | Denmark: "丹麦", 114 | Switzerland: "瑞士", 115 | Italy: "意大利", 116 | Spain: "西班牙", 117 | Poland: "波兰", 118 | Belgium: "比利时", 119 | Austria: "奥地利", 120 | "Czech Republic": "捷克", 121 | Romania: "罗马尼亚", 122 | Hungary: "匈牙利", 123 | Ukraine: "乌克兰", 124 | Turkey: "土耳其", 125 | Israel: "以色列", 126 | Thailand: "泰国", 127 | Vietnam: "越南", 128 | Malaysia: "马来西亚", 129 | Indonesia: "印度尼西亚", 130 | Philippines: "菲律宾", 131 | "New Zealand": "新西兰", 132 | "South Africa": "南非", 133 | Mexico: "墨西哥", 134 | Argentina: "阿根廷", 135 | Chile: "智利", 136 | Colombia: "哥伦比亚", 137 | } 138 | 139 | // 常见城市英文名转中文映射表 140 | const cityMap = { 141 | Beijing: "北京", 142 | Shanghai: "上海", 143 | Guangzhou: "广州", 144 | Shenzhen: "深圳", 145 | Hangzhou: "杭州", 146 | Tokyo: "东京", 147 | Osaka: "大阪", 148 | Seoul: "首尔", 149 | Busan: "釜山", 150 | London: "伦敦", 151 | Paris: "巴黎", 152 | Berlin: "柏林", 153 | Frankfurt: "法兰克福", 154 | Amsterdam: "阿姆斯特丹", 155 | Sydney: "悉尼", 156 | Melbourne: "墨尔本", 157 | Toronto: "多伦多", 158 | Vancouver: "温哥华", 159 | Moscow: "莫斯科", 160 | Mumbai: "孟买", 161 | "New Delhi": "新德里", 162 | Bangkok: "曼谷", 163 | "Ho Chi Minh City": "胡志明市", 164 | "Kuala Lumpur": "吉隆坡", 165 | Jakarta: "雅加达", 166 | Manila: "马尼拉", 167 | "Los Angeles": "洛杉矶", 168 | "San Francisco": "旧金山", 169 | "New York": "纽约", 170 | Chicago: "芝加哥", 171 | Seattle: "西雅图", 172 | Dallas: "达拉斯", 173 | Miami: "迈阿密", 174 | Atlanta: "亚特兰大", 175 | "San Jose": "圣何塞", 176 | Phoenix: "凤凰城", 177 | Denver: "丹佛", 178 | Boston: "波士顿", 179 | Washington: "华盛顿", 180 | Ashburn: "阿什本", 181 | Dublin: "都柏林", 182 | Stockholm: "斯德哥尔摩", 183 | Helsinki: "赫尔辛基", 184 | Oslo: "奥斯陆", 185 | Copenhagen: "哥本哈根", 186 | Zurich: "苏黎世", 187 | Geneva: "日内瓦", 188 | Milan: "米兰", 189 | Rome: "罗马", 190 | Madrid: "马德里", 191 | Barcelona: "巴塞罗那", 192 | Warsaw: "华沙", 193 | Brussels: "布鲁塞尔", 194 | Vienna: "维也纳", 195 | Prague: "布拉格", 196 | Bucharest: "布加勒斯特", 197 | Budapest: "布达佩斯", 198 | Kyiv: "基辅", 199 | Istanbul: "伊斯坦布尔", 200 | "Tel Aviv": "特拉维夫", 201 | "Cape Town": "开普敦", 202 | Johannesburg: "约翰内斯堡", 203 | "Mexico City": "墨西哥城", 204 | "São Paulo": "圣保罗", 205 | "Sao Paulo": "圣保罗", 206 | "Rio de Janeiro": "里约热内卢", 207 | "Buenos Aires": "布宜诺斯艾利斯", 208 | Santiago: "圣地亚哥", 209 | Bogotá: "波哥大", 210 | Bogota: "波哥大", 211 | Auckland: "奥克兰", 212 | } 213 | 214 | function translateLocation(country, city) { 215 | const cnCountry = countryMap[country] || country || "" 216 | const cnCity = cityMap[city] || city || "" 217 | 218 | return [cnCountry, cnCity].filter(Boolean).join("/") 219 | } 220 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | const prompts = require("prompts") 2 | const getBestHosts = require("./lib/getBestHosts") 3 | const sudoCallResetHosts = require("./lib/sudoCallResetHosts") 4 | const sudoCallSetHosts = require("./lib/sudoCallSetHosts") 5 | const loadHostsInfo = require("./lib/loadHostsInfo") 6 | const chalk = require("chalk") 7 | const os = require("os") 8 | 9 | // 解析命令行参数 10 | const args = process.argv.slice(2) 11 | const hasArg = (flags) => args.some((arg) => flags.includes(arg)) 12 | 13 | const isChangeMode = hasArg(["--change", "-C"]) 14 | const isChangeAllMode = hasArg(["--change-all", "-CA"]) 15 | const isResetMode = hasArg(["--reset", "-R"]) 16 | const isHelpMode = hasArg(["--help", "-h"]) 17 | 18 | // 显示帮助信息 19 | function showHelp() { 20 | console.log(chalk.green.bold("\n FigmaNetOK - 命令行参数说明\n")) 21 | console.log(chalk.white(" 用法: figma-net-ok [选项]\n")) 22 | console.log(chalk.yellow(" 选项:")) 23 | console.log(chalk.gray(" --change, -C ") + "运行快速测试,并自动设置 hosts") 24 | console.log(chalk.gray(" --change-all, -CA ") + "运行全部测试,并自动设置 hosts") 25 | console.log(chalk.gray(" --reset, -R ") + "重置 hosts(清除 Figma 相关配置)") 26 | console.log(chalk.gray(" --help, -h ") + "显示此帮助信息") 27 | console.log(chalk.gray("\n 不带参数运行时进入交互模式\n")) 28 | } 29 | 30 | // 快速模式:测试并设置 hosts 31 | async function runChangeMode(mode) { 32 | console.log(chalk.green.bold("\n FigmaNetOK - 自动模式\n")) 33 | console.log(chalk.blue(` · 测试模式: ${mode === "fast" ? "快速" : "全面"}`)) 34 | console.log(chalk.gray("----------------------------------------------\n")) 35 | 36 | let bestList = await getBestHosts(mode) 37 | if (bestList && bestList.length > 0) { 38 | console.log(chalk.green("\n · 测试完成,正在设置 hosts...\n")) 39 | await sudoCallSetHosts(bestList) 40 | let isWindow = os.platform() === "win32" 41 | if (isWindow) process.stdin.resume() 42 | } else { 43 | console.log(chalk.red("\n ✗ 测试失败,未找到可用的 hosts\n")) 44 | process.exit(1) 45 | } 46 | } 47 | 48 | // 重置模式 49 | async function runResetMode() { 50 | console.log(chalk.green.bold("\n FigmaNetOK - 重置模式\n")) 51 | console.log(chalk.yellow(" · 正在重置 Figma hosts 配置...")) 52 | console.log(chalk.gray("----------------------------------------------\n")) 53 | 54 | await sudoCallResetHosts(["s3-alpha-sig.figma.com", "www.figma.com", "static.figma.com"]) 55 | let isWindow = os.platform() === "win32" 56 | if (isWindow) process.stdin.resume() 57 | } 58 | 59 | // 命令行参数模式 60 | if (isHelpMode) { 61 | showHelp() 62 | process.exit(0) 63 | } else if (isChangeMode) { 64 | runChangeMode("fast") 65 | } else if (isChangeAllMode) { 66 | runChangeMode("full") 67 | } else if (isResetMode) { 68 | runResetMode() 69 | } else { 70 | // 交互模式 71 | console.clear() 72 | 73 | const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "2.5.0" 74 | 75 | console.log(chalk.green.bold(" FigmaNetOK \n")) 76 | console.log(chalk.green(` 🐌 Figma 网络最佳线路测试 v${VERSION} 🐙 `)) 77 | console.log(chalk.whiteBright(" 🌕 Moonvy.com ")) 78 | console.log(" https://github.com/Moonvy/Figma-Net-OK ") 79 | console.log(chalk.gray("----------------------------------------------\n")) 80 | 81 | // console.log("Host 编辑工具:https://swh.app/zh/\n") 82 | 83 | console.log( 84 | chalk.bgYellow.black(" ! "), 85 | `本工具适用于${chalk.yellow("不使用网络代理工具")},${chalk.green("直连")} Figma 的场合 \n`, 86 | ` 如果你在使用网络代理,就不适合使用本工具\n` 87 | ) 88 | console.log( 89 | chalk.bgYellow.black(" ! "), 90 | `本工具查找${chalk.yellow("此时最佳")}的服务器地址,具有一定的时效性 \n`, 91 | ` 当你的网络环境变换或者 Figma 服务器调整,就需要重新测速了\n` 92 | ) 93 | 94 | // 检查当前 Figma hosts 配置 95 | const hostsInfo = loadHostsInfo() 96 | if (hostsInfo.error) { 97 | console.log(chalk.bgRed.white(" ✗ "), `读取 hosts 文件失败: ${hostsInfo.error}\n`) 98 | } else if (hostsInfo.hasFigmaConfig) { 99 | console.log(chalk.bgGreen.black(" ✓ "), `检测到已有 Figma hosts 配置 (${hostsInfo.figmaEntries.length} 条):\n`) 100 | hostsInfo.figmaEntries.forEach((entry) => { 101 | console.log(chalk.gray(` ${entry.ip.padEnd(18)} ${chalk.cyan(entry.hostname)}`)) 102 | }) 103 | console.log() 104 | } else { 105 | console.log(chalk.bgBlue.white(" i "), `当前 hosts 中没有 Figma 相关配置\n`) 106 | } 107 | 108 | console.log(chalk.green(" · "), "相关问题,可以加 Figma 微信讨论群:" + chalk.bold("sixichacha")) 109 | 110 | console.log(chalk.gray("----------------------------------------------\n")) 111 | let qs = [ 112 | { 113 | type: "select", 114 | name: "selectMode", 115 | message: "选择测试模式", 116 | hint: "使用键盘方向键选择一个选项,按回车键确认", 117 | choices: [ 118 | { title: "全面", description: "尝试全部 DNS 服务商", value: "full" }, 119 | { title: "快速", description: "快速测试常用的 DNS 服务商", value: "fast" }, 120 | { title: "重置", description: "清除 Hosts 中的 Figma 配置", value: "reset" }, 121 | ], 122 | initial: 1, 123 | }, 124 | ] 125 | 126 | prompts(qs).then(async function (re) { 127 | if (re.selectMode === "reset") { 128 | await sudoCallResetHosts(["s3-alpha-sig.figma.com", "www.figma.com", "static.figma.com"]) 129 | let isWindow = os.platform() === "win32" 130 | if (isWindow) process.stdin.resume() 131 | } else { 132 | let bestLest = await getBestHosts(re.selectMode) 133 | prompts([ 134 | { 135 | type: "select", 136 | name: "selectMode", 137 | message: "是否自动设置 Hosts 文件?", 138 | hint: "使用键盘方向键选择一个选项,按回车键确认", 139 | initial: 0, 140 | choices: [ 141 | { title: "设置 Hosts", description: "通过本程序自动设置 Hosts ", value: "set" }, 142 | { title: "不了", description: "退出。你可以手动去修改 Hosts 文件", value: "exit" }, 143 | ], 144 | }, 145 | ]).then(async function (re) { 146 | if (re.selectMode === "set") { 147 | await sudoCallSetHosts(bestLest) 148 | let isWindow = os.platform() === "win32" 149 | if (isWindow) process.stdin.resume() 150 | } else { 151 | process.exit(0) 152 | } 153 | }) 154 | } 155 | }) 156 | } 157 | 158 | // require("./script/test-dns.js") 159 | -------------------------------------------------------------------------------- /app/bun.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "workspaces": { 4 | "": { 5 | "name": "figma-net-ok", 6 | "dependencies": { 7 | "axios": "^1.13.2", 8 | "chalk": "^4.1.2", 9 | "dns-lookup": "^0.1.0", 10 | "hostile": "^1.3.3", 11 | "nslookup": "^1.1.1", 12 | "ora": "^5.4.1", 13 | "ping": "^0.4.1", 14 | "prompts": "^2.4.2", 15 | "sudo-prompt": "^9.2.1", 16 | }, 17 | }, 18 | }, 19 | "packages": { 20 | "@ljharb/through": ["@ljharb/through@2.3.14", "https://registry.npmmirror.com/@ljharb/through/-/through-2.3.14.tgz", { "dependencies": { "call-bind": "^1.0.8" } }, "sha512-ajBvlKpWucBB17FuQYUShqpqy8GRgYEpJW0vWJbUu1CV9lWyrDCapy0lScU8T8Z6qn49sSwJB3+M+evYIdGg+A=="], 21 | 22 | "ansi-regex": ["ansi-regex@5.0.1", "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], 23 | 24 | "ansi-styles": ["ansi-styles@4.3.0", "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 25 | 26 | "assert-plus": ["assert-plus@1.0.0", "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="], 27 | 28 | "asynckit": ["asynckit@0.4.0", "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], 29 | 30 | "axios": ["axios@1.13.2", "https://registry.npmmirror.com/axios/-/axios-1.13.2.tgz", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA=="], 31 | 32 | "base64-js": ["base64-js@1.5.1", "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], 33 | 34 | "binaryheap": ["binaryheap@0.0.3", "https://registry.npmmirror.com/binaryheap/-/binaryheap-0.0.3.tgz", {}, "sha512-9JFb4Yt5R9FZwbJaxOayF+T5sxn5eiU2NA9/LOeI1g2FUFRTdxpdmWppikO4O5AbNze8s0sL6ZuFxB1y4Ay8GA=="], 35 | 36 | "bl": ["bl@4.1.0", "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], 37 | 38 | "buffer": ["buffer@5.7.1", "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], 39 | 40 | "buffercursor": ["buffercursor@0.0.12", "https://registry.npmmirror.com/buffercursor/-/buffercursor-0.0.12.tgz", { "dependencies": { "verror": "^1.4.0" } }, "sha512-Z+6Jm/eW6ITeqcFQKVXX7LYIGk7rENqCKHJ4CbWfJMeLpQZJj1v70WehkLmp+1kFN/QyCgpQ3Z0dKUHAwSbf9w=="], 41 | 42 | "call-bind": ["call-bind@1.0.8", "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.8.tgz", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], 43 | 44 | "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], 45 | 46 | "chalk": ["chalk@4.1.2", "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], 47 | 48 | "cli-cursor": ["cli-cursor@3.1.0", "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-3.1.0.tgz", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], 49 | 50 | "cli-spinners": ["cli-spinners@2.9.2", "https://registry.npmmirror.com/cli-spinners/-/cli-spinners-2.9.2.tgz", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], 51 | 52 | "clone": ["clone@1.0.4", "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], 53 | 54 | "color-convert": ["color-convert@2.0.1", "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], 55 | 56 | "color-name": ["color-name@1.1.4", "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], 57 | 58 | "combined-stream": ["combined-stream@1.0.8", "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], 59 | 60 | "core-util-is": ["core-util-is@1.0.2", "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="], 61 | 62 | "defaults": ["defaults@1.0.4", "https://registry.npmmirror.com/defaults/-/defaults-1.0.4.tgz", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], 63 | 64 | "define-data-property": ["define-data-property@1.1.4", "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], 65 | 66 | "delayed-stream": ["delayed-stream@1.0.0", "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], 67 | 68 | "dns-lookup": ["dns-lookup@0.1.0", "https://registry.npmmirror.com/dns-lookup/-/dns-lookup-0.1.0.tgz", {}, "sha512-eQM0vt8EJZc5gaBCegHn9YRzdeDmMIFdzEAhRXb+mN7bli3KUoPAYXZKKUPjXaMH5NZ1L/FchjXC66zdcRcp2g=="], 69 | 70 | "dunder-proto": ["dunder-proto@1.0.1", "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], 71 | 72 | "es-define-property": ["es-define-property@1.0.1", "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], 73 | 74 | "es-errors": ["es-errors@1.3.0", "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], 75 | 76 | "es-object-atoms": ["es-object-atoms@1.1.1", "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], 77 | 78 | "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], 79 | 80 | "extsprintf": ["extsprintf@1.4.1", "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.4.1.tgz", {}, "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="], 81 | 82 | "follow-redirects": ["follow-redirects@1.15.11", "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], 83 | 84 | "form-data": ["form-data@4.0.5", "https://registry.npmmirror.com/form-data/-/form-data-4.0.5.tgz", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], 85 | 86 | "function-bind": ["function-bind@1.1.2", "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], 87 | 88 | "get-intrinsic": ["get-intrinsic@1.3.0", "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], 89 | 90 | "get-proto": ["get-proto@1.0.1", "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], 91 | 92 | "gopd": ["gopd@1.2.0", "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], 93 | 94 | "has-flag": ["has-flag@4.0.0", "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], 95 | 96 | "has-property-descriptors": ["has-property-descriptors@1.0.2", "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], 97 | 98 | "has-symbols": ["has-symbols@1.1.0", "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], 99 | 100 | "has-tostringtag": ["has-tostringtag@1.0.2", "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], 101 | 102 | "hasown": ["hasown@2.0.2", "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], 103 | 104 | "hostile": ["hostile@1.4.0", "https://registry.npmmirror.com/hostile/-/hostile-1.4.0.tgz", { "dependencies": { "@ljharb/through": "^2.3.11", "chalk": "^4.1.2", "minimist": "^1.2.8", "once": "^1.4.0", "split": "^1.0.1" }, "bin": { "hostile": "bin/cmd.js" } }, "sha512-q5eniv6NnjeQ2S1Wh3/knyl4UE2FAQ9xz7yT0f6y5FK2j3fFHBI2jyaUVwAiAU20G6LQMAkRGM1WbTMXoeUwMg=="], 105 | 106 | "ieee754": ["ieee754@1.2.1", "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], 107 | 108 | "inherits": ["inherits@2.0.4", "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], 109 | 110 | "ipaddr.js": ["ipaddr.js@0.1.9", "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-0.1.9.tgz", {}, "sha512-dp0C1YYJuZMlFCM9eah1GbCVGRwcvLuCHDWfqUhIS6WqLO6jFK3GJHRQrD+OTID/mS3grl3gqGJ76QsOTpNsRw=="], 111 | 112 | "is-interactive": ["is-interactive@1.0.0", "https://registry.npmmirror.com/is-interactive/-/is-interactive-1.0.0.tgz", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="], 113 | 114 | "is-unicode-supported": ["is-unicode-supported@0.1.0", "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], 115 | 116 | "kleur": ["kleur@3.0.3", "https://registry.npmmirror.com/kleur/-/kleur-3.0.3.tgz", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], 117 | 118 | "log-symbols": ["log-symbols@4.1.0", "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], 119 | 120 | "math-intrinsics": ["math-intrinsics@1.1.0", "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], 121 | 122 | "mime-db": ["mime-db@1.52.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], 123 | 124 | "mime-types": ["mime-types@2.1.35", "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], 125 | 126 | "mimic-fn": ["mimic-fn@2.1.0", "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], 127 | 128 | "minimist": ["minimist@1.2.8", "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], 129 | 130 | "native-dns": ["native-dns@0.7.0", "https://registry.npmmirror.com/native-dns/-/native-dns-0.7.0.tgz", { "dependencies": { "ipaddr.js": "~0.1.3", "native-dns-cache": "~0.0.2", "native-dns-packet": "~0.1.1" } }, "sha512-tqpWBqpfeCgjdl3fMuKH0wXTGa9eQtT28H910QHZ1TRMK0pAdet8/LS6xRA5fNfO33u3JYcnc5wggWuHLnb5GQ=="], 131 | 132 | "native-dns-cache": ["native-dns-cache@0.0.2", "https://registry.npmmirror.com/native-dns-cache/-/native-dns-cache-0.0.2.tgz", { "dependencies": { "binaryheap": ">= 0.0.3", "native-dns-packet": ">= 0.0.1" } }, "sha512-09HXHdb/updxfigaFbR53F8nCKqxM8WuHfTWBsusVlwSSZZ3qwWRdD6Kx2x8HBI1Q5IaycwcJOvBoXZWJNfVEg=="], 133 | 134 | "native-dns-packet": ["native-dns-packet@0.1.1", "https://registry.npmmirror.com/native-dns-packet/-/native-dns-packet-0.1.1.tgz", { "dependencies": { "buffercursor": ">= 0.0.12", "ipaddr.js": ">= 0.1.1" } }, "sha512-j1XxnFFTUB7mujma468WyAOmyVtkuuLTelxJF13tSTIPO56X7bHALrG0G4jFQnvyTPCt4VnFiZezWpfKbaHc+g=="], 135 | 136 | "nslookup": ["nslookup@1.1.1", "https://registry.npmmirror.com/nslookup/-/nslookup-1.1.1.tgz", { "dependencies": { "native-dns": "~0.7.0" } }, "sha512-bf5PncO25UbSbj8KXu0+k6EQe+QLYahSmgkfYVp/4WEnd5XltnQ+hhchZTUo5S1kjsKCIoC9sqBAzYj2lDwsTg=="], 137 | 138 | "once": ["once@1.4.0", "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], 139 | 140 | "onetime": ["onetime@5.1.2", "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], 141 | 142 | "ora": ["ora@5.4.1", "https://registry.npmmirror.com/ora/-/ora-5.4.1.tgz", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], 143 | 144 | "ping": ["ping@0.4.4", "https://registry.npmmirror.com/ping/-/ping-0.4.4.tgz", {}, "sha512-56ZMC0j7SCsMMLdOoUg12VZCfj/+ZO+yfOSjaNCRrmZZr6GLbN2X/Ui56T15dI8NhiHckaw5X2pvyfAomanwqQ=="], 145 | 146 | "prompts": ["prompts@2.4.2", "https://registry.npmmirror.com/prompts/-/prompts-2.4.2.tgz", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], 147 | 148 | "proxy-from-env": ["proxy-from-env@1.1.0", "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], 149 | 150 | "readable-stream": ["readable-stream@3.6.2", "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], 151 | 152 | "restore-cursor": ["restore-cursor@3.1.0", "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], 153 | 154 | "safe-buffer": ["safe-buffer@5.2.1", "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], 155 | 156 | "set-function-length": ["set-function-length@1.2.2", "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], 157 | 158 | "signal-exit": ["signal-exit@3.0.7", "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], 159 | 160 | "sisteransi": ["sisteransi@1.0.5", "https://registry.npmmirror.com/sisteransi/-/sisteransi-1.0.5.tgz", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], 161 | 162 | "split": ["split@1.0.1", "https://registry.npmmirror.com/split/-/split-1.0.1.tgz", { "dependencies": { "through": "2" } }, "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg=="], 163 | 164 | "string_decoder": ["string_decoder@1.3.0", "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], 165 | 166 | "strip-ansi": ["strip-ansi@6.0.1", "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 167 | 168 | "sudo-prompt": ["sudo-prompt@9.2.1", "https://registry.npmmirror.com/sudo-prompt/-/sudo-prompt-9.2.1.tgz", {}, "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw=="], 169 | 170 | "supports-color": ["supports-color@7.2.0", "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 171 | 172 | "through": ["through@2.3.8", "https://registry.npmmirror.com/through/-/through-2.3.8.tgz", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], 173 | 174 | "util-deprecate": ["util-deprecate@1.0.2", "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], 175 | 176 | "verror": ["verror@1.10.1", "https://registry.npmmirror.com/verror/-/verror-1.10.1.tgz", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="], 177 | 178 | "wcwidth": ["wcwidth@1.0.1", "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], 179 | 180 | "wrappy": ["wrappy@1.0.2", "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "figma-net-ok", 3 | "version": "2.3.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "figma-net-ok", 9 | "version": "2.3.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^1.13.2", 13 | "chalk": "^4.1.2", 14 | "dns-lookup": "^0.1.0", 15 | "hostile": "^1.3.3", 16 | "nslookup": "^1.1.1", 17 | "ora": "^5.4.1", 18 | "ping": "^0.4.1", 19 | "prompts": "^2.4.2", 20 | "sudo-prompt": "^9.2.1" 21 | }, 22 | "bin": { 23 | "figma-net-ok": "index.js" 24 | }, 25 | "devDependencies": { 26 | "esbuild": "0.27.2" 27 | } 28 | }, 29 | "node_modules/@esbuild/aix-ppc64": { 30 | "version": "0.27.2", 31 | "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", 32 | "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", 33 | "cpu": [ 34 | "ppc64" 35 | ], 36 | "dev": true, 37 | "license": "MIT", 38 | "optional": true, 39 | "os": [ 40 | "aix" 41 | ], 42 | "engines": { 43 | "node": ">=18" 44 | } 45 | }, 46 | "node_modules/@esbuild/android-arm": { 47 | "version": "0.27.2", 48 | "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.2.tgz", 49 | "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", 50 | "cpu": [ 51 | "arm" 52 | ], 53 | "dev": true, 54 | "license": "MIT", 55 | "optional": true, 56 | "os": [ 57 | "android" 58 | ], 59 | "engines": { 60 | "node": ">=18" 61 | } 62 | }, 63 | "node_modules/@esbuild/android-arm64": { 64 | "version": "0.27.2", 65 | "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", 66 | "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", 67 | "cpu": [ 68 | "arm64" 69 | ], 70 | "dev": true, 71 | "license": "MIT", 72 | "optional": true, 73 | "os": [ 74 | "android" 75 | ], 76 | "engines": { 77 | "node": ">=18" 78 | } 79 | }, 80 | "node_modules/@esbuild/android-x64": { 81 | "version": "0.27.2", 82 | "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.2.tgz", 83 | "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", 84 | "cpu": [ 85 | "x64" 86 | ], 87 | "dev": true, 88 | "license": "MIT", 89 | "optional": true, 90 | "os": [ 91 | "android" 92 | ], 93 | "engines": { 94 | "node": ">=18" 95 | } 96 | }, 97 | "node_modules/@esbuild/darwin-arm64": { 98 | "version": "0.27.2", 99 | "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", 100 | "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", 101 | "cpu": [ 102 | "arm64" 103 | ], 104 | "dev": true, 105 | "license": "MIT", 106 | "optional": true, 107 | "os": [ 108 | "darwin" 109 | ], 110 | "engines": { 111 | "node": ">=18" 112 | } 113 | }, 114 | "node_modules/@esbuild/darwin-x64": { 115 | "version": "0.27.2", 116 | "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", 117 | "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", 118 | "cpu": [ 119 | "x64" 120 | ], 121 | "dev": true, 122 | "license": "MIT", 123 | "optional": true, 124 | "os": [ 125 | "darwin" 126 | ], 127 | "engines": { 128 | "node": ">=18" 129 | } 130 | }, 131 | "node_modules/@esbuild/freebsd-arm64": { 132 | "version": "0.27.2", 133 | "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", 134 | "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", 135 | "cpu": [ 136 | "arm64" 137 | ], 138 | "dev": true, 139 | "license": "MIT", 140 | "optional": true, 141 | "os": [ 142 | "freebsd" 143 | ], 144 | "engines": { 145 | "node": ">=18" 146 | } 147 | }, 148 | "node_modules/@esbuild/freebsd-x64": { 149 | "version": "0.27.2", 150 | "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", 151 | "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", 152 | "cpu": [ 153 | "x64" 154 | ], 155 | "dev": true, 156 | "license": "MIT", 157 | "optional": true, 158 | "os": [ 159 | "freebsd" 160 | ], 161 | "engines": { 162 | "node": ">=18" 163 | } 164 | }, 165 | "node_modules/@esbuild/linux-arm": { 166 | "version": "0.27.2", 167 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", 168 | "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", 169 | "cpu": [ 170 | "arm" 171 | ], 172 | "dev": true, 173 | "license": "MIT", 174 | "optional": true, 175 | "os": [ 176 | "linux" 177 | ], 178 | "engines": { 179 | "node": ">=18" 180 | } 181 | }, 182 | "node_modules/@esbuild/linux-arm64": { 183 | "version": "0.27.2", 184 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", 185 | "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", 186 | "cpu": [ 187 | "arm64" 188 | ], 189 | "dev": true, 190 | "license": "MIT", 191 | "optional": true, 192 | "os": [ 193 | "linux" 194 | ], 195 | "engines": { 196 | "node": ">=18" 197 | } 198 | }, 199 | "node_modules/@esbuild/linux-ia32": { 200 | "version": "0.27.2", 201 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", 202 | "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", 203 | "cpu": [ 204 | "ia32" 205 | ], 206 | "dev": true, 207 | "license": "MIT", 208 | "optional": true, 209 | "os": [ 210 | "linux" 211 | ], 212 | "engines": { 213 | "node": ">=18" 214 | } 215 | }, 216 | "node_modules/@esbuild/linux-loong64": { 217 | "version": "0.27.2", 218 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", 219 | "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", 220 | "cpu": [ 221 | "loong64" 222 | ], 223 | "dev": true, 224 | "license": "MIT", 225 | "optional": true, 226 | "os": [ 227 | "linux" 228 | ], 229 | "engines": { 230 | "node": ">=18" 231 | } 232 | }, 233 | "node_modules/@esbuild/linux-mips64el": { 234 | "version": "0.27.2", 235 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", 236 | "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", 237 | "cpu": [ 238 | "mips64el" 239 | ], 240 | "dev": true, 241 | "license": "MIT", 242 | "optional": true, 243 | "os": [ 244 | "linux" 245 | ], 246 | "engines": { 247 | "node": ">=18" 248 | } 249 | }, 250 | "node_modules/@esbuild/linux-ppc64": { 251 | "version": "0.27.2", 252 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", 253 | "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", 254 | "cpu": [ 255 | "ppc64" 256 | ], 257 | "dev": true, 258 | "license": "MIT", 259 | "optional": true, 260 | "os": [ 261 | "linux" 262 | ], 263 | "engines": { 264 | "node": ">=18" 265 | } 266 | }, 267 | "node_modules/@esbuild/linux-riscv64": { 268 | "version": "0.27.2", 269 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", 270 | "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", 271 | "cpu": [ 272 | "riscv64" 273 | ], 274 | "dev": true, 275 | "license": "MIT", 276 | "optional": true, 277 | "os": [ 278 | "linux" 279 | ], 280 | "engines": { 281 | "node": ">=18" 282 | } 283 | }, 284 | "node_modules/@esbuild/linux-s390x": { 285 | "version": "0.27.2", 286 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", 287 | "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", 288 | "cpu": [ 289 | "s390x" 290 | ], 291 | "dev": true, 292 | "license": "MIT", 293 | "optional": true, 294 | "os": [ 295 | "linux" 296 | ], 297 | "engines": { 298 | "node": ">=18" 299 | } 300 | }, 301 | "node_modules/@esbuild/linux-x64": { 302 | "version": "0.27.2", 303 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", 304 | "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", 305 | "cpu": [ 306 | "x64" 307 | ], 308 | "dev": true, 309 | "license": "MIT", 310 | "optional": true, 311 | "os": [ 312 | "linux" 313 | ], 314 | "engines": { 315 | "node": ">=18" 316 | } 317 | }, 318 | "node_modules/@esbuild/netbsd-arm64": { 319 | "version": "0.27.2", 320 | "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", 321 | "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", 322 | "cpu": [ 323 | "arm64" 324 | ], 325 | "dev": true, 326 | "license": "MIT", 327 | "optional": true, 328 | "os": [ 329 | "netbsd" 330 | ], 331 | "engines": { 332 | "node": ">=18" 333 | } 334 | }, 335 | "node_modules/@esbuild/netbsd-x64": { 336 | "version": "0.27.2", 337 | "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", 338 | "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", 339 | "cpu": [ 340 | "x64" 341 | ], 342 | "dev": true, 343 | "license": "MIT", 344 | "optional": true, 345 | "os": [ 346 | "netbsd" 347 | ], 348 | "engines": { 349 | "node": ">=18" 350 | } 351 | }, 352 | "node_modules/@esbuild/openbsd-arm64": { 353 | "version": "0.27.2", 354 | "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", 355 | "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", 356 | "cpu": [ 357 | "arm64" 358 | ], 359 | "dev": true, 360 | "license": "MIT", 361 | "optional": true, 362 | "os": [ 363 | "openbsd" 364 | ], 365 | "engines": { 366 | "node": ">=18" 367 | } 368 | }, 369 | "node_modules/@esbuild/openbsd-x64": { 370 | "version": "0.27.2", 371 | "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", 372 | "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", 373 | "cpu": [ 374 | "x64" 375 | ], 376 | "dev": true, 377 | "license": "MIT", 378 | "optional": true, 379 | "os": [ 380 | "openbsd" 381 | ], 382 | "engines": { 383 | "node": ">=18" 384 | } 385 | }, 386 | "node_modules/@esbuild/openharmony-arm64": { 387 | "version": "0.27.2", 388 | "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", 389 | "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", 390 | "cpu": [ 391 | "arm64" 392 | ], 393 | "dev": true, 394 | "license": "MIT", 395 | "optional": true, 396 | "os": [ 397 | "openharmony" 398 | ], 399 | "engines": { 400 | "node": ">=18" 401 | } 402 | }, 403 | "node_modules/@esbuild/sunos-x64": { 404 | "version": "0.27.2", 405 | "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", 406 | "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", 407 | "cpu": [ 408 | "x64" 409 | ], 410 | "dev": true, 411 | "license": "MIT", 412 | "optional": true, 413 | "os": [ 414 | "sunos" 415 | ], 416 | "engines": { 417 | "node": ">=18" 418 | } 419 | }, 420 | "node_modules/@esbuild/win32-arm64": { 421 | "version": "0.27.2", 422 | "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", 423 | "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", 424 | "cpu": [ 425 | "arm64" 426 | ], 427 | "dev": true, 428 | "license": "MIT", 429 | "optional": true, 430 | "os": [ 431 | "win32" 432 | ], 433 | "engines": { 434 | "node": ">=18" 435 | } 436 | }, 437 | "node_modules/@esbuild/win32-ia32": { 438 | "version": "0.27.2", 439 | "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", 440 | "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", 441 | "cpu": [ 442 | "ia32" 443 | ], 444 | "dev": true, 445 | "license": "MIT", 446 | "optional": true, 447 | "os": [ 448 | "win32" 449 | ], 450 | "engines": { 451 | "node": ">=18" 452 | } 453 | }, 454 | "node_modules/@esbuild/win32-x64": { 455 | "version": "0.27.2", 456 | "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", 457 | "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", 458 | "cpu": [ 459 | "x64" 460 | ], 461 | "dev": true, 462 | "license": "MIT", 463 | "optional": true, 464 | "os": [ 465 | "win32" 466 | ], 467 | "engines": { 468 | "node": ">=18" 469 | } 470 | }, 471 | "node_modules/@ljharb/through": { 472 | "version": "2.3.14", 473 | "license": "MIT", 474 | "dependencies": { 475 | "call-bind": "^1.0.8" 476 | }, 477 | "engines": { 478 | "node": ">= 0.4" 479 | } 480 | }, 481 | "node_modules/ansi-regex": { 482 | "version": "5.0.1", 483 | "license": "MIT", 484 | "engines": { 485 | "node": ">=8" 486 | } 487 | }, 488 | "node_modules/ansi-styles": { 489 | "version": "4.3.0", 490 | "license": "MIT", 491 | "dependencies": { 492 | "color-convert": "^2.0.1" 493 | }, 494 | "engines": { 495 | "node": ">=8" 496 | }, 497 | "funding": { 498 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 499 | } 500 | }, 501 | "node_modules/assert-plus": { 502 | "version": "1.0.0", 503 | "license": "MIT", 504 | "engines": { 505 | "node": ">=0.8" 506 | } 507 | }, 508 | "node_modules/asynckit": { 509 | "version": "0.4.0", 510 | "license": "MIT" 511 | }, 512 | "node_modules/axios": { 513 | "version": "1.13.2", 514 | "license": "MIT", 515 | "dependencies": { 516 | "follow-redirects": "^1.15.6", 517 | "form-data": "^4.0.4", 518 | "proxy-from-env": "^1.1.0" 519 | } 520 | }, 521 | "node_modules/base64-js": { 522 | "version": "1.5.1", 523 | "funding": [ 524 | { 525 | "type": "github", 526 | "url": "https://github.com/sponsors/feross" 527 | }, 528 | { 529 | "type": "patreon", 530 | "url": "https://www.patreon.com/feross" 531 | }, 532 | { 533 | "type": "consulting", 534 | "url": "https://feross.org/support" 535 | } 536 | ], 537 | "license": "MIT" 538 | }, 539 | "node_modules/binaryheap": { 540 | "version": "0.0.3", 541 | "engines": { 542 | "node": ">= 0.6.0" 543 | } 544 | }, 545 | "node_modules/bl": { 546 | "version": "4.1.0", 547 | "license": "MIT", 548 | "dependencies": { 549 | "buffer": "^5.5.0", 550 | "inherits": "^2.0.4", 551 | "readable-stream": "^3.4.0" 552 | } 553 | }, 554 | "node_modules/buffer": { 555 | "version": "5.7.1", 556 | "funding": [ 557 | { 558 | "type": "github", 559 | "url": "https://github.com/sponsors/feross" 560 | }, 561 | { 562 | "type": "patreon", 563 | "url": "https://www.patreon.com/feross" 564 | }, 565 | { 566 | "type": "consulting", 567 | "url": "https://feross.org/support" 568 | } 569 | ], 570 | "license": "MIT", 571 | "dependencies": { 572 | "base64-js": "^1.3.1", 573 | "ieee754": "^1.1.13" 574 | } 575 | }, 576 | "node_modules/buffercursor": { 577 | "version": "0.0.12", 578 | "dependencies": { 579 | "verror": "^1.4.0" 580 | }, 581 | "engines": { 582 | "node": ">= 0.5.0" 583 | } 584 | }, 585 | "node_modules/call-bind": { 586 | "version": "1.0.8", 587 | "license": "MIT", 588 | "dependencies": { 589 | "call-bind-apply-helpers": "^1.0.0", 590 | "es-define-property": "^1.0.0", 591 | "get-intrinsic": "^1.2.4", 592 | "set-function-length": "^1.2.2" 593 | }, 594 | "engines": { 595 | "node": ">= 0.4" 596 | }, 597 | "funding": { 598 | "url": "https://github.com/sponsors/ljharb" 599 | } 600 | }, 601 | "node_modules/call-bind-apply-helpers": { 602 | "version": "1.0.2", 603 | "license": "MIT", 604 | "dependencies": { 605 | "es-errors": "^1.3.0", 606 | "function-bind": "^1.1.2" 607 | }, 608 | "engines": { 609 | "node": ">= 0.4" 610 | } 611 | }, 612 | "node_modules/chalk": { 613 | "version": "4.1.2", 614 | "license": "MIT", 615 | "dependencies": { 616 | "ansi-styles": "^4.1.0", 617 | "supports-color": "^7.1.0" 618 | }, 619 | "engines": { 620 | "node": ">=10" 621 | }, 622 | "funding": { 623 | "url": "https://github.com/chalk/chalk?sponsor=1" 624 | } 625 | }, 626 | "node_modules/cli-cursor": { 627 | "version": "3.1.0", 628 | "license": "MIT", 629 | "dependencies": { 630 | "restore-cursor": "^3.1.0" 631 | }, 632 | "engines": { 633 | "node": ">=8" 634 | } 635 | }, 636 | "node_modules/cli-spinners": { 637 | "version": "2.9.2", 638 | "license": "MIT", 639 | "engines": { 640 | "node": ">=6" 641 | }, 642 | "funding": { 643 | "url": "https://github.com/sponsors/sindresorhus" 644 | } 645 | }, 646 | "node_modules/clone": { 647 | "version": "1.0.4", 648 | "license": "MIT", 649 | "engines": { 650 | "node": ">=0.8" 651 | } 652 | }, 653 | "node_modules/color-convert": { 654 | "version": "2.0.1", 655 | "license": "MIT", 656 | "dependencies": { 657 | "color-name": "~1.1.4" 658 | }, 659 | "engines": { 660 | "node": ">=7.0.0" 661 | } 662 | }, 663 | "node_modules/color-name": { 664 | "version": "1.1.4", 665 | "license": "MIT" 666 | }, 667 | "node_modules/combined-stream": { 668 | "version": "1.0.8", 669 | "license": "MIT", 670 | "dependencies": { 671 | "delayed-stream": "~1.0.0" 672 | }, 673 | "engines": { 674 | "node": ">= 0.8" 675 | } 676 | }, 677 | "node_modules/core-util-is": { 678 | "version": "1.0.2", 679 | "license": "MIT" 680 | }, 681 | "node_modules/defaults": { 682 | "version": "1.0.4", 683 | "license": "MIT", 684 | "dependencies": { 685 | "clone": "^1.0.2" 686 | }, 687 | "funding": { 688 | "url": "https://github.com/sponsors/sindresorhus" 689 | } 690 | }, 691 | "node_modules/define-data-property": { 692 | "version": "1.1.4", 693 | "license": "MIT", 694 | "dependencies": { 695 | "es-define-property": "^1.0.0", 696 | "es-errors": "^1.3.0", 697 | "gopd": "^1.0.1" 698 | }, 699 | "engines": { 700 | "node": ">= 0.4" 701 | }, 702 | "funding": { 703 | "url": "https://github.com/sponsors/ljharb" 704 | } 705 | }, 706 | "node_modules/delayed-stream": { 707 | "version": "1.0.0", 708 | "license": "MIT", 709 | "engines": { 710 | "node": ">=0.4.0" 711 | } 712 | }, 713 | "node_modules/dns-lookup": { 714 | "version": "0.1.0", 715 | "license": "MIT" 716 | }, 717 | "node_modules/dunder-proto": { 718 | "version": "1.0.1", 719 | "license": "MIT", 720 | "dependencies": { 721 | "call-bind-apply-helpers": "^1.0.1", 722 | "es-errors": "^1.3.0", 723 | "gopd": "^1.2.0" 724 | }, 725 | "engines": { 726 | "node": ">= 0.4" 727 | } 728 | }, 729 | "node_modules/es-define-property": { 730 | "version": "1.0.1", 731 | "license": "MIT", 732 | "engines": { 733 | "node": ">= 0.4" 734 | } 735 | }, 736 | "node_modules/es-errors": { 737 | "version": "1.3.0", 738 | "license": "MIT", 739 | "engines": { 740 | "node": ">= 0.4" 741 | } 742 | }, 743 | "node_modules/es-object-atoms": { 744 | "version": "1.1.1", 745 | "license": "MIT", 746 | "dependencies": { 747 | "es-errors": "^1.3.0" 748 | }, 749 | "engines": { 750 | "node": ">= 0.4" 751 | } 752 | }, 753 | "node_modules/es-set-tostringtag": { 754 | "version": "2.1.0", 755 | "license": "MIT", 756 | "dependencies": { 757 | "es-errors": "^1.3.0", 758 | "get-intrinsic": "^1.2.6", 759 | "has-tostringtag": "^1.0.2", 760 | "hasown": "^2.0.2" 761 | }, 762 | "engines": { 763 | "node": ">= 0.4" 764 | } 765 | }, 766 | "node_modules/esbuild": { 767 | "version": "0.27.2", 768 | "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.2.tgz", 769 | "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", 770 | "dev": true, 771 | "hasInstallScript": true, 772 | "license": "MIT", 773 | "bin": { 774 | "esbuild": "bin/esbuild" 775 | }, 776 | "engines": { 777 | "node": ">=18" 778 | }, 779 | "optionalDependencies": { 780 | "@esbuild/aix-ppc64": "0.27.2", 781 | "@esbuild/android-arm": "0.27.2", 782 | "@esbuild/android-arm64": "0.27.2", 783 | "@esbuild/android-x64": "0.27.2", 784 | "@esbuild/darwin-arm64": "0.27.2", 785 | "@esbuild/darwin-x64": "0.27.2", 786 | "@esbuild/freebsd-arm64": "0.27.2", 787 | "@esbuild/freebsd-x64": "0.27.2", 788 | "@esbuild/linux-arm": "0.27.2", 789 | "@esbuild/linux-arm64": "0.27.2", 790 | "@esbuild/linux-ia32": "0.27.2", 791 | "@esbuild/linux-loong64": "0.27.2", 792 | "@esbuild/linux-mips64el": "0.27.2", 793 | "@esbuild/linux-ppc64": "0.27.2", 794 | "@esbuild/linux-riscv64": "0.27.2", 795 | "@esbuild/linux-s390x": "0.27.2", 796 | "@esbuild/linux-x64": "0.27.2", 797 | "@esbuild/netbsd-arm64": "0.27.2", 798 | "@esbuild/netbsd-x64": "0.27.2", 799 | "@esbuild/openbsd-arm64": "0.27.2", 800 | "@esbuild/openbsd-x64": "0.27.2", 801 | "@esbuild/openharmony-arm64": "0.27.2", 802 | "@esbuild/sunos-x64": "0.27.2", 803 | "@esbuild/win32-arm64": "0.27.2", 804 | "@esbuild/win32-ia32": "0.27.2", 805 | "@esbuild/win32-x64": "0.27.2" 806 | } 807 | }, 808 | "node_modules/extsprintf": { 809 | "version": "1.4.1", 810 | "engines": [ 811 | "node >=0.6.0" 812 | ], 813 | "license": "MIT" 814 | }, 815 | "node_modules/follow-redirects": { 816 | "version": "1.15.11", 817 | "funding": [ 818 | { 819 | "type": "individual", 820 | "url": "https://github.com/sponsors/RubenVerborgh" 821 | } 822 | ], 823 | "license": "MIT", 824 | "engines": { 825 | "node": ">=4.0" 826 | }, 827 | "peerDependenciesMeta": { 828 | "debug": { 829 | "optional": true 830 | } 831 | } 832 | }, 833 | "node_modules/form-data": { 834 | "version": "4.0.5", 835 | "license": "MIT", 836 | "dependencies": { 837 | "asynckit": "^0.4.0", 838 | "combined-stream": "^1.0.8", 839 | "es-set-tostringtag": "^2.1.0", 840 | "hasown": "^2.0.2", 841 | "mime-types": "^2.1.12" 842 | }, 843 | "engines": { 844 | "node": ">= 6" 845 | } 846 | }, 847 | "node_modules/function-bind": { 848 | "version": "1.1.2", 849 | "license": "MIT", 850 | "funding": { 851 | "url": "https://github.com/sponsors/ljharb" 852 | } 853 | }, 854 | "node_modules/get-intrinsic": { 855 | "version": "1.3.0", 856 | "license": "MIT", 857 | "dependencies": { 858 | "call-bind-apply-helpers": "^1.0.2", 859 | "es-define-property": "^1.0.1", 860 | "es-errors": "^1.3.0", 861 | "es-object-atoms": "^1.1.1", 862 | "function-bind": "^1.1.2", 863 | "get-proto": "^1.0.1", 864 | "gopd": "^1.2.0", 865 | "has-symbols": "^1.1.0", 866 | "hasown": "^2.0.2", 867 | "math-intrinsics": "^1.1.0" 868 | }, 869 | "engines": { 870 | "node": ">= 0.4" 871 | }, 872 | "funding": { 873 | "url": "https://github.com/sponsors/ljharb" 874 | } 875 | }, 876 | "node_modules/get-proto": { 877 | "version": "1.0.1", 878 | "license": "MIT", 879 | "dependencies": { 880 | "dunder-proto": "^1.0.1", 881 | "es-object-atoms": "^1.0.0" 882 | }, 883 | "engines": { 884 | "node": ">= 0.4" 885 | } 886 | }, 887 | "node_modules/gopd": { 888 | "version": "1.2.0", 889 | "license": "MIT", 890 | "engines": { 891 | "node": ">= 0.4" 892 | }, 893 | "funding": { 894 | "url": "https://github.com/sponsors/ljharb" 895 | } 896 | }, 897 | "node_modules/has-flag": { 898 | "version": "4.0.0", 899 | "license": "MIT", 900 | "engines": { 901 | "node": ">=8" 902 | } 903 | }, 904 | "node_modules/has-property-descriptors": { 905 | "version": "1.0.2", 906 | "license": "MIT", 907 | "dependencies": { 908 | "es-define-property": "^1.0.0" 909 | }, 910 | "funding": { 911 | "url": "https://github.com/sponsors/ljharb" 912 | } 913 | }, 914 | "node_modules/has-symbols": { 915 | "version": "1.1.0", 916 | "license": "MIT", 917 | "engines": { 918 | "node": ">= 0.4" 919 | }, 920 | "funding": { 921 | "url": "https://github.com/sponsors/ljharb" 922 | } 923 | }, 924 | "node_modules/has-tostringtag": { 925 | "version": "1.0.2", 926 | "license": "MIT", 927 | "dependencies": { 928 | "has-symbols": "^1.0.3" 929 | }, 930 | "engines": { 931 | "node": ">= 0.4" 932 | }, 933 | "funding": { 934 | "url": "https://github.com/sponsors/ljharb" 935 | } 936 | }, 937 | "node_modules/hasown": { 938 | "version": "2.0.2", 939 | "license": "MIT", 940 | "dependencies": { 941 | "function-bind": "^1.1.2" 942 | }, 943 | "engines": { 944 | "node": ">= 0.4" 945 | } 946 | }, 947 | "node_modules/hostile": { 948 | "version": "1.4.0", 949 | "funding": [ 950 | { 951 | "type": "github", 952 | "url": "https://github.com/sponsors/feross" 953 | }, 954 | { 955 | "type": "patreon", 956 | "url": "https://www.patreon.com/feross" 957 | }, 958 | { 959 | "type": "consulting", 960 | "url": "https://feross.org/support" 961 | } 962 | ], 963 | "license": "MIT", 964 | "dependencies": { 965 | "@ljharb/through": "^2.3.11", 966 | "chalk": "^4.1.2", 967 | "minimist": "^1.2.8", 968 | "once": "^1.4.0", 969 | "split": "^1.0.1" 970 | }, 971 | "bin": { 972 | "hostile": "bin/cmd.js" 973 | } 974 | }, 975 | "node_modules/ieee754": { 976 | "version": "1.2.1", 977 | "funding": [ 978 | { 979 | "type": "github", 980 | "url": "https://github.com/sponsors/feross" 981 | }, 982 | { 983 | "type": "patreon", 984 | "url": "https://www.patreon.com/feross" 985 | }, 986 | { 987 | "type": "consulting", 988 | "url": "https://feross.org/support" 989 | } 990 | ], 991 | "license": "BSD-3-Clause" 992 | }, 993 | "node_modules/inherits": { 994 | "version": "2.0.4", 995 | "license": "ISC" 996 | }, 997 | "node_modules/ipaddr.js": { 998 | "version": "0.1.9", 999 | "license": "MIT", 1000 | "engines": { 1001 | "node": ">= 0.2.5" 1002 | } 1003 | }, 1004 | "node_modules/is-interactive": { 1005 | "version": "1.0.0", 1006 | "license": "MIT", 1007 | "engines": { 1008 | "node": ">=8" 1009 | } 1010 | }, 1011 | "node_modules/is-unicode-supported": { 1012 | "version": "0.1.0", 1013 | "license": "MIT", 1014 | "engines": { 1015 | "node": ">=10" 1016 | }, 1017 | "funding": { 1018 | "url": "https://github.com/sponsors/sindresorhus" 1019 | } 1020 | }, 1021 | "node_modules/kleur": { 1022 | "version": "3.0.3", 1023 | "license": "MIT", 1024 | "engines": { 1025 | "node": ">=6" 1026 | } 1027 | }, 1028 | "node_modules/log-symbols": { 1029 | "version": "4.1.0", 1030 | "license": "MIT", 1031 | "dependencies": { 1032 | "chalk": "^4.1.0", 1033 | "is-unicode-supported": "^0.1.0" 1034 | }, 1035 | "engines": { 1036 | "node": ">=10" 1037 | }, 1038 | "funding": { 1039 | "url": "https://github.com/sponsors/sindresorhus" 1040 | } 1041 | }, 1042 | "node_modules/math-intrinsics": { 1043 | "version": "1.1.0", 1044 | "license": "MIT", 1045 | "engines": { 1046 | "node": ">= 0.4" 1047 | } 1048 | }, 1049 | "node_modules/mime-db": { 1050 | "version": "1.52.0", 1051 | "license": "MIT", 1052 | "engines": { 1053 | "node": ">= 0.6" 1054 | } 1055 | }, 1056 | "node_modules/mime-types": { 1057 | "version": "2.1.35", 1058 | "license": "MIT", 1059 | "dependencies": { 1060 | "mime-db": "1.52.0" 1061 | }, 1062 | "engines": { 1063 | "node": ">= 0.6" 1064 | } 1065 | }, 1066 | "node_modules/mimic-fn": { 1067 | "version": "2.1.0", 1068 | "license": "MIT", 1069 | "engines": { 1070 | "node": ">=6" 1071 | } 1072 | }, 1073 | "node_modules/minimist": { 1074 | "version": "1.2.8", 1075 | "license": "MIT", 1076 | "funding": { 1077 | "url": "https://github.com/sponsors/ljharb" 1078 | } 1079 | }, 1080 | "node_modules/native-dns": { 1081 | "version": "0.7.0", 1082 | "dependencies": { 1083 | "ipaddr.js": "~0.1.3", 1084 | "native-dns-cache": "~0.0.2", 1085 | "native-dns-packet": "~0.1.1" 1086 | }, 1087 | "engines": { 1088 | "node": ">= 0.5.0" 1089 | } 1090 | }, 1091 | "node_modules/native-dns-cache": { 1092 | "version": "0.0.2", 1093 | "dependencies": { 1094 | "binaryheap": ">= 0.0.3", 1095 | "native-dns-packet": ">= 0.0.1" 1096 | }, 1097 | "engines": { 1098 | "node": ">= 0.5.0" 1099 | } 1100 | }, 1101 | "node_modules/native-dns-packet": { 1102 | "version": "0.1.1", 1103 | "license": "MIT", 1104 | "dependencies": { 1105 | "buffercursor": ">= 0.0.12", 1106 | "ipaddr.js": ">= 0.1.1" 1107 | }, 1108 | "engines": { 1109 | "node": ">= 0.5.0" 1110 | } 1111 | }, 1112 | "node_modules/nslookup": { 1113 | "version": "1.1.1", 1114 | "license": "MIT", 1115 | "dependencies": { 1116 | "native-dns": "~0.7.0" 1117 | } 1118 | }, 1119 | "node_modules/once": { 1120 | "version": "1.4.0", 1121 | "license": "ISC", 1122 | "dependencies": { 1123 | "wrappy": "1" 1124 | } 1125 | }, 1126 | "node_modules/onetime": { 1127 | "version": "5.1.2", 1128 | "license": "MIT", 1129 | "dependencies": { 1130 | "mimic-fn": "^2.1.0" 1131 | }, 1132 | "engines": { 1133 | "node": ">=6" 1134 | }, 1135 | "funding": { 1136 | "url": "https://github.com/sponsors/sindresorhus" 1137 | } 1138 | }, 1139 | "node_modules/ora": { 1140 | "version": "5.4.1", 1141 | "license": "MIT", 1142 | "dependencies": { 1143 | "bl": "^4.1.0", 1144 | "chalk": "^4.1.0", 1145 | "cli-cursor": "^3.1.0", 1146 | "cli-spinners": "^2.5.0", 1147 | "is-interactive": "^1.0.0", 1148 | "is-unicode-supported": "^0.1.0", 1149 | "log-symbols": "^4.1.0", 1150 | "strip-ansi": "^6.0.0", 1151 | "wcwidth": "^1.0.1" 1152 | }, 1153 | "engines": { 1154 | "node": ">=10" 1155 | }, 1156 | "funding": { 1157 | "url": "https://github.com/sponsors/sindresorhus" 1158 | } 1159 | }, 1160 | "node_modules/ping": { 1161 | "version": "0.4.4", 1162 | "license": "MIT", 1163 | "engines": { 1164 | "node": ">=4.0.0" 1165 | } 1166 | }, 1167 | "node_modules/prompts": { 1168 | "version": "2.4.2", 1169 | "license": "MIT", 1170 | "dependencies": { 1171 | "kleur": "^3.0.3", 1172 | "sisteransi": "^1.0.5" 1173 | }, 1174 | "engines": { 1175 | "node": ">= 6" 1176 | } 1177 | }, 1178 | "node_modules/proxy-from-env": { 1179 | "version": "1.1.0", 1180 | "license": "MIT" 1181 | }, 1182 | "node_modules/readable-stream": { 1183 | "version": "3.6.2", 1184 | "license": "MIT", 1185 | "dependencies": { 1186 | "inherits": "^2.0.3", 1187 | "string_decoder": "^1.1.1", 1188 | "util-deprecate": "^1.0.1" 1189 | }, 1190 | "engines": { 1191 | "node": ">= 6" 1192 | } 1193 | }, 1194 | "node_modules/restore-cursor": { 1195 | "version": "3.1.0", 1196 | "license": "MIT", 1197 | "dependencies": { 1198 | "onetime": "^5.1.0", 1199 | "signal-exit": "^3.0.2" 1200 | }, 1201 | "engines": { 1202 | "node": ">=8" 1203 | } 1204 | }, 1205 | "node_modules/safe-buffer": { 1206 | "version": "5.2.1", 1207 | "funding": [ 1208 | { 1209 | "type": "github", 1210 | "url": "https://github.com/sponsors/feross" 1211 | }, 1212 | { 1213 | "type": "patreon", 1214 | "url": "https://www.patreon.com/feross" 1215 | }, 1216 | { 1217 | "type": "consulting", 1218 | "url": "https://feross.org/support" 1219 | } 1220 | ], 1221 | "license": "MIT" 1222 | }, 1223 | "node_modules/set-function-length": { 1224 | "version": "1.2.2", 1225 | "license": "MIT", 1226 | "dependencies": { 1227 | "define-data-property": "^1.1.4", 1228 | "es-errors": "^1.3.0", 1229 | "function-bind": "^1.1.2", 1230 | "get-intrinsic": "^1.2.4", 1231 | "gopd": "^1.0.1", 1232 | "has-property-descriptors": "^1.0.2" 1233 | }, 1234 | "engines": { 1235 | "node": ">= 0.4" 1236 | } 1237 | }, 1238 | "node_modules/signal-exit": { 1239 | "version": "3.0.7", 1240 | "license": "ISC" 1241 | }, 1242 | "node_modules/sisteransi": { 1243 | "version": "1.0.5", 1244 | "license": "MIT" 1245 | }, 1246 | "node_modules/split": { 1247 | "version": "1.0.1", 1248 | "license": "MIT", 1249 | "dependencies": { 1250 | "through": "2" 1251 | }, 1252 | "engines": { 1253 | "node": "*" 1254 | } 1255 | }, 1256 | "node_modules/string_decoder": { 1257 | "version": "1.3.0", 1258 | "license": "MIT", 1259 | "dependencies": { 1260 | "safe-buffer": "~5.2.0" 1261 | } 1262 | }, 1263 | "node_modules/strip-ansi": { 1264 | "version": "6.0.1", 1265 | "license": "MIT", 1266 | "dependencies": { 1267 | "ansi-regex": "^5.0.1" 1268 | }, 1269 | "engines": { 1270 | "node": ">=8" 1271 | } 1272 | }, 1273 | "node_modules/sudo-prompt": { 1274 | "version": "9.2.1", 1275 | "license": "MIT" 1276 | }, 1277 | "node_modules/supports-color": { 1278 | "version": "7.2.0", 1279 | "license": "MIT", 1280 | "dependencies": { 1281 | "has-flag": "^4.0.0" 1282 | }, 1283 | "engines": { 1284 | "node": ">=8" 1285 | } 1286 | }, 1287 | "node_modules/through": { 1288 | "version": "2.3.8", 1289 | "license": "MIT" 1290 | }, 1291 | "node_modules/util-deprecate": { 1292 | "version": "1.0.2", 1293 | "license": "MIT" 1294 | }, 1295 | "node_modules/verror": { 1296 | "version": "1.10.1", 1297 | "license": "MIT", 1298 | "dependencies": { 1299 | "assert-plus": "^1.0.0", 1300 | "core-util-is": "1.0.2", 1301 | "extsprintf": "^1.2.0" 1302 | }, 1303 | "engines": { 1304 | "node": ">=0.6.0" 1305 | } 1306 | }, 1307 | "node_modules/wcwidth": { 1308 | "version": "1.0.1", 1309 | "license": "MIT", 1310 | "dependencies": { 1311 | "defaults": "^1.0.3" 1312 | } 1313 | }, 1314 | "node_modules/wrappy": { 1315 | "version": "1.0.2", 1316 | "license": "ISC" 1317 | } 1318 | } 1319 | } 1320 | --------------------------------------------------------------------------------