dsh-pocket 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/client.js +1 -1
- package/client/index.jsx +2 -1
- package/lib/service.mjs +46 -5
- package/package.json +1 -1
package/client/client.js
CHANGED
|
@@ -1348,7 +1348,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1348
1348
|
(async () => {
|
|
1349
1349
|
try {
|
|
1350
1350
|
const v = await call(POCKET_ENDPOINTS.version, {});
|
|
1351
|
-
const meta = await (await fetch("https://registry.npmjs.org/dsh-pocket/latest")).json();
|
|
1351
|
+
const meta = await (await fetch("https://registry.npmjs.org/dsh-pocket/latest", { cache: "no-store" })).json();
|
|
1352
1352
|
if (!alive) return;
|
|
1353
1353
|
const latest = typeof meta?.version === "string" ? meta.version : null;
|
|
1354
1354
|
if (latest && v.current && compareVersions(latest, v.current) > 0) {
|
package/client/index.jsx
CHANGED
|
@@ -84,12 +84,13 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
84
84
|
|
|
85
85
|
// 版本检测:host 当前版本 vs npm registry latest(registry 带 CORS *)
|
|
86
86
|
// 两种情况显示横幅:① 有新版可更新;② 磁盘已更新但进程还是旧代码(重启生效)
|
|
87
|
+
// cache: 'no-store' —— registry 响应带缓存头,浏览器会缓存旧版本号导致「小版本不提示」
|
|
87
88
|
useEffect(() => {
|
|
88
89
|
let alive = true;
|
|
89
90
|
(async () => {
|
|
90
91
|
try {
|
|
91
92
|
const v = await call(POCKET_ENDPOINTS.version, {});
|
|
92
|
-
const meta = await (await fetch('https://registry.npmjs.org/dsh-pocket/latest')).json();
|
|
93
|
+
const meta = await (await fetch('https://registry.npmjs.org/dsh-pocket/latest', { cache: 'no-store' })).json();
|
|
93
94
|
if (!alive) return;
|
|
94
95
|
const latest = typeof meta?.version === 'string' ? meta.version : null;
|
|
95
96
|
if (latest && v.current && compareVersions(latest, v.current) > 0) {
|
package/lib/service.mjs
CHANGED
|
@@ -19,13 +19,54 @@ export async function qrDataUrl(text, { width = 220, margin = 1 } = {}) {
|
|
|
19
19
|
return QRCode.toDataURL(text, { errorCorrectionLevel: 'M', margin, width, type: 'image/png' });
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
/** RFC1918 私网地址:手机与电脑连同一局域网时通常可直连。 */
|
|
23
|
+
const PRIVATE_IPV4_RE = /^(?:10\.|192\.168\.|172\.(?:1[6-9]|2\d|3[01])\.)/;
|
|
24
|
+
|
|
25
|
+
/** 名称像真实物理网卡的接口(WLAN / Wi-Fi / Ethernet / 以太网 / en / eth)。 */
|
|
26
|
+
const PHYSICAL_IFACE_RE = /^(?:wlan|wi-?fi|wireless|ethernet|eth\d|en\d|wlp\d|以太网|本地连接)/i;
|
|
27
|
+
|
|
28
|
+
/** 常见的 VPN / 虚拟网卡名称:手机通常无法通过它们直连电脑。 */
|
|
29
|
+
const VPN_IFACE_RE = /(?:radmin|tailscale|zerotier|tun|tap|vpn|vethernet|virtual|vmware|virtualbox|wsl|docker|teredo|hamachi|bluetooth|bridge)/i;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 从 networkInterfaces() 返回的接口表里选出手机最可能可达的 IPv4。
|
|
33
|
+
*
|
|
34
|
+
* `os.networkInterfaces()` 的枚举顺序不可靠:Windows 上 Radmin VPN / Tailscale /
|
|
35
|
+
* vEthernet 等虚拟网卡常排在 WLAN 前面,旧实现直接取第一张非回环网卡,会生成
|
|
36
|
+
* 手机打不开的二维码。这里按以下规则打分排序:
|
|
37
|
+
* - RFC1918 私网地址优先(10/8、172.16/12、192.168/16);
|
|
38
|
+
* - 名称像物理网卡再加分;
|
|
39
|
+
* - 名称像 VPN/虚拟网卡减分;
|
|
40
|
+
* - 同分保持原枚举顺序。
|
|
41
|
+
* 没有任何私网地址时回退到最高分地址(例如纯 VPN 环境仍可用)。
|
|
42
|
+
*
|
|
43
|
+
* @param {ReturnType<typeof networkInterfaces>} interfaces
|
|
44
|
+
* @returns {string|null}
|
|
45
|
+
*/
|
|
46
|
+
export function selectLanIPv4(interfaces) {
|
|
47
|
+
const candidates = [];
|
|
48
|
+
for (const [name, addrs] of Object.entries(interfaces ?? {})) {
|
|
49
|
+
for (const addr of addrs ?? []) {
|
|
50
|
+
if (addr.family !== 'IPv4' || addr.internal) continue;
|
|
51
|
+
const ip = addr.address;
|
|
52
|
+
// 排除 loopback 与 link-local;其余地址即使不是私网(如 Radmin 的 26.x)也保留兜底
|
|
53
|
+
if (!ip || ip.startsWith('127.') || ip.startsWith('169.254.')) continue;
|
|
54
|
+
|
|
55
|
+
let score = 0;
|
|
56
|
+
if (PRIVATE_IPV4_RE.test(ip)) score += 100;
|
|
57
|
+
if (PHYSICAL_IFACE_RE.test(name)) score += 20;
|
|
58
|
+
else if (VPN_IFACE_RE.test(name)) score -= 50;
|
|
59
|
+
|
|
60
|
+
candidates.push({ ip, score, order: candidates.length });
|
|
26
61
|
}
|
|
27
62
|
}
|
|
28
|
-
|
|
63
|
+
|
|
64
|
+
candidates.sort((a, b) => b.score - a.score || a.order - b.order);
|
|
65
|
+
return candidates[0]?.ip ?? null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function lanIPv4() {
|
|
69
|
+
return selectLanIPv4(networkInterfaces());
|
|
29
70
|
}
|
|
30
71
|
|
|
31
72
|
/**
|
package/package.json
CHANGED