@dsh-sup/dsh-core-linux-x64 0.1.6-BETA.11 → 0.1.6-BETA.13
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/core.cjs +751 -241
- package/package.json +1 -1
- package/ui-react/assets/{InstancesPage--LhDhPDs.js → InstancesPage-DM0dMQHh.js} +1 -1
- package/ui-react/assets/{LanPage-D7soTx9V.js → LanPage-B5oThF8O.js} +1 -1
- package/ui-react/assets/{OverviewPage-DxCKB6BV.js → OverviewPage-DH8PtnPI.js} +1 -1
- package/ui-react/assets/{PluginsPage-mISvN5b8.js → PluginsPage-C1llxTDk.js} +1 -1
- package/ui-react/assets/{RouterPage-vhAx87Fo.js → RouterPage-CUKMV2Q9.js} +1 -1
- package/ui-react/assets/{SettingsPage-DgA5JCBo.js → SettingsPage-BZG-EvR3.js} +1 -1
- package/ui-react/assets/{TasksPage-CGdHy0sy.js → TasksPage-haZMZbBh.js} +1 -1
- package/ui-react/assets/openExternal-CzqErnSy.js +1 -0
- package/ui-react/assets/{supervisor-C_6Efj6Z.js → supervisor-BCZW2z-5.js} +2 -2
- package/ui-react/assets/supervisor-YWIsBeZU.css +2 -0
- package/ui-react/supervisor.html +2 -2
- package/ui-react/assets/openExternal-CBH3SnvT.js +0 -1
- package/ui-react/assets/supervisor-B5Bq0rnN.css +0 -2
package/core.cjs
CHANGED
|
@@ -947,7 +947,7 @@ var require_version = __commonJS({
|
|
|
947
947
|
var fs2 = require("node:fs");
|
|
948
948
|
var path2 = require("node:path");
|
|
949
949
|
function guardVersion() {
|
|
950
|
-
if (true) return String("0.1.6-BETA.
|
|
950
|
+
if (true) return String("0.1.6-BETA.13");
|
|
951
951
|
try {
|
|
952
952
|
return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
|
|
953
953
|
} catch {
|
|
@@ -4639,23 +4639,66 @@ var require_desktop = __commonJS({
|
|
|
4639
4639
|
"src/platform/os/desktop.js"(exports2, module2) {
|
|
4640
4640
|
"use strict";
|
|
4641
4641
|
var fs2 = require("node:fs");
|
|
4642
|
+
var os2 = require("node:os");
|
|
4643
|
+
var path2 = require("node:path");
|
|
4642
4644
|
var PLATFORM = process.platform;
|
|
4643
|
-
|
|
4645
|
+
var X11_DIR = "/tmp/.X11-unix";
|
|
4646
|
+
function deps(o) {
|
|
4647
|
+
const ov = o || {};
|
|
4648
|
+
return {
|
|
4649
|
+
env: ov.env || process.env,
|
|
4650
|
+
readdir: ov.readdir || ((p) => fs2.readdirSync(p)),
|
|
4651
|
+
exists: ov.exists || ((p) => fs2.existsSync(p)),
|
|
4652
|
+
home: ov.home || os2.homedir(),
|
|
4653
|
+
uid: typeof process.getuid === "function" ? process.getuid() : 0
|
|
4654
|
+
};
|
|
4655
|
+
}
|
|
4656
|
+
function runtimeDir(env, uid) {
|
|
4657
|
+
return env.XDG_RUNTIME_DIR || "/run/user/" + uid;
|
|
4658
|
+
}
|
|
4659
|
+
function x11Displays(o) {
|
|
4660
|
+
const d = deps(o);
|
|
4644
4661
|
try {
|
|
4645
|
-
return
|
|
4662
|
+
return d.readdir(X11_DIR).filter((f) => /^X\d+$/.test(f)).map((f) => Number(f.slice(1))).sort((a, b) => a - b);
|
|
4646
4663
|
} catch {
|
|
4647
|
-
return
|
|
4664
|
+
return [];
|
|
4648
4665
|
}
|
|
4649
4666
|
}
|
|
4650
|
-
function
|
|
4651
|
-
const
|
|
4652
|
-
const rt = process.env.XDG_RUNTIME_DIR || "/run/user/" + uid;
|
|
4667
|
+
function waylandSockets(o) {
|
|
4668
|
+
const d = deps(o);
|
|
4653
4669
|
try {
|
|
4654
|
-
return
|
|
4670
|
+
return d.readdir(runtimeDir(d.env, d.uid)).filter((f) => /^wayland-\d+$/.test(f)).sort();
|
|
4655
4671
|
} catch {
|
|
4656
|
-
return
|
|
4672
|
+
return [];
|
|
4657
4673
|
}
|
|
4658
4674
|
}
|
|
4675
|
+
function hasX11Socket(o) {
|
|
4676
|
+
return x11Displays(o).length > 0;
|
|
4677
|
+
}
|
|
4678
|
+
function hasWaylandSocket(o) {
|
|
4679
|
+
return waylandSockets(o).length > 0;
|
|
4680
|
+
}
|
|
4681
|
+
function sessionEnv(o) {
|
|
4682
|
+
const d = deps(o);
|
|
4683
|
+
const out = {};
|
|
4684
|
+
if (PLATFORM !== "linux") return out;
|
|
4685
|
+
if (!d.env.DISPLAY && !d.env.WAYLAND_DISPLAY) {
|
|
4686
|
+
const xs = x11Displays(d);
|
|
4687
|
+
if (xs.length) {
|
|
4688
|
+
out.DISPLAY = ":" + xs[0];
|
|
4689
|
+
const xauth = path2.join(d.home, ".Xauthority");
|
|
4690
|
+
if (d.exists(xauth)) out.XAUTHORITY = xauth;
|
|
4691
|
+
} else {
|
|
4692
|
+
const wl = waylandSockets(d);
|
|
4693
|
+
if (wl.length) out.WAYLAND_DISPLAY = wl[0];
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4696
|
+
if (!d.env.DBUS_SESSION_BUS_ADDRESS) {
|
|
4697
|
+
const bus = path2.join(runtimeDir(d.env, d.uid), "bus");
|
|
4698
|
+
if (d.exists(bus)) out.DBUS_SESSION_BUS_ADDRESS = "unix:path=" + bus;
|
|
4699
|
+
}
|
|
4700
|
+
return out;
|
|
4701
|
+
}
|
|
4659
4702
|
function sessionAvailable() {
|
|
4660
4703
|
if (PLATFORM === "linux") {
|
|
4661
4704
|
if (process.env.DISPLAY || process.env.WAYLAND_DISPLAY) return true;
|
|
@@ -4682,7 +4725,7 @@ var require_desktop = __commonJS({
|
|
|
4682
4725
|
reason: "session-scoped-by-launcher"
|
|
4683
4726
|
};
|
|
4684
4727
|
}
|
|
4685
|
-
module2.exports = { sessionAvailable, describe, PLATFORM };
|
|
4728
|
+
module2.exports = { sessionAvailable, sessionEnv, describe, x11Displays, waylandSockets, PLATFORM };
|
|
4686
4729
|
}
|
|
4687
4730
|
});
|
|
4688
4731
|
|
|
@@ -4755,8 +4798,9 @@ var require_capability_profile = __commonJS({
|
|
|
4755
4798
|
autostart: true,
|
|
4756
4799
|
// 期望 schtasks(实测覆写)
|
|
4757
4800
|
frpExpose: true,
|
|
4758
|
-
//
|
|
4759
|
-
//
|
|
4801
|
+
// 可打开,但 Windows 没有可信调度器(系统调度器只有 darwin 的 open 与 linux 的 xdg-open),
|
|
4802
|
+
// 只能直启探测层解析出的浏览器本体;浏览器已在运行时本次进程只转交地址,退出码与窗口出现与否无关,
|
|
4803
|
+
// 故该平台每次调用最多到 handedOff(判据见 browser.js#ownsItsWindow)。能力位只声明「能交出去」。
|
|
4760
4804
|
openBrowser: true,
|
|
4761
4805
|
hostService: "windows-service",
|
|
4762
4806
|
guardAutostart: true,
|
|
@@ -5452,18 +5496,567 @@ var require_notify = __commonJS({
|
|
|
5452
5496
|
}
|
|
5453
5497
|
});
|
|
5454
5498
|
|
|
5499
|
+
// src/platform/os/browser-inventory.js
|
|
5500
|
+
var require_browser_inventory = __commonJS({
|
|
5501
|
+
"src/platform/os/browser-inventory.js"(exports2, module2) {
|
|
5502
|
+
"use strict";
|
|
5503
|
+
var fs2 = require("node:fs");
|
|
5504
|
+
var path2 = require("node:path");
|
|
5505
|
+
var os2 = require("node:os");
|
|
5506
|
+
var exec = require_exec();
|
|
5507
|
+
var { isExecutableFile } = require_exec_path();
|
|
5508
|
+
var PROBE_TIMEOUT_MS = 1500;
|
|
5509
|
+
function engineOf(bin) {
|
|
5510
|
+
const base = String(bin || "").toLowerCase().split(/[\\/]/).pop();
|
|
5511
|
+
if (/(chrome|chromium|msedge|edge|brave|vivaldi|opera|thorium)/.test(base)) return "chromium";
|
|
5512
|
+
if (/(firefox|librewolf|waterfox)/.test(base)) return "firefox";
|
|
5513
|
+
return "other";
|
|
5514
|
+
}
|
|
5515
|
+
function tokenizeExec(line) {
|
|
5516
|
+
const toks = [];
|
|
5517
|
+
let cur = "";
|
|
5518
|
+
let q = null;
|
|
5519
|
+
let esc = false;
|
|
5520
|
+
let has = false;
|
|
5521
|
+
for (const ch of String(line)) {
|
|
5522
|
+
if (esc) {
|
|
5523
|
+
cur += ch;
|
|
5524
|
+
esc = false;
|
|
5525
|
+
continue;
|
|
5526
|
+
}
|
|
5527
|
+
if (ch === "\\") {
|
|
5528
|
+
esc = true;
|
|
5529
|
+
has = true;
|
|
5530
|
+
continue;
|
|
5531
|
+
}
|
|
5532
|
+
if (q) {
|
|
5533
|
+
if (ch === q) q = null;
|
|
5534
|
+
else cur += ch;
|
|
5535
|
+
continue;
|
|
5536
|
+
}
|
|
5537
|
+
if (ch === "'" || ch === '"') {
|
|
5538
|
+
q = ch;
|
|
5539
|
+
has = true;
|
|
5540
|
+
continue;
|
|
5541
|
+
}
|
|
5542
|
+
if (/\s/.test(ch)) {
|
|
5543
|
+
if (has) {
|
|
5544
|
+
toks.push(cur);
|
|
5545
|
+
cur = "";
|
|
5546
|
+
has = false;
|
|
5547
|
+
}
|
|
5548
|
+
continue;
|
|
5549
|
+
}
|
|
5550
|
+
cur += ch;
|
|
5551
|
+
has = true;
|
|
5552
|
+
}
|
|
5553
|
+
if (has) toks.push(cur);
|
|
5554
|
+
return toks;
|
|
5555
|
+
}
|
|
5556
|
+
function parseExecLine(line) {
|
|
5557
|
+
let toks = tokenizeExec(line).filter((t) => t !== "%%" && !/^%[a-zA-Z]$/.test(t));
|
|
5558
|
+
if (toks[0] === "env") {
|
|
5559
|
+
let i = 1;
|
|
5560
|
+
while (i < toks.length && /=/.test(toks[i])) i++;
|
|
5561
|
+
toks = toks.slice(i);
|
|
5562
|
+
}
|
|
5563
|
+
if (!toks.length) return null;
|
|
5564
|
+
return { bin: toks[0], baseArgs: toks.slice(1) };
|
|
5565
|
+
}
|
|
5566
|
+
function regValueOf(out) {
|
|
5567
|
+
const m = String(out || "").match(/REG_(?:EXPAND_SZ|SZ)\s+(.*)/);
|
|
5568
|
+
if (!m) return null;
|
|
5569
|
+
return m[1].trim() || null;
|
|
5570
|
+
}
|
|
5571
|
+
function expandEnvVars(value, env) {
|
|
5572
|
+
const e = env || process.env;
|
|
5573
|
+
return String(value).replace(/%([^%]+)%/g, (all, name) => e[name] === void 0 ? all : e[name]);
|
|
5574
|
+
}
|
|
5575
|
+
function exeFromCmdLine(cmdLine) {
|
|
5576
|
+
const s = String(cmdLine || "");
|
|
5577
|
+
let m = s.match(/^\s*"([^"]+\.exe)"/i);
|
|
5578
|
+
if (m) return m[1];
|
|
5579
|
+
m = s.match(/^\s*(.*?\.exe)/i);
|
|
5580
|
+
return m ? m[1] : null;
|
|
5581
|
+
}
|
|
5582
|
+
function safeRegKeyPart(s) {
|
|
5583
|
+
return typeof s === "string" && s.length > 0 && s.length <= 200 && /^[\x20-\x7e]+$/.test(s) && !/[;|&`$()<>^"'\r\n]/.test(s);
|
|
5584
|
+
}
|
|
5585
|
+
function regValue(runner, note, key, name) {
|
|
5586
|
+
const args = name ? ["query", key, "/v", name] : ["query", key, "/ve"];
|
|
5587
|
+
const out = runner("reg.exe", args);
|
|
5588
|
+
const v = regValueOf(out);
|
|
5589
|
+
note(name ? key + " /v " + name : key, v ? "ok" : "empty");
|
|
5590
|
+
return v;
|
|
5591
|
+
}
|
|
5592
|
+
var REG_HIVE_ALIAS = { HKLM: "HKEY_LOCAL_MACHINE", HKCU: "HKEY_CURRENT_USER", HKCR: "HKEY_CLASSES_ROOT", HKU: "HKEY_USERS", HKCC: "HKEY_CURRENT_CONFIG" };
|
|
5593
|
+
function regKeyFull(key) {
|
|
5594
|
+
const s = String(key || "");
|
|
5595
|
+
const i = s.indexOf("\\");
|
|
5596
|
+
const root = i < 0 ? s : s.slice(0, i);
|
|
5597
|
+
return (REG_HIVE_ALIAS[root.toUpperCase()] || root) + (i < 0 ? "" : s.slice(i));
|
|
5598
|
+
}
|
|
5599
|
+
function regSubkeys(runner, note, key) {
|
|
5600
|
+
const out = runner("reg.exe", ["query", key]);
|
|
5601
|
+
if (!out) {
|
|
5602
|
+
note(key, "unreadable");
|
|
5603
|
+
return [];
|
|
5604
|
+
}
|
|
5605
|
+
const prefix = regKeyFull(key) + "\\";
|
|
5606
|
+
const names = [];
|
|
5607
|
+
for (const line of String(out).split(/\r?\n/)) {
|
|
5608
|
+
const l = line.trim();
|
|
5609
|
+
if (!/^HKEY_/i.test(l) || l.length <= prefix.length) continue;
|
|
5610
|
+
if (l.slice(0, prefix.length).toUpperCase() !== prefix.toUpperCase()) continue;
|
|
5611
|
+
const rest = l.slice(prefix.length);
|
|
5612
|
+
if (rest && !rest.includes("\\") && safeRegKeyPart(rest)) names.push(rest);
|
|
5613
|
+
}
|
|
5614
|
+
note(key, names.length ? names.length + " \u9879" : "\u65E0\u5B50\u952E");
|
|
5615
|
+
return names;
|
|
5616
|
+
}
|
|
5617
|
+
var WIN_APP_PATHS = ["msedge.exe", "chrome.exe", "firefox.exe", "brave.exe", "opera.exe", "vivaldi.exe", "chromium.exe", "thorium.exe", "librewolf.exe"];
|
|
5618
|
+
function winExeOfProgId(runner, note, progId, env) {
|
|
5619
|
+
if (!safeRegKeyPart(progId)) return null;
|
|
5620
|
+
for (const root of ["HKCU\\Software\\Classes", "HKLM\\Software\\Classes"]) {
|
|
5621
|
+
const cmd2 = regValue(runner, note, root + "\\" + progId + "\\shell\\open\\command");
|
|
5622
|
+
const exe = cmd2 ? exeFromCmdLine(expandEnvVars(cmd2, env)) : null;
|
|
5623
|
+
if (exe) return exe;
|
|
5624
|
+
}
|
|
5625
|
+
return null;
|
|
5626
|
+
}
|
|
5627
|
+
function probeWin(d) {
|
|
5628
|
+
const { runOut, env, canExec } = d;
|
|
5629
|
+
const notes = [];
|
|
5630
|
+
const note = (source, detail) => {
|
|
5631
|
+
notes.push({ source, detail });
|
|
5632
|
+
};
|
|
5633
|
+
const found = /* @__PURE__ */ new Map();
|
|
5634
|
+
const keyOf = (exe) => String(exe || "").toLowerCase().replace(/[\\/]/g, "\\");
|
|
5635
|
+
const push = (exe, how) => {
|
|
5636
|
+
const full = expandEnvVars(exe, env).trim();
|
|
5637
|
+
if (!/\.exe$/i.test(full)) {
|
|
5638
|
+
note(how, "\u6765\u6E90\u7ED9\u51FA\u7684\u4E0D\u662F exe \u8DEF\u5F84: " + full);
|
|
5639
|
+
return null;
|
|
5640
|
+
}
|
|
5641
|
+
const k = keyOf(full);
|
|
5642
|
+
const hit = found.get(k);
|
|
5643
|
+
if (hit) {
|
|
5644
|
+
if (!hit.sources.includes(how)) hit.sources.push(how);
|
|
5645
|
+
return hit;
|
|
5646
|
+
}
|
|
5647
|
+
if (!canExec(full)) {
|
|
5648
|
+
note(how, "\u6307\u5411\u7684\u6587\u4EF6\u4E0D\u53EF\u6267\u884C: " + full);
|
|
5649
|
+
return null;
|
|
5650
|
+
}
|
|
5651
|
+
const item = { id: k, name: path2.basename(full).replace(/\.exe$/i, ""), engine: engineOf(full), bin: full, source: how, sources: [how] };
|
|
5652
|
+
found.set(k, item);
|
|
5653
|
+
note(how, item.name);
|
|
5654
|
+
return item;
|
|
5655
|
+
};
|
|
5656
|
+
const progIds = /* @__PURE__ */ new Map();
|
|
5657
|
+
const addProgId = (pid, how) => {
|
|
5658
|
+
const s = String(pid || "").trim();
|
|
5659
|
+
if (!safeRegKeyPart(s)) return;
|
|
5660
|
+
if (progIds.get(s) === "userchoice") return;
|
|
5661
|
+
progIds.set(s, how);
|
|
5662
|
+
};
|
|
5663
|
+
let defaultId = null;
|
|
5664
|
+
let defaultSource = null;
|
|
5665
|
+
const DEF_RANK = { userchoice: 1, "scheme-association": 2, "only-installed": 9 };
|
|
5666
|
+
let defRank = 99;
|
|
5667
|
+
const setDefault = (item, how) => {
|
|
5668
|
+
const r = DEF_RANK[how] === void 0 ? 99 : DEF_RANK[how];
|
|
5669
|
+
if (item && r < defRank) {
|
|
5670
|
+
defRank = r;
|
|
5671
|
+
defaultId = item.id;
|
|
5672
|
+
defaultSource = how;
|
|
5673
|
+
}
|
|
5674
|
+
};
|
|
5675
|
+
const cmdToExe = (raw) => raw ? exeFromCmdLine(expandEnvVars(raw, env)) : null;
|
|
5676
|
+
const uc = regValue(runOut, note, "HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\https\\UserChoice", "ProgId");
|
|
5677
|
+
if (uc) addProgId(uc, "userchoice");
|
|
5678
|
+
for (const root of ["HKCU\\Software\\Classes", "HKLM\\Software\\Classes"]) {
|
|
5679
|
+
const pid = regValue(runOut, note, root + "\\https");
|
|
5680
|
+
if (pid) addProgId(pid, "scheme-association");
|
|
5681
|
+
const exe = cmdToExe(regValue(runOut, note, root + "\\https\\shell\\open\\command"));
|
|
5682
|
+
if (exe) setDefault(push(exe, "scheme-association"), "scheme-association");
|
|
5683
|
+
}
|
|
5684
|
+
for (const name of regSubkeys(runOut, note, "HKLM\\SOFTWARE\\Clients\\StartMenuInternet")) {
|
|
5685
|
+
addProgId(name, "startmenu-catalog");
|
|
5686
|
+
const exe = cmdToExe(regValue(runOut, note, "HKLM\\SOFTWARE\\Clients\\StartMenuInternet\\" + name + "\\shell\\open\\command")) || winExeOfProgId(runOut, note, name, env);
|
|
5687
|
+
if (exe) push(exe, "startmenu-catalog");
|
|
5688
|
+
}
|
|
5689
|
+
for (const root of ["HKLM\\SOFTWARE", "HKCU\\SOFTWARE"]) {
|
|
5690
|
+
for (const capPath of regValueTargets(runOut, note, root + "\\RegisteredApplications")) {
|
|
5691
|
+
const https = regValue(runOut, note, capPath + "\\UrlAssociations\\https");
|
|
5692
|
+
const sid = regValue(runOut, note, capPath, "StartMenuInternet");
|
|
5693
|
+
const pid = https || sid;
|
|
5694
|
+
if (pid) addProgId(pid, "registered-apps");
|
|
5695
|
+
}
|
|
5696
|
+
}
|
|
5697
|
+
for (const exe of WIN_APP_PATHS) {
|
|
5698
|
+
for (const root of ["HKCU", "HKLM"]) {
|
|
5699
|
+
const v = regValue(runOut, note, root + "\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + exe);
|
|
5700
|
+
if (v && push(v, "app-paths")) break;
|
|
5701
|
+
}
|
|
5702
|
+
}
|
|
5703
|
+
for (const [pid, how] of progIds) {
|
|
5704
|
+
const exe = winExeOfProgId(runOut, note, pid, env);
|
|
5705
|
+
if (!exe) continue;
|
|
5706
|
+
const item = push(exe, how);
|
|
5707
|
+
if (how === "userchoice") setDefault(item, "userchoice");
|
|
5708
|
+
}
|
|
5709
|
+
if (found.size === 1) setDefault([...found.values()][0], "only-installed");
|
|
5710
|
+
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5711
|
+
}
|
|
5712
|
+
function regValueTargets(runOut, note, key) {
|
|
5713
|
+
const out = runOut("reg.exe", ["query", key]);
|
|
5714
|
+
if (!out) {
|
|
5715
|
+
note(key, "unreadable");
|
|
5716
|
+
return [];
|
|
5717
|
+
}
|
|
5718
|
+
const paths = [];
|
|
5719
|
+
for (const line of String(out).split(/\r?\n/)) {
|
|
5720
|
+
const m = line.trim().match(/REG_SZ\s+(.*)/);
|
|
5721
|
+
if (!m) continue;
|
|
5722
|
+
const rel = m[1].trim();
|
|
5723
|
+
if (!safeRegKeyPart(rel)) continue;
|
|
5724
|
+
const root = key.slice(0, key.indexOf("\\"));
|
|
5725
|
+
paths.push(root + "\\" + rel);
|
|
5726
|
+
}
|
|
5727
|
+
note(key, paths.length ? paths.length + " \u4E2A\u80FD\u529B\u8DEF\u5F84" : "\u65E0\u503C");
|
|
5728
|
+
return paths;
|
|
5729
|
+
}
|
|
5730
|
+
var MAC_JXA_LIST = [
|
|
5731
|
+
"ObjC.import('Foundation');",
|
|
5732
|
+
"var ws=$.NSWorkspace.sharedWorkspace;",
|
|
5733
|
+
"var u=$.NSURL.URLWithString('https://dsh.local/probe');",
|
|
5734
|
+
"var out=[];var def='';",
|
|
5735
|
+
"try{var d=ws.URLForApplicationToOpenURL(u); if(!d.isNil()) def=ObjC.unwrap(d.path)||'';}catch(e){}",
|
|
5736
|
+
"var list=null;",
|
|
5737
|
+
"try{list=ws.urlsForApplicationsToOpenURL(u);}catch(e){}",
|
|
5738
|
+
"if(list===null||typeof list.count!=='number'){if(def){out.push(def+'\\t\\t1');}}else{",
|
|
5739
|
+
"var n=Number(list.count);",
|
|
5740
|
+
"for(var i=0;i<n;i++){",
|
|
5741
|
+
"var p=ObjC.unwrap(list.objectAtIndex(i).path)||''; if(!p) continue;",
|
|
5742
|
+
"var exe='';var bid='';",
|
|
5743
|
+
"var b=$.NSBundle.bundleWithPath(p);",
|
|
5744
|
+
"if(!b.isNil()){exe=ObjC.unwrap(b.executablePath)||'';bid=ObjC.unwrap(b.bundleIdentifier)||'';}",
|
|
5745
|
+
"out.push((exe||p)+'\\t'+bid+'\\t'+(p&&def&&p===def?1:0));}",
|
|
5746
|
+
"}",
|
|
5747
|
+
// 末句必须是裸表达式:osascript 取的是最后一条**语句**的值,if/else 语句不产结果,
|
|
5748
|
+
// 写在分支里会让整段查询输出空字符串(表现为「系统未报任何可用应用」)。
|
|
5749
|
+
"out.join('\\n');"
|
|
5750
|
+
].join("");
|
|
5751
|
+
function probeMac(d) {
|
|
5752
|
+
const { runOut, canExec } = d;
|
|
5753
|
+
const notes = [];
|
|
5754
|
+
const note = (source, detail) => {
|
|
5755
|
+
notes.push({ source, detail });
|
|
5756
|
+
};
|
|
5757
|
+
const out = runOut("osascript", ["-l", "JavaScript", "-e", MAC_JXA_LIST]);
|
|
5758
|
+
if (!out || !out.trim()) {
|
|
5759
|
+
note("launchservices", "\u67E5\u8BE2\u65E0\u8F93\u51FA\uFF08\u65E7\u7CFB\u7EDF\u6216\u88AB\u6743\u9650\u62E6\u622A\uFF09");
|
|
5760
|
+
return { browsers: [], defaultId: null, defaultSource: null, probed: notes };
|
|
5761
|
+
}
|
|
5762
|
+
const keyOf = (exe) => String(exe || "").toLowerCase();
|
|
5763
|
+
const found = /* @__PURE__ */ new Map();
|
|
5764
|
+
let defaultId = null;
|
|
5765
|
+
let defaultSource = null;
|
|
5766
|
+
for (const line of out.trim().split("\n")) {
|
|
5767
|
+
const parts = line.split(" ");
|
|
5768
|
+
const bin = (parts[0] || "").trim();
|
|
5769
|
+
if (!bin) continue;
|
|
5770
|
+
if (!canExec(bin)) {
|
|
5771
|
+
note("launchservices", "\u4E0D\u53EF\u6267\u884C: " + bin);
|
|
5772
|
+
continue;
|
|
5773
|
+
}
|
|
5774
|
+
const k = keyOf(bin);
|
|
5775
|
+
if (!found.has(k)) found.set(k, { id: k, name: path2.basename(bin), engine: engineOf(bin), bin, source: "launchservices", sources: ["launchservices"], isDefault: false });
|
|
5776
|
+
if (parts[2] === "1") {
|
|
5777
|
+
found.get(k).isDefault = true;
|
|
5778
|
+
if (!defaultId) {
|
|
5779
|
+
defaultId = k;
|
|
5780
|
+
defaultSource = "launchservices";
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
}
|
|
5784
|
+
note("launchservices", found.size ? found.size + " \u4E2A\u53EF\u6253\u5F00 https \u7684\u5E94\u7528" : "\u7CFB\u7EDF\u672A\u62A5\u4EFB\u4F55\u53EF\u7528\u5E94\u7528");
|
|
5785
|
+
if (!defaultId && found.size === 1) {
|
|
5786
|
+
defaultId = [...found.keys()][0];
|
|
5787
|
+
defaultSource = "only-installed";
|
|
5788
|
+
}
|
|
5789
|
+
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5790
|
+
}
|
|
5791
|
+
var PJ = path2.posix.join;
|
|
5792
|
+
function desktopDirs(env, home) {
|
|
5793
|
+
const dataHome = env.XDG_DATA_HOME || PJ(home, ".local", "share");
|
|
5794
|
+
const dataDirs = String(env.XDG_DATA_DIRS || "/usr/local/share:/usr/share").split(":").filter(Boolean);
|
|
5795
|
+
const dirs = [[dataHome, "xdg"], ...dataDirs.map((p) => [p, "xdg"])];
|
|
5796
|
+
dirs.push([PJ(home, ".local", "share"), "xdg"]);
|
|
5797
|
+
dirs.push(["/var/lib/flatpak/exports/share", "flatpak"]);
|
|
5798
|
+
dirs.push([PJ(home, ".local", "share", "flatpak", "exports", "share"), "flatpak"]);
|
|
5799
|
+
dirs.push(["/var/lib/snapd/desktop", "snap"]);
|
|
5800
|
+
const seen = [];
|
|
5801
|
+
return dirs.map(([root, kind]) => ({ dir: PJ(root, "applications"), kind })).filter((x) => {
|
|
5802
|
+
if (seen.includes(x.dir)) return false;
|
|
5803
|
+
seen.push(x.dir);
|
|
5804
|
+
return true;
|
|
5805
|
+
});
|
|
5806
|
+
}
|
|
5807
|
+
function browserFromDesktop(text, kind, file) {
|
|
5808
|
+
let inMain = false;
|
|
5809
|
+
const got = {};
|
|
5810
|
+
for (const line of String(text).split(/\r?\n/)) {
|
|
5811
|
+
if (/^\[Desktop Entry\]\s*$/.test(line)) {
|
|
5812
|
+
inMain = true;
|
|
5813
|
+
continue;
|
|
5814
|
+
}
|
|
5815
|
+
if (/^\[/.test(line)) break;
|
|
5816
|
+
if (!inMain) continue;
|
|
5817
|
+
const m = line.match(/^(Exec|Name|TryExec|Categories)=(.*)$/);
|
|
5818
|
+
if (!m) continue;
|
|
5819
|
+
if (m[1] === "Name" && got.Name) continue;
|
|
5820
|
+
got[m[1]] = m[2].trim();
|
|
5821
|
+
}
|
|
5822
|
+
if (!got.Exec) return null;
|
|
5823
|
+
const categories = String(got.Categories || "");
|
|
5824
|
+
const parsed = parseExecLine(got.Exec);
|
|
5825
|
+
if (!parsed) return null;
|
|
5826
|
+
const engine = engineOf(parsed.bin);
|
|
5827
|
+
const claimsBrowser = /(^|;)WebBrowser(;|$)/.test(categories);
|
|
5828
|
+
if (!claimsBrowser && engine === "other") return null;
|
|
5829
|
+
if (engine === "other") return null;
|
|
5830
|
+
return {
|
|
5831
|
+
// id 恒为归一后的可执行文件路径:defaultId 靠它在清单里定位条目,三平台同一契约
|
|
5832
|
+
id: parsed.bin.toLowerCase(),
|
|
5833
|
+
name: got.Name || path2.basename(file, ".desktop"),
|
|
5834
|
+
engine,
|
|
5835
|
+
bin: parsed.bin,
|
|
5836
|
+
baseArgs: parsed.baseArgs,
|
|
5837
|
+
source: kind,
|
|
5838
|
+
desktopFile: file
|
|
5839
|
+
};
|
|
5840
|
+
}
|
|
5841
|
+
function resolveLinuxBin(bin, canExec, env) {
|
|
5842
|
+
const b = String(bin || "").trim();
|
|
5843
|
+
if (!b) return null;
|
|
5844
|
+
if (b.startsWith("/")) return canExec(b) ? b : null;
|
|
5845
|
+
if (b.includes("/")) return null;
|
|
5846
|
+
for (const dir of String(env.PATH || "").split(":")) {
|
|
5847
|
+
if (!dir) continue;
|
|
5848
|
+
const p = PJ(dir.replace(/\/+$/, ""), b);
|
|
5849
|
+
if (canExec(p)) return p;
|
|
5850
|
+
}
|
|
5851
|
+
return null;
|
|
5852
|
+
}
|
|
5853
|
+
function probeLinux(d) {
|
|
5854
|
+
const { runOut, readFile, exists, listDir, canExec, env, home } = d;
|
|
5855
|
+
const notes = [];
|
|
5856
|
+
const note = (source, detail) => {
|
|
5857
|
+
notes.push({ source, detail });
|
|
5858
|
+
};
|
|
5859
|
+
const found = /* @__PURE__ */ new Map();
|
|
5860
|
+
const usable = (item) => {
|
|
5861
|
+
const resolved = resolveLinuxBin(item.bin, canExec, env);
|
|
5862
|
+
if (!resolved) {
|
|
5863
|
+
note(item.source, "\u4E0D\u53EF\u6267\u884C: " + item.bin);
|
|
5864
|
+
return null;
|
|
5865
|
+
}
|
|
5866
|
+
const k = resolved.toLowerCase();
|
|
5867
|
+
const hit = found.get(k);
|
|
5868
|
+
if (hit) {
|
|
5869
|
+
if (!hit.sources.includes(item.source)) hit.sources.push(item.source);
|
|
5870
|
+
return hit;
|
|
5871
|
+
}
|
|
5872
|
+
const v = Object.assign({}, item, { id: k, bin: resolved, sources: [item.source] });
|
|
5873
|
+
found.set(k, v);
|
|
5874
|
+
return v;
|
|
5875
|
+
};
|
|
5876
|
+
for (const { dir, kind } of desktopDirs(env, home)) {
|
|
5877
|
+
let names = [];
|
|
5878
|
+
try {
|
|
5879
|
+
names = listDir(dir).filter((f) => f.endsWith(".desktop"));
|
|
5880
|
+
} catch {
|
|
5881
|
+
continue;
|
|
5882
|
+
}
|
|
5883
|
+
for (const f of names) {
|
|
5884
|
+
let text = null;
|
|
5885
|
+
try {
|
|
5886
|
+
text = readFile(PJ(dir, f));
|
|
5887
|
+
} catch {
|
|
5888
|
+
continue;
|
|
5889
|
+
}
|
|
5890
|
+
const item = browserFromDesktop(text, kind, f);
|
|
5891
|
+
if (item) usable(item);
|
|
5892
|
+
}
|
|
5893
|
+
}
|
|
5894
|
+
let defaultId = null;
|
|
5895
|
+
let defaultSource = null;
|
|
5896
|
+
const fromMime = linuxDefaultFromMimeApps(readFile, exists, env, home, note);
|
|
5897
|
+
if (fromMime) {
|
|
5898
|
+
const item = usable(fromMime);
|
|
5899
|
+
if (item) {
|
|
5900
|
+
defaultId = item.id;
|
|
5901
|
+
defaultSource = "mimeapps";
|
|
5902
|
+
}
|
|
5903
|
+
}
|
|
5904
|
+
const id = runOut("xdg-settings", ["get", "default-web-browser"]);
|
|
5905
|
+
const desktopId = id && String(id).trim();
|
|
5906
|
+
if (!defaultId && desktopId && /^[A-Za-z0-9._-]+\.desktop$/.test(desktopId)) {
|
|
5907
|
+
for (const { dir } of desktopDirs(env, home)) {
|
|
5908
|
+
const p = PJ(dir, desktopId);
|
|
5909
|
+
let text = null;
|
|
5910
|
+
try {
|
|
5911
|
+
if (exists(p)) text = readFile(p);
|
|
5912
|
+
} catch {
|
|
5913
|
+
continue;
|
|
5914
|
+
}
|
|
5915
|
+
if (text === null) continue;
|
|
5916
|
+
const item = browserFromDesktop(text, "xdg-settings", desktopId);
|
|
5917
|
+
const used = item && usable(item);
|
|
5918
|
+
if (used) {
|
|
5919
|
+
defaultId = used.id;
|
|
5920
|
+
defaultSource = "xdg-settings";
|
|
5921
|
+
break;
|
|
5922
|
+
}
|
|
5923
|
+
}
|
|
5924
|
+
}
|
|
5925
|
+
if (!desktopId) note("xdg-settings", "\u65E0\u8F93\u51FA");
|
|
5926
|
+
else if (defaultSource === "xdg-settings") note("xdg-settings", "\u9ED8\u8BA4=" + defaultId);
|
|
5927
|
+
else note("xdg-settings", "\u62A5\u51FA " + desktopId + (defaultId ? "\uFF08\u9ED8\u8BA4\u5DF2\u7531 " + defaultSource + " \u5B9A\u51FA\uFF09" : " \u4F46\u4E0D\u53EF\u7528"));
|
|
5928
|
+
if (!defaultId && found.size === 1) {
|
|
5929
|
+
defaultId = [...found.keys()][0];
|
|
5930
|
+
defaultSource = "only-installed";
|
|
5931
|
+
}
|
|
5932
|
+
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5933
|
+
}
|
|
5934
|
+
function linuxDefaultFromMimeApps(readFile, exists, env, home, note) {
|
|
5935
|
+
const cfgHome = env.XDG_CONFIG_HOME || PJ(home, ".config");
|
|
5936
|
+
const cfgDirs = String(env.XDG_CONFIG_DIRS || "/etc/xdg").split(":").filter(Boolean);
|
|
5937
|
+
const dataDirs = String(env.XDG_DATA_DIRS || "/usr/local/share:/usr/share").split(":").filter(Boolean);
|
|
5938
|
+
const files = [
|
|
5939
|
+
PJ(cfgHome, "mimeapps.list"),
|
|
5940
|
+
...cfgDirs.map((d) => PJ(d, "mimeapps.list")),
|
|
5941
|
+
...dataDirs.map((d) => PJ(d, "applications", "mimeapps.list"))
|
|
5942
|
+
];
|
|
5943
|
+
for (const f of files) {
|
|
5944
|
+
if (!exists(f)) continue;
|
|
5945
|
+
let text = null;
|
|
5946
|
+
try {
|
|
5947
|
+
text = readFile(f);
|
|
5948
|
+
} catch {
|
|
5949
|
+
continue;
|
|
5950
|
+
}
|
|
5951
|
+
const id = mimeAppsDefault(text);
|
|
5952
|
+
if (!id) continue;
|
|
5953
|
+
note("mimeapps", path2.basename(f) + " -> " + id);
|
|
5954
|
+
for (const { dir, kind } of desktopDirs(env, home)) {
|
|
5955
|
+
const p = PJ(dir, id);
|
|
5956
|
+
if (!exists(p)) continue;
|
|
5957
|
+
let dt = null;
|
|
5958
|
+
try {
|
|
5959
|
+
dt = readFile(p);
|
|
5960
|
+
} catch {
|
|
5961
|
+
continue;
|
|
5962
|
+
}
|
|
5963
|
+
const item = browserFromDesktop(dt, kind, id);
|
|
5964
|
+
if (item) return item;
|
|
5965
|
+
}
|
|
5966
|
+
return null;
|
|
5967
|
+
}
|
|
5968
|
+
note("mimeapps", "\u65E0\u9ED8\u8BA4\u9879");
|
|
5969
|
+
return null;
|
|
5970
|
+
}
|
|
5971
|
+
function mimeAppsDefault(text) {
|
|
5972
|
+
let inDefault = false;
|
|
5973
|
+
for (const line of String(text || "").split(/\r?\n/)) {
|
|
5974
|
+
if (/^\s*\[/.test(line)) {
|
|
5975
|
+
inDefault = /^\s*\[Default Applications\]\s*$/.test(line);
|
|
5976
|
+
continue;
|
|
5977
|
+
}
|
|
5978
|
+
if (!inDefault) continue;
|
|
5979
|
+
const m = line.match(/^\s*x-scheme-handler\/https?\s*=\s*(.*)$/i);
|
|
5980
|
+
if (!m) continue;
|
|
5981
|
+
const ids = m[1].split(";").map((s) => s.trim()).filter((s) => /^[A-Za-z0-9._-]+\.desktop$/.test(s));
|
|
5982
|
+
if (ids.length) return ids[0];
|
|
5983
|
+
}
|
|
5984
|
+
return null;
|
|
5985
|
+
}
|
|
5986
|
+
function probe(platform, d) {
|
|
5987
|
+
const pl = platform || process.platform;
|
|
5988
|
+
const dd = Object.assign({}, d, { canExec: d.canExec || ((p) => isExecutableFile(p, pl)) });
|
|
5989
|
+
if (pl === "win32") return probeWin(dd);
|
|
5990
|
+
if (pl === "darwin") return probeMac(dd);
|
|
5991
|
+
return probeLinux(dd);
|
|
5992
|
+
}
|
|
5993
|
+
var CACHE = /* @__PURE__ */ Object.create(null);
|
|
5994
|
+
function inventory(platform, o) {
|
|
5995
|
+
const ov = o || {};
|
|
5996
|
+
const pl = platform || process.platform;
|
|
5997
|
+
const now = ov.now || (() => Date.now());
|
|
5998
|
+
const ttl = ov.ttlMs === void 0 ? 6e4 : ov.ttlMs;
|
|
5999
|
+
const cached = CACHE[pl];
|
|
6000
|
+
if (!ov.force && cached && now() - cached.at < ttl) return Object.assign({ cached: true }, cached.value);
|
|
6001
|
+
const runOut = ov.runOut || ((bin, args) => exec.runOut(bin, args, { timeoutMs: PROBE_TIMEOUT_MS }));
|
|
6002
|
+
const readFile = ov.readFile || ((p) => fs2.readFileSync(p, "utf8"));
|
|
6003
|
+
const exists = ov.exists || ((p) => fs2.existsSync(p));
|
|
6004
|
+
const listDir = ov.listDir || ((p) => fs2.readdirSync(p));
|
|
6005
|
+
let value;
|
|
6006
|
+
try {
|
|
6007
|
+
value = probe(pl, { runOut, readFile, exists, listDir, canExec: ov.canExec, env: ov.env || process.env, home: ov.home || os2.homedir() });
|
|
6008
|
+
} catch (e) {
|
|
6009
|
+
value = { browsers: [], defaultId: null, defaultSource: null, probed: [{ source: "probe-error", detail: String(e && e.message || e) }] };
|
|
6010
|
+
}
|
|
6011
|
+
value.at = now();
|
|
6012
|
+
value.platform = pl;
|
|
6013
|
+
value.browsers.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
6014
|
+
CACHE[pl] = { at: now(), value };
|
|
6015
|
+
return Object.assign({ cached: false }, value);
|
|
6016
|
+
}
|
|
6017
|
+
function invalidate(platform) {
|
|
6018
|
+
if (platform) delete CACHE[platform];
|
|
6019
|
+
else for (const k of Object.keys(CACHE)) delete CACHE[k];
|
|
6020
|
+
}
|
|
6021
|
+
module2.exports = {
|
|
6022
|
+
inventory,
|
|
6023
|
+
invalidate,
|
|
6024
|
+
probe,
|
|
6025
|
+
probeWin,
|
|
6026
|
+
probeMac,
|
|
6027
|
+
probeLinux,
|
|
6028
|
+
engineOf,
|
|
6029
|
+
tokenizeExec,
|
|
6030
|
+
parseExecLine,
|
|
6031
|
+
regValueOf,
|
|
6032
|
+
expandEnvVars,
|
|
6033
|
+
exeFromCmdLine,
|
|
6034
|
+
regSubkeys,
|
|
6035
|
+
regKeyFull,
|
|
6036
|
+
regValueTargets,
|
|
6037
|
+
safeRegKeyPart,
|
|
6038
|
+
browserFromDesktop,
|
|
6039
|
+
desktopDirs,
|
|
6040
|
+
resolveLinuxBin,
|
|
6041
|
+
mimeAppsDefault,
|
|
6042
|
+
linuxDefaultFromMimeApps,
|
|
6043
|
+
WIN_APP_PATHS,
|
|
6044
|
+
PROBE_TIMEOUT_MS
|
|
6045
|
+
};
|
|
6046
|
+
}
|
|
6047
|
+
});
|
|
6048
|
+
|
|
5455
6049
|
// src/platform/os/browser.js
|
|
5456
6050
|
var require_browser = __commonJS({
|
|
5457
6051
|
"src/platform/os/browser.js"(exports2, module2) {
|
|
5458
6052
|
"use strict";
|
|
5459
|
-
var fs2 = require("node:fs");
|
|
5460
6053
|
var path2 = require("node:path");
|
|
5461
|
-
var os2 = require("node:os");
|
|
5462
6054
|
var spawnOS = require_spawn();
|
|
5463
6055
|
var desktop = require_desktop();
|
|
5464
6056
|
var CAPABILITY_PROFILES = require_capability_profile();
|
|
5465
6057
|
var { resolveExecutable, isExecutableFile } = require_exec_path();
|
|
5466
|
-
var
|
|
6058
|
+
var detector = require_browser_inventory();
|
|
6059
|
+
var { engineOf } = detector;
|
|
5467
6060
|
function isSafeHttpUrl(url) {
|
|
5468
6061
|
try {
|
|
5469
6062
|
const u = new URL(String(url));
|
|
@@ -5475,7 +6068,7 @@ var require_browser = __commonJS({
|
|
|
5475
6068
|
function openCommand(platform, url) {
|
|
5476
6069
|
const pl = platform || process.platform;
|
|
5477
6070
|
if (pl === "darwin") return { cmd: "open", args: [url] };
|
|
5478
|
-
if (pl === "win32") return
|
|
6071
|
+
if (pl === "win32") return null;
|
|
5479
6072
|
return { cmd: "xdg-open", args: [url] };
|
|
5480
6073
|
}
|
|
5481
6074
|
var SUPPORTED_OPEN_PLATFORMS = Object.keys(CAPABILITY_PROFILES).filter((k) => CAPABILITY_PROFILES[k].openBrowser === true);
|
|
@@ -5496,26 +6089,58 @@ var require_browser = __commonJS({
|
|
|
5496
6089
|
};
|
|
5497
6090
|
}
|
|
5498
6091
|
var CONFIRMED_TEXT = "\u5DF2\u5728\u7CFB\u7EDF\u6D4F\u89C8\u5668\u6253\u5F00";
|
|
5499
|
-
var HANDEDOFF_TEXT = "\u5DF2\u628A\u5730\u5740\u4EA4\u7ED9\u7CFB\u7EDF\uFF0C\u4F46\
|
|
6092
|
+
var HANDEDOFF_TEXT = "\u5DF2\u628A\u5730\u5740\u4EA4\u7ED9\u7CFB\u7EDF\uFF0C\u4F46\u8FD9\u6B21\u542F\u52A8\u62FF\u4E0D\u5230\u7A97\u53E3\u662F\u5426\u51FA\u73B0\u7684\u8BC1\u636E";
|
|
5500
6093
|
var FAILURE_TEXT = {
|
|
5501
6094
|
"unsafe-url": "\u5730\u5740\u4E0D\u662F http(s) \u7EDD\u5BF9 URL\uFF0C\u5DF2\u62D2\u7EDD\u4EA4\u7ED9\u6D4F\u89C8\u5668",
|
|
5502
|
-
"no-launcher": "\u672A\
|
|
6095
|
+
"no-launcher": "\u672A\u80FD\u786E\u5B9A\u8BE5\u7528\u54EA\u4E2A\u6D4F\u89C8\u5668\u6253\u5F00\uFF08\u7CFB\u7EDF\u91CC\u8BFB\u4E0D\u5230\u9ED8\u8BA4\u6D4F\u89C8\u5668\u8BBE\u7F6E\uFF09\uFF0C\u8BF7\u5728\u7CFB\u7EDF\u8BBE\u7F6E\u91CC\u6307\u5B9A\u9ED8\u8BA4\u6D4F\u89C8\u5668\u6216\u624B\u52A8\u6253\u5F00\u8BE5\u5730\u5740",
|
|
5503
6096
|
"spawn-failed": "\u6D4F\u89C8\u5668\u542F\u52A8\u5931\u8D25\uFF08\u7CFB\u7EDF\u62D2\u7EDD\u4E86\u8BE5\u547D\u4EE4\uFF09",
|
|
5504
|
-
"exit-nonzero": "\
|
|
5505
|
-
"killed-by-signal": "\u6D4F\u89C8\u5668\u542F\u52A8\u547D\u4EE4\u88AB\u7CFB\u7EDF\u7EC8\u6B62",
|
|
6097
|
+
"exit-nonzero": "\u7CFB\u7EDF\u62D2\u7EDD\u4E86\u8FD9\u4E2A\u5730\u5740\uFF08\u542F\u52A8\u547D\u4EE4\u975E 0 \u9000\u51FA\uFF09\uFF0C\u7A97\u53E3\u672A\u51FA\u73B0",
|
|
6098
|
+
"killed-by-signal": "\u6D4F\u89C8\u5668\u542F\u52A8\u547D\u4EE4\u88AB\u7CFB\u7EDF\u7EC8\u6B62\uFF0C\u7A97\u53E3\u672A\u51FA\u73B0",
|
|
5506
6099
|
"no-desktop-session": "\u5F53\u524D\u6CA1\u6709\u56FE\u5F62\u4F1A\u8BDD\uFF0C\u65E0\u6CD5\u8C03\u8D77\u6D4F\u89C8\u5668",
|
|
5507
6100
|
"unsupported-platform": "\u5F53\u524D\u5E73\u53F0\u4E0D\u5728\u4EA7\u54C1\u652F\u6301\u7684\u684C\u9762\u5E73\u53F0\u5185\uFF0C\u8BF7\u624B\u52A8\u6253\u5F00\u8BE5\u5730\u5740"
|
|
5508
6101
|
};
|
|
6102
|
+
function ownsItsWindow(via, platform) {
|
|
6103
|
+
if (via !== "dispatcher") return false;
|
|
6104
|
+
return platform !== "win32";
|
|
6105
|
+
}
|
|
6106
|
+
function pickLauncher(platform, inv) {
|
|
6107
|
+
const list = inv && Array.isArray(inv.browsers) ? inv.browsers : [];
|
|
6108
|
+
const id = inv && inv.defaultId;
|
|
6109
|
+
const hit = id ? list.find((b) => b.id === id) : null;
|
|
6110
|
+
if (hit) return { browser: hit, how: inv && inv.defaultSource || "default" };
|
|
6111
|
+
if (list.length === 1) return { browser: list[0], how: "only-installed" };
|
|
6112
|
+
return { browser: null, how: list.length ? "no-default" : "none-found" };
|
|
6113
|
+
}
|
|
6114
|
+
function formOfBin(pl, b) {
|
|
6115
|
+
const engine = b && b.bin ? engineOf(b.bin) : "other";
|
|
6116
|
+
return { engine, direct: !!b && (engine !== "other" || pl === "win32") };
|
|
6117
|
+
}
|
|
5509
6118
|
function openPlan(platform, url, opts) {
|
|
5510
6119
|
const o = opts || {};
|
|
5511
6120
|
const pl = platform || process.platform;
|
|
5512
|
-
const
|
|
5513
|
-
const
|
|
5514
|
-
|
|
5515
|
-
|
|
6121
|
+
const picked = o.pick || pickLauncher(pl, o.inventory);
|
|
6122
|
+
const b = picked.browser;
|
|
6123
|
+
const form = formOfBin(pl, b);
|
|
6124
|
+
if (form.direct) {
|
|
6125
|
+
return {
|
|
6126
|
+
bin: b.bin,
|
|
6127
|
+
engine: form.engine,
|
|
6128
|
+
via: "browser",
|
|
6129
|
+
pick: picked.how,
|
|
6130
|
+
baseArgs: (b.baseArgs || []).concat([url]),
|
|
6131
|
+
exitIsEvidence: ownsItsWindow("browser", pl)
|
|
6132
|
+
};
|
|
5516
6133
|
}
|
|
5517
6134
|
const c = openCommand(pl, url);
|
|
5518
|
-
return { bin:
|
|
6135
|
+
if (!c) return { bin: null, engine: form.engine, via: "none", pick: picked.how, baseArgs: [], exitIsEvidence: false };
|
|
6136
|
+
return {
|
|
6137
|
+
bin: c.cmd,
|
|
6138
|
+
engine: "other",
|
|
6139
|
+
via: "dispatcher",
|
|
6140
|
+
pick: picked.how,
|
|
6141
|
+
baseArgs: c.args,
|
|
6142
|
+
exitIsEvidence: ownsItsWindow("dispatcher", pl)
|
|
6143
|
+
};
|
|
5519
6144
|
}
|
|
5520
6145
|
function observeSpawn(child, windowMs, setTimeoutFn) {
|
|
5521
6146
|
return new Promise((resolve) => {
|
|
@@ -5534,6 +6159,21 @@ var require_browser = __commonJS({
|
|
|
5534
6159
|
});
|
|
5535
6160
|
}
|
|
5536
6161
|
var OPEN_OBSERVE_MS = 1500;
|
|
6162
|
+
function launchDiagnostics(inv, plan, how) {
|
|
6163
|
+
const found = (inv && inv.browsers || []).map((b) => ({
|
|
6164
|
+
name: b.name,
|
|
6165
|
+
engine: b.engine || engineOf(b.bin),
|
|
6166
|
+
via: (b.sources && b.sources.length ? b.sources : [b.source || "unknown"]).join("+")
|
|
6167
|
+
}));
|
|
6168
|
+
return {
|
|
6169
|
+
platform: inv && inv.platform || null,
|
|
6170
|
+
pick: how || plan && plan.pick || "none",
|
|
6171
|
+
bin: plan && plan.bin || null,
|
|
6172
|
+
default: inv && inv.defaultId ? { id: inv.defaultId, source: inv.defaultSource || null } : null,
|
|
6173
|
+
found,
|
|
6174
|
+
probed: inv && inv.probed || []
|
|
6175
|
+
};
|
|
6176
|
+
}
|
|
5537
6177
|
async function openBrowser(url, o) {
|
|
5538
6178
|
const opts = o || {};
|
|
5539
6179
|
const pl = opts.platform || process.platform;
|
|
@@ -5547,16 +6187,27 @@ var require_browser = __commonJS({
|
|
|
5547
6187
|
const spawnWith = typeof opts.spawn === "function" ? opts.spawn : _spawnDetachedIgnored;
|
|
5548
6188
|
const avail = typeof opts.binAvailable === "function" ? opts.binAvailable : binAvailable;
|
|
5549
6189
|
const observe = typeof opts.observe === "function" ? opts.observe : observeSpawn;
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
const
|
|
5555
|
-
|
|
6190
|
+
const resolveInv = typeof opts.resolveInventory === "function" ? opts.resolveInventory : ((platform, deps) => detector.inventory(platform, deps));
|
|
6191
|
+
const inv = "inventory" in opts ? opts.inventory : resolveInv(pl, opts.resolveDeps || {});
|
|
6192
|
+
const plan = openPlan(pl, url, { inventory: inv, pick: opts.pick });
|
|
6193
|
+
const diagnostics = launchDiagnostics(inv, plan, plan.pick);
|
|
6194
|
+
const evidence = {
|
|
6195
|
+
bin: plan.bin,
|
|
6196
|
+
engine: plan.engine,
|
|
6197
|
+
via: plan.via,
|
|
6198
|
+
ownsWindow: plan.exitIsEvidence === true,
|
|
6199
|
+
exitCode: null,
|
|
6200
|
+
exitSignal: null,
|
|
6201
|
+
error: null,
|
|
6202
|
+
diagnostics
|
|
6203
|
+
};
|
|
5556
6204
|
const desktopAvailable = typeof opts.desktopAvailable === "function" ? opts.desktopAvailable : desktop.sessionAvailable;
|
|
5557
6205
|
if (pl === "linux" && !desktopAvailable()) {
|
|
5558
6206
|
return outcome({ ok: false, reason: "no-desktop-session", url, evidence });
|
|
5559
6207
|
}
|
|
6208
|
+
if (!plan.bin) {
|
|
6209
|
+
return outcome({ ok: false, reason: "no-launcher", url, evidence });
|
|
6210
|
+
}
|
|
5560
6211
|
if (!avail(plan.bin)) {
|
|
5561
6212
|
return outcome({ ok: false, reason: "no-launcher", url, evidence });
|
|
5562
6213
|
}
|
|
@@ -5573,7 +6224,8 @@ var require_browser = __commonJS({
|
|
|
5573
6224
|
evidence.exitCode = seen.code === void 0 ? null : seen.code;
|
|
5574
6225
|
evidence.exitSignal = seen.signal === void 0 ? null : seen.signal;
|
|
5575
6226
|
if (seen.stage === "error") return outcome({ ok: false, reason: "spawn-failed", url, evidence });
|
|
5576
|
-
|
|
6227
|
+
const exitDecides = seen.stage === "exit" && plan.exitIsEvidence === true;
|
|
6228
|
+
if (exitDecides && (seen.code !== 0 || seen.signal)) {
|
|
5577
6229
|
return outcome({
|
|
5578
6230
|
ok: false,
|
|
5579
6231
|
reason: seen.signal ? "killed-by-signal" : "exit-nonzero",
|
|
@@ -5582,8 +6234,29 @@ var require_browser = __commonJS({
|
|
|
5582
6234
|
error: FAILURE_TEXT[seen.signal ? "killed-by-signal" : "exit-nonzero"] + "\uFF08" + (seen.signal || seen.code) + "\uFF09"
|
|
5583
6235
|
});
|
|
5584
6236
|
}
|
|
5585
|
-
|
|
5586
|
-
|
|
6237
|
+
return outcome({ ok: true, confirmed: exitDecides, handedOff: !exitDecides, url, evidence });
|
|
6238
|
+
}
|
|
6239
|
+
function listBrowsers(o) {
|
|
6240
|
+
const ov = o || {};
|
|
6241
|
+
const inv = detector.inventory(ov.platform, { force: ov.force === true });
|
|
6242
|
+
return {
|
|
6243
|
+
ok: true,
|
|
6244
|
+
platform: inv.platform,
|
|
6245
|
+
cached: inv.cached === true,
|
|
6246
|
+
default: inv.defaultId ? { id: inv.defaultId, source: inv.defaultSource || null } : null,
|
|
6247
|
+
browsers: (inv.browsers || []).map((b) => ({
|
|
6248
|
+
id: b.id,
|
|
6249
|
+
name: b.name,
|
|
6250
|
+
engine: b.engine || engineOf(b.bin),
|
|
6251
|
+
bin: b.bin,
|
|
6252
|
+
sources: b.sources && b.sources.length ? b.sources : [b.source],
|
|
6253
|
+
isDefault: b.id === inv.defaultId
|
|
6254
|
+
})),
|
|
6255
|
+
probed: inv.probed || []
|
|
6256
|
+
};
|
|
6257
|
+
}
|
|
6258
|
+
function invalidateBrowsers(platform) {
|
|
6259
|
+
return detector.invalidate(platform);
|
|
5587
6260
|
}
|
|
5588
6261
|
function _spawnDetachedIgnored(bin, args) {
|
|
5589
6262
|
try {
|
|
@@ -5614,178 +6287,37 @@ var require_browser = __commonJS({
|
|
|
5614
6287
|
child.unref();
|
|
5615
6288
|
return child;
|
|
5616
6289
|
}
|
|
5617
|
-
function engineOf(bin) {
|
|
5618
|
-
const base = String(bin || "").toLowerCase().split(/[\\/]/).pop();
|
|
5619
|
-
if (/(chrome|chromium|msedge|edge|brave|vivaldi|opera|thorium)/.test(base)) return "chromium";
|
|
5620
|
-
if (/(firefox|librewolf|waterfox)/.test(base)) return "firefox";
|
|
5621
|
-
return "other";
|
|
5622
|
-
}
|
|
5623
|
-
function tokenizeExec(line) {
|
|
5624
|
-
const toks = [];
|
|
5625
|
-
let cur = "";
|
|
5626
|
-
let q = null;
|
|
5627
|
-
let esc = false;
|
|
5628
|
-
let has = false;
|
|
5629
|
-
for (const ch of String(line)) {
|
|
5630
|
-
if (esc) {
|
|
5631
|
-
cur += ch;
|
|
5632
|
-
esc = false;
|
|
5633
|
-
continue;
|
|
5634
|
-
}
|
|
5635
|
-
if (ch === "\\") {
|
|
5636
|
-
esc = true;
|
|
5637
|
-
has = true;
|
|
5638
|
-
continue;
|
|
5639
|
-
}
|
|
5640
|
-
if (q) {
|
|
5641
|
-
if (ch === q) q = null;
|
|
5642
|
-
else cur += ch;
|
|
5643
|
-
continue;
|
|
5644
|
-
}
|
|
5645
|
-
if (ch === "'" || ch === '"') {
|
|
5646
|
-
q = ch;
|
|
5647
|
-
has = true;
|
|
5648
|
-
continue;
|
|
5649
|
-
}
|
|
5650
|
-
if (/\s/.test(ch)) {
|
|
5651
|
-
if (has) {
|
|
5652
|
-
toks.push(cur);
|
|
5653
|
-
cur = "";
|
|
5654
|
-
has = false;
|
|
5655
|
-
}
|
|
5656
|
-
continue;
|
|
5657
|
-
}
|
|
5658
|
-
cur += ch;
|
|
5659
|
-
has = true;
|
|
5660
|
-
}
|
|
5661
|
-
if (has) toks.push(cur);
|
|
5662
|
-
return toks;
|
|
5663
|
-
}
|
|
5664
|
-
function parseExecLine(line) {
|
|
5665
|
-
let toks = tokenizeExec(line).filter((t) => t !== "%%" && !/^%[a-zA-Z]$/.test(t));
|
|
5666
|
-
if (toks[0] === "env") {
|
|
5667
|
-
let i = 1;
|
|
5668
|
-
while (i < toks.length && /=/.test(toks[i])) i++;
|
|
5669
|
-
toks = toks.slice(i);
|
|
5670
|
-
}
|
|
5671
|
-
if (!toks.length) return null;
|
|
5672
|
-
return { bin: toks[0], baseArgs: toks.slice(1) };
|
|
5673
|
-
}
|
|
5674
|
-
function regValueOf(out) {
|
|
5675
|
-
const m = String(out || "").match(/REG_SZ\s+(.*)/);
|
|
5676
|
-
return m ? m[1].trim() : null;
|
|
5677
|
-
}
|
|
5678
|
-
function exeFromCmdLine(cmdLine) {
|
|
5679
|
-
const s = String(cmdLine || "");
|
|
5680
|
-
let m = s.match(/^\s*"([^"]+\.exe)"/i);
|
|
5681
|
-
if (m) return m[1];
|
|
5682
|
-
m = s.match(/^\s*(\S+\.exe)/i);
|
|
5683
|
-
return m ? m[1] : null;
|
|
5684
|
-
}
|
|
5685
|
-
function resolveDefaultWin(runOut) {
|
|
5686
|
-
const roots = ["HKCU\\Software\\Clients\\StartMenuInternet", "HKLM\\Software\\Clients\\StartMenuInternet"];
|
|
5687
|
-
for (const root of roots) {
|
|
5688
|
-
const progId = regValueOf(runOut("reg.exe", ["query", root, "/ve"]));
|
|
5689
|
-
if (!progId || !/^[\x20-\x7e]+$/.test(progId)) continue;
|
|
5690
|
-
for (const r2 of roots) {
|
|
5691
|
-
const cmd2 = regValueOf(runOut("reg.exe", ["query", r2 + "\\" + progId + "\\shell\\open\\command", "/ve"]));
|
|
5692
|
-
const bin = exeFromCmdLine(cmd2);
|
|
5693
|
-
if (bin) return { bin, baseArgs: [] };
|
|
5694
|
-
}
|
|
5695
|
-
}
|
|
5696
|
-
return null;
|
|
5697
|
-
}
|
|
5698
|
-
var MAC_JXA = [
|
|
5699
|
-
"ObjC.import('CoreServices');ObjC.import('Foundation');",
|
|
5700
|
-
"var b=ObjC.unwrap($.LSCopyDefaultHandlerForURLScheme(null,'https'))||ObjC.unwrap($.LSCopyDefaultHandlerForURLScheme(null,'http'));",
|
|
5701
|
-
"if(!b){'EMPTY';}else{",
|
|
5702
|
-
"var u=$.NSWorkspace.workspace.URLForApplicationWithBundleIdentifier(b);",
|
|
5703
|
-
"if(u.isNil()){'EMPTY';}else{",
|
|
5704
|
-
"var e=ObjC.unwrap($.NSBundle.bundleWithURL(u).objectForInfoDictionaryKey('CFBundleExecutable'));",
|
|
5705
|
-
"b+'\\t'+ObjC.unwrap(u.path)+'\\t'+e;}}"
|
|
5706
|
-
].join("");
|
|
5707
|
-
function resolveDefaultMac(runOut) {
|
|
5708
|
-
const out = runOut("osascript", ["-l", "JavaScript", "-e", MAC_JXA]);
|
|
5709
|
-
if (!out) return null;
|
|
5710
|
-
const parts = out.trim().split(" ");
|
|
5711
|
-
if (parts.length < 3 || parts[0] === "EMPTY" || !parts[2]) return null;
|
|
5712
|
-
return { bin: path2.posix.join(parts[1], "Contents", "MacOS", parts[2]), baseArgs: [], bundleId: parts[0] };
|
|
5713
|
-
}
|
|
5714
|
-
function resolveDefaultLinux(runOut, readFile, exists, env, home) {
|
|
5715
|
-
const id = runOut("xdg-settings", ["get", "default-web-browser"]);
|
|
5716
|
-
const desktop2 = id && id.trim();
|
|
5717
|
-
if (!desktop2 || !/^[A-Za-z0-9._-]+\.desktop$/.test(desktop2)) return null;
|
|
5718
|
-
const dirs = [
|
|
5719
|
-
env.XDG_DATA_HOME || path2.join(home, ".local", "share"),
|
|
5720
|
-
"/usr/local/share",
|
|
5721
|
-
"/usr/share",
|
|
5722
|
-
"/var/lib/snapd/desktop"
|
|
5723
|
-
].map((d) => path2.join(d, "applications"));
|
|
5724
|
-
for (const dir of dirs) {
|
|
5725
|
-
const p = path2.join(dir, desktop2);
|
|
5726
|
-
let text = null;
|
|
5727
|
-
try {
|
|
5728
|
-
if (exists(p)) text = readFile(p);
|
|
5729
|
-
} catch {
|
|
5730
|
-
continue;
|
|
5731
|
-
}
|
|
5732
|
-
if (text === null) continue;
|
|
5733
|
-
let inMain = false;
|
|
5734
|
-
for (const line of text.split(/\r?\n/)) {
|
|
5735
|
-
if (/^\[Desktop Entry\]\s*$/.test(line)) {
|
|
5736
|
-
inMain = true;
|
|
5737
|
-
continue;
|
|
5738
|
-
}
|
|
5739
|
-
if (/^\[/.test(line)) break;
|
|
5740
|
-
if (inMain) {
|
|
5741
|
-
const m = line.match(/^Exec=(.+)/);
|
|
5742
|
-
if (m) return parseExecLine(m[1]);
|
|
5743
|
-
}
|
|
5744
|
-
}
|
|
5745
|
-
}
|
|
5746
|
-
return null;
|
|
5747
|
-
}
|
|
5748
|
-
function resolveDefaultBrowser(platform, o) {
|
|
5749
|
-
const ov = o || {};
|
|
5750
|
-
const pl = platform || process.platform;
|
|
5751
|
-
const runOut = ov.runOut || ((bin, args) => exec.runOut(bin, args, { timeoutMs: 5e3 }));
|
|
5752
|
-
const readFile = ov.readFile || ((p) => fs2.readFileSync(p, "utf8"));
|
|
5753
|
-
const exists = ov.exists || ((p) => fs2.existsSync(p));
|
|
5754
|
-
const env = ov.env || process.env;
|
|
5755
|
-
const home = ov.home || os2.homedir();
|
|
5756
|
-
try {
|
|
5757
|
-
if (pl === "win32") return resolveDefaultWin(runOut);
|
|
5758
|
-
if (pl === "darwin") return resolveDefaultMac(runOut);
|
|
5759
|
-
return resolveDefaultLinux(runOut, readFile, exists, env, home);
|
|
5760
|
-
} catch {
|
|
5761
|
-
return null;
|
|
5762
|
-
}
|
|
5763
|
-
}
|
|
5764
6290
|
function isolatedPlan(platform, url, opts) {
|
|
5765
6291
|
const o = opts || {};
|
|
5766
6292
|
const pl = platform || process.platform;
|
|
5767
|
-
const
|
|
5768
|
-
const
|
|
5769
|
-
const
|
|
5770
|
-
|
|
6293
|
+
const picked = o.pick || pickLauncher(pl, o.inventory);
|
|
6294
|
+
const b = picked.browser;
|
|
6295
|
+
const form = formOfBin(pl, b);
|
|
6296
|
+
const baseArgs = b && b.baseArgs || [];
|
|
6297
|
+
if (form.direct && form.engine === "chromium" && o.profileDir) {
|
|
5771
6298
|
const args = ["--incognito", "--user-data-dir=" + o.profileDir];
|
|
5772
6299
|
if (Array.isArray(o.size) && o.size.length === 2) args.push("--window-size=" + o.size[0] + "," + o.size[1]);
|
|
5773
6300
|
if (o.lang) args.push("--lang=" + o.lang);
|
|
5774
6301
|
args.push("--no-first-run", "--no-default-browser-check", "--disable-session-crashed-bubble");
|
|
5775
|
-
return { bin:
|
|
6302
|
+
return { bin: b.bin, args: [...baseArgs, ...args, url], isolated: true, watch: true, envKind: "anti", label: "chromium", pick: picked.how };
|
|
5776
6303
|
}
|
|
5777
|
-
if (engine === "firefox" && o.profileDir) {
|
|
6304
|
+
if (form.direct && form.engine === "firefox" && o.profileDir) {
|
|
5778
6305
|
return {
|
|
5779
|
-
bin:
|
|
6306
|
+
bin: b.bin,
|
|
5780
6307
|
args: [...baseArgs, "--no-remote", "--profile", o.profileDir, "-private-window", url],
|
|
5781
6308
|
isolated: true,
|
|
5782
6309
|
watch: true,
|
|
5783
6310
|
envKind: "anti",
|
|
5784
|
-
label: "firefox"
|
|
6311
|
+
label: "firefox",
|
|
6312
|
+
pick: picked.how
|
|
5785
6313
|
};
|
|
5786
6314
|
}
|
|
6315
|
+
if (form.direct) {
|
|
6316
|
+
return { bin: b.bin, args: baseArgs.concat([url]), isolated: false, watch: false, envKind: "sys", label: path2.basename(b.bin), pick: picked.how };
|
|
6317
|
+
}
|
|
5787
6318
|
const c = openCommand(pl, url);
|
|
5788
|
-
return { bin:
|
|
6319
|
+
if (!c) return { bin: null, args: [url], isolated: false, watch: false, envKind: "sys", label: null, pick: picked.how };
|
|
6320
|
+
return { bin: c.cmd, args: c.args, isolated: false, watch: false, envKind: "sys", label: c.cmd, pick: picked.how };
|
|
5789
6321
|
}
|
|
5790
6322
|
function binAvailable(bin) {
|
|
5791
6323
|
if (!bin) return false;
|
|
@@ -5802,21 +6334,21 @@ var require_browser = __commonJS({
|
|
|
5802
6334
|
const spawnWith = typeof opts.spawn === "function" ? opts.spawn : _spawnDetached;
|
|
5803
6335
|
const fail = (reason, extra) => Object.assign(outcome(Object.assign({ ok: false, reason, url }, extra)), { bin: null, isolated: false });
|
|
5804
6336
|
try {
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
else if (typeof opts.resolveDefault === "function") db = opts.resolveDefault(process.platform, opts.resolveDeps || {});
|
|
5808
|
-
else db = resolveDefaultBrowser(process.platform, opts.resolveDeps || {});
|
|
6337
|
+
const resolveInv = typeof opts.resolveInventory === "function" ? opts.resolveInventory : ((platform, deps) => detector.inventory(platform, deps));
|
|
6338
|
+
const inv = "inventory" in opts ? opts.inventory : resolveInv(process.platform, opts.resolveDeps || {});
|
|
5809
6339
|
const plan = isolatedPlan(process.platform, url, {
|
|
5810
|
-
|
|
6340
|
+
inventory: inv,
|
|
6341
|
+
pick: opts.pick,
|
|
5811
6342
|
profileDir: opts.profileDir,
|
|
5812
6343
|
size: opts.size,
|
|
5813
6344
|
lang: opts.lang
|
|
5814
6345
|
});
|
|
5815
|
-
|
|
6346
|
+
const evidence = { bin: plan.bin, engine: plan.label, via: plan.isolated ? "browser" : "dispatcher", diagnostics: launchDiagnostics(inv, plan, plan.pick) };
|
|
6347
|
+
if (!avail(plan.bin)) return fail("no-launcher", { evidence });
|
|
5816
6348
|
const env = plan.envKind === "anti" ? antiEnv : sysEnv;
|
|
5817
6349
|
const p = spawnWith(plan.bin, plan.args, env, plan.watch ? onExit : void 0);
|
|
5818
|
-
if (!p) return fail("spawn-failed");
|
|
5819
|
-
return Object.assign(outcome({ ok: true, confirmed: false, handedOff: true, url }), { bin: plan.label, isolated: plan.isolated });
|
|
6350
|
+
if (!p) return fail("spawn-failed", { evidence });
|
|
6351
|
+
return Object.assign(outcome({ ok: true, confirmed: false, handedOff: true, url, evidence }), { bin: plan.label, isolated: plan.isolated });
|
|
5820
6352
|
} catch (e) {
|
|
5821
6353
|
return fail("spawn-failed", { error: FAILURE_TEXT["spawn-failed"] + "\uFF08" + (e && e.code || e) + "\uFF09" });
|
|
5822
6354
|
}
|
|
@@ -5827,18 +6359,18 @@ var require_browser = __commonJS({
|
|
|
5827
6359
|
openCommand,
|
|
5828
6360
|
openPlan,
|
|
5829
6361
|
isolatedPlan,
|
|
6362
|
+
pickLauncher,
|
|
6363
|
+
ownsItsWindow,
|
|
5830
6364
|
observeSpawn,
|
|
5831
6365
|
isSafeHttpUrl,
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
6366
|
+
binAvailable,
|
|
6367
|
+
listBrowsers,
|
|
6368
|
+
invalidateBrowsers,
|
|
6369
|
+
launchDiagnostics,
|
|
6370
|
+
// 探测层的解析原语经此转出(唯一实现处在 ./browser-inventory.js):门禁与消费方按同一出口取用,
|
|
6371
|
+
// 不在别处再写第二份平台解析。
|
|
5836
6372
|
engineOf,
|
|
5837
|
-
|
|
5838
|
-
tokenizeExec,
|
|
5839
|
-
regValueOf,
|
|
5840
|
-
exeFromCmdLine,
|
|
5841
|
-
binAvailable
|
|
6373
|
+
detector
|
|
5842
6374
|
};
|
|
5843
6375
|
}
|
|
5844
6376
|
});
|
|
@@ -17684,44 +18216,13 @@ var require_browser2 = __commonJS({
|
|
|
17684
18216
|
"src/domains/router/ops/browser.js"(exports2, module2) {
|
|
17685
18217
|
"use strict";
|
|
17686
18218
|
var platform = require_os();
|
|
18219
|
+
var desktop = require_desktop();
|
|
17687
18220
|
var fs2 = require("node:fs");
|
|
17688
18221
|
var os2 = require("node:os");
|
|
17689
18222
|
var path2 = require("node:path");
|
|
17690
18223
|
var crypto = require("node:crypto");
|
|
17691
18224
|
function graphicalEnv() {
|
|
17692
|
-
|
|
17693
|
-
try {
|
|
17694
|
-
const uid = process.getuid ? String(process.getuid()) : "";
|
|
17695
|
-
const xdgRun = process.env.XDG_RUNTIME_DIR || "/run/user/" + uid;
|
|
17696
|
-
if (!process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
|
|
17697
|
-
const x11 = "/tmp/.X11-unix";
|
|
17698
|
-
try {
|
|
17699
|
-
if (fs2.existsSync(x11)) {
|
|
17700
|
-
const socks = fs2.readdirSync(x11).filter((f) => /^X\d+$/.test(f)).map((f) => parseInt(f.slice(1), 10)).sort((a, b) => a - b);
|
|
17701
|
-
if (socks.length > 0) {
|
|
17702
|
-
out.DISPLAY = ":" + socks[0];
|
|
17703
|
-
const xauth = path2.join(os2.homedir(), ".Xauthority");
|
|
17704
|
-
if (fs2.existsSync(xauth)) out.XAUTHORITY = xauth;
|
|
17705
|
-
}
|
|
17706
|
-
}
|
|
17707
|
-
} catch {
|
|
17708
|
-
}
|
|
17709
|
-
if (!out.DISPLAY) {
|
|
17710
|
-
try {
|
|
17711
|
-
if (fs2.existsSync(xdgRun)) {
|
|
17712
|
-
const wl = fs2.readdirSync(xdgRun).filter((f) => f.startsWith("wayland-")).sort();
|
|
17713
|
-
if (wl.length > 0) out.WAYLAND_DISPLAY = wl[0];
|
|
17714
|
-
}
|
|
17715
|
-
} catch {
|
|
17716
|
-
}
|
|
17717
|
-
}
|
|
17718
|
-
}
|
|
17719
|
-
if (!process.env.DBUS_SESSION_BUS_ADDRESS && fs2.existsSync(path2.join(xdgRun, "bus"))) {
|
|
17720
|
-
out.DBUS_SESSION_BUS_ADDRESS = "unix:path=" + path2.join(xdgRun, "bus");
|
|
17721
|
-
}
|
|
17722
|
-
} catch {
|
|
17723
|
-
}
|
|
17724
|
-
return out;
|
|
18225
|
+
return desktop.sessionEnv();
|
|
17725
18226
|
}
|
|
17726
18227
|
function openInBrowser(url, onExit) {
|
|
17727
18228
|
try {
|
|
@@ -17960,6 +18461,7 @@ var require_oauth = __commonJS({
|
|
|
17960
18461
|
confirmed: false,
|
|
17961
18462
|
handedOff: false,
|
|
17962
18463
|
reason: evidence.reason || "no-launcher",
|
|
18464
|
+
evidence: evidence.evidence || null,
|
|
17963
18465
|
error: (evidence.error || "\u65E0\u6CD5\u8C03\u8D77\u7CFB\u7EDF\u6D4F\u89C8\u5668") + "\uFF0C\u8BF7\u624B\u52A8\u6253\u5F00\u4E0B\u65B9\u5730\u5740\u5B8C\u6210\u6388\u6743"
|
|
17964
18466
|
};
|
|
17965
18467
|
}
|
|
@@ -25507,7 +26009,7 @@ var require_guard = __commonJS({
|
|
|
25507
26009
|
var fs2 = require("node:fs");
|
|
25508
26010
|
var path2 = require("node:path");
|
|
25509
26011
|
function owns(pathname) {
|
|
25510
|
-
return pathname === "/changelog" || pathname.startsWith("/guard/") || pathname === "/autostart" || pathname.startsWith("/settings/") || pathname.startsWith("/self-update/") || pathname === "/env/dsh" || pathname === "/env/status" || pathname === "/env/node-lts" || pathname === "/env/open-url" || pathname === "/ports" || pathname === "/shutdown";
|
|
26012
|
+
return pathname === "/changelog" || pathname.startsWith("/guard/") || pathname === "/autostart" || pathname.startsWith("/settings/") || pathname.startsWith("/self-update/") || pathname === "/env/dsh" || pathname === "/env/status" || pathname === "/env/node-lts" || pathname === "/env/open-url" || pathname === "/env/browsers" || pathname === "/ports" || pathname === "/shutdown";
|
|
25511
26013
|
}
|
|
25512
26014
|
function fetchDshChangelog(res, sup) {
|
|
25513
26015
|
const v = sup && sup.nativeManager ? sup.nativeManager.versionInfo() : {};
|
|
@@ -25683,6 +26185,14 @@ var require_guard = __commonJS({
|
|
|
25683
26185
|
if (req.method === "GET" && pathname === "/env/node-lts") {
|
|
25684
26186
|
return sup.nodeLtsStatus().then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: e.message }));
|
|
25685
26187
|
}
|
|
26188
|
+
if (req.method === "GET" && pathname === "/env/browsers") {
|
|
26189
|
+
if (!originAllowed(req, sup.config.apiPort)) {
|
|
26190
|
+
req.resume();
|
|
26191
|
+
return send(403, { ok: false, error: "cross-origin request rejected" });
|
|
26192
|
+
}
|
|
26193
|
+
const force = /[?&]force=1/.test(req.url || "");
|
|
26194
|
+
return Promise.resolve(browser.listBrowsers({ force })).then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: "\u6D4F\u89C8\u5668\u63A2\u6D4B\u5931\u8D25\uFF1A" + (e && e.message || e) }));
|
|
26195
|
+
}
|
|
25686
26196
|
if (req.method === "POST" && pathname === "/env/open-url") {
|
|
25687
26197
|
if (!identity.loopback) {
|
|
25688
26198
|
req.resume();
|