├── 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 |
--------------------------------------------------------------------------------