@dsh-sup/dsh-core-linux-x64 0.1.6-BETA.12 → 0.1.6-BETA.14
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 +1216 -389
- package/package.json +1 -1
- package/ui-react/assets/{InstancesPage-DadqCqud.js → InstancesPage-DhR8E6q2.js} +1 -1
- package/ui-react/assets/{LanPage-DWzQ-VLz.js → LanPage-BymkZ5Lp.js} +1 -1
- package/ui-react/assets/OverviewPage-BwAeZq3_.js +2 -0
- package/ui-react/assets/{PluginsPage-BwLIhj7E.js → PluginsPage-D9nLksEp.js} +1 -1
- package/ui-react/assets/{RouterPage-BeMIxdSL.js → RouterPage-B_dPmJbu.js} +1 -1
- package/ui-react/assets/{SettingsPage-R7lkiQwq.js → SettingsPage-C-iKRaHC.js} +1 -1
- package/ui-react/assets/{TasksPage-A3SFro8F.js → TasksPage-CceWxOiG.js} +1 -1
- package/ui-react/assets/openExternal-RPwenHBw.js +1 -0
- package/ui-react/assets/{refresh-cw-B-VAKpDt.js → refresh-cw-qHR0pOo6.js} +1 -1
- package/ui-react/assets/{rocket-CLAmwatt.js → rocket-qAs1Npqn.js} +1 -1
- package/ui-react/assets/{shield-check-CMRwmPpk.js → shield-check-DdnUZAa0.js} +1 -1
- package/ui-react/assets/{supervisor-Btn_MIEc.js → supervisor-Af5v0BTw.js} +3 -3
- package/ui-react/assets/supervisor-C1zJELaq.css +2 -0
- package/ui-react/assets/{supervisor-BbSavtNN.js → supervisor-CWSt_-Ws.js} +1 -1
- package/ui-react/assets/{useSupervisorAction-q0YJmhui.js → useSupervisorAction-CeZGHqFZ.js} +1 -1
- package/ui-react/assets/{widgets-BbRkZm-Z.js → widgets-BhlrHuez.js} +1 -1
- package/ui-react/supervisor.html +3 -3
- package/ui-react/assets/OverviewPage-D9y-GeR2.js +0 -2
- package/ui-react/assets/openExternal-DOkxrLUq.js +0 -1
- package/ui-react/assets/supervisor-YWIsBeZU.css +0 -2
package/core.cjs
CHANGED
|
@@ -833,7 +833,11 @@ var require_config = __commonJS({
|
|
|
833
833
|
// 不配置 = LAN 受 RFC1918 白名单约束,FRP 暴露仍强制 remoteToken。
|
|
834
834
|
apiAccessKey: null,
|
|
835
835
|
// 关闭窗口行为(系统级):'hide' = 隐藏至托盘、服务常驻(默认);'exit' = 退出管家并停全部服务链。
|
|
836
|
-
closeAction: "hide"
|
|
836
|
+
closeAction: "hide",
|
|
837
|
+
// 外部打开的浏览器偏好(系统级,本机配置):存环境表单候选清单里的 id,null = 未选。
|
|
838
|
+
// 与「系统默认浏览器」分两个字段是刻意的:前者是用户在本产品里的选择,后者是操作系统的事实;
|
|
839
|
+
// 系统说不出默认时按候选次序分发并如实标注,用户可在这里定一次覆盖它(见 platform/os/environment.js)。
|
|
840
|
+
externalBrowser: null
|
|
837
841
|
};
|
|
838
842
|
function buildDefaults2(ext) {
|
|
839
843
|
const pending = normalizeExtension(ext).defaults.slice();
|
|
@@ -947,7 +951,7 @@ var require_version = __commonJS({
|
|
|
947
951
|
var fs2 = require("node:fs");
|
|
948
952
|
var path2 = require("node:path");
|
|
949
953
|
function guardVersion() {
|
|
950
|
-
if (true) return String("0.1.6-BETA.
|
|
954
|
+
if (true) return String("0.1.6-BETA.14");
|
|
951
955
|
try {
|
|
952
956
|
return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
|
|
953
957
|
} catch {
|
|
@@ -1080,6 +1084,7 @@ var require_fs = __commonJS({
|
|
|
1080
1084
|
"src/platform/util/fs.js"(exports2, module2) {
|
|
1081
1085
|
"use strict";
|
|
1082
1086
|
var fs2 = require("node:fs");
|
|
1087
|
+
var os2 = require("node:os");
|
|
1083
1088
|
var path2 = require("node:path");
|
|
1084
1089
|
function dirSizeBytes(root) {
|
|
1085
1090
|
let total = 0;
|
|
@@ -1140,7 +1145,26 @@ var require_fs = __commonJS({
|
|
|
1140
1145
|
throw e;
|
|
1141
1146
|
}
|
|
1142
1147
|
}
|
|
1143
|
-
|
|
1148
|
+
function removeTreeDeferred(dir, ms) {
|
|
1149
|
+
if (!dir) return null;
|
|
1150
|
+
const t = setTimeout(() => {
|
|
1151
|
+
try {
|
|
1152
|
+
fs2.rmSync(dir, { recursive: true, force: true });
|
|
1153
|
+
} catch {
|
|
1154
|
+
}
|
|
1155
|
+
}, ms === void 0 ? 6e4 : ms);
|
|
1156
|
+
if (t.unref) t.unref();
|
|
1157
|
+
return t;
|
|
1158
|
+
}
|
|
1159
|
+
function allocTempDir(prefix) {
|
|
1160
|
+
const dir = fs2.mkdtempSync(path2.join(os2.tmpdir(), prefix || "dsh-"));
|
|
1161
|
+
try {
|
|
1162
|
+
fs2.chmodSync(dir, 448);
|
|
1163
|
+
} catch {
|
|
1164
|
+
}
|
|
1165
|
+
return dir;
|
|
1166
|
+
}
|
|
1167
|
+
module2.exports = { dirSizeBytes, writeAtomic, removeTreeDeferred, allocTempDir };
|
|
1144
1168
|
}
|
|
1145
1169
|
});
|
|
1146
1170
|
|
|
@@ -4639,23 +4663,66 @@ var require_desktop = __commonJS({
|
|
|
4639
4663
|
"src/platform/os/desktop.js"(exports2, module2) {
|
|
4640
4664
|
"use strict";
|
|
4641
4665
|
var fs2 = require("node:fs");
|
|
4666
|
+
var os2 = require("node:os");
|
|
4667
|
+
var path2 = require("node:path");
|
|
4642
4668
|
var PLATFORM = process.platform;
|
|
4643
|
-
|
|
4669
|
+
var X11_DIR = "/tmp/.X11-unix";
|
|
4670
|
+
function deps(o) {
|
|
4671
|
+
const ov = o || {};
|
|
4672
|
+
return {
|
|
4673
|
+
env: ov.env || process.env,
|
|
4674
|
+
readdir: ov.readdir || ((p) => fs2.readdirSync(p)),
|
|
4675
|
+
exists: ov.exists || ((p) => fs2.existsSync(p)),
|
|
4676
|
+
home: ov.home || os2.homedir(),
|
|
4677
|
+
uid: typeof process.getuid === "function" ? process.getuid() : 0
|
|
4678
|
+
};
|
|
4679
|
+
}
|
|
4680
|
+
function runtimeDir(env, uid) {
|
|
4681
|
+
return env.XDG_RUNTIME_DIR || "/run/user/" + uid;
|
|
4682
|
+
}
|
|
4683
|
+
function x11Displays(o) {
|
|
4684
|
+
const d = deps(o);
|
|
4644
4685
|
try {
|
|
4645
|
-
return
|
|
4686
|
+
return d.readdir(X11_DIR).filter((f) => /^X\d+$/.test(f)).map((f) => Number(f.slice(1))).sort((a, b) => a - b);
|
|
4646
4687
|
} catch {
|
|
4647
|
-
return
|
|
4688
|
+
return [];
|
|
4648
4689
|
}
|
|
4649
4690
|
}
|
|
4650
|
-
function
|
|
4651
|
-
const
|
|
4652
|
-
const rt = process.env.XDG_RUNTIME_DIR || "/run/user/" + uid;
|
|
4691
|
+
function waylandSockets(o) {
|
|
4692
|
+
const d = deps(o);
|
|
4653
4693
|
try {
|
|
4654
|
-
return
|
|
4694
|
+
return d.readdir(runtimeDir(d.env, d.uid)).filter((f) => /^wayland-\d+$/.test(f)).sort();
|
|
4655
4695
|
} catch {
|
|
4656
|
-
return
|
|
4696
|
+
return [];
|
|
4657
4697
|
}
|
|
4658
4698
|
}
|
|
4699
|
+
function hasX11Socket(o) {
|
|
4700
|
+
return x11Displays(o).length > 0;
|
|
4701
|
+
}
|
|
4702
|
+
function hasWaylandSocket(o) {
|
|
4703
|
+
return waylandSockets(o).length > 0;
|
|
4704
|
+
}
|
|
4705
|
+
function sessionEnv(o) {
|
|
4706
|
+
const d = deps(o);
|
|
4707
|
+
const out = {};
|
|
4708
|
+
if (PLATFORM !== "linux") return out;
|
|
4709
|
+
if (!d.env.DISPLAY && !d.env.WAYLAND_DISPLAY) {
|
|
4710
|
+
const xs = x11Displays(d);
|
|
4711
|
+
if (xs.length) {
|
|
4712
|
+
out.DISPLAY = ":" + xs[0];
|
|
4713
|
+
const xauth = path2.join(d.home, ".Xauthority");
|
|
4714
|
+
if (d.exists(xauth)) out.XAUTHORITY = xauth;
|
|
4715
|
+
} else {
|
|
4716
|
+
const wl = waylandSockets(d);
|
|
4717
|
+
if (wl.length) out.WAYLAND_DISPLAY = wl[0];
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
if (!d.env.DBUS_SESSION_BUS_ADDRESS) {
|
|
4721
|
+
const bus = path2.join(runtimeDir(d.env, d.uid), "bus");
|
|
4722
|
+
if (d.exists(bus)) out.DBUS_SESSION_BUS_ADDRESS = "unix:path=" + bus;
|
|
4723
|
+
}
|
|
4724
|
+
return out;
|
|
4725
|
+
}
|
|
4659
4726
|
function sessionAvailable() {
|
|
4660
4727
|
if (PLATFORM === "linux") {
|
|
4661
4728
|
if (process.env.DISPLAY || process.env.WAYLAND_DISPLAY) return true;
|
|
@@ -4682,7 +4749,7 @@ var require_desktop = __commonJS({
|
|
|
4682
4749
|
reason: "session-scoped-by-launcher"
|
|
4683
4750
|
};
|
|
4684
4751
|
}
|
|
4685
|
-
module2.exports = { sessionAvailable, describe, PLATFORM };
|
|
4752
|
+
module2.exports = { sessionAvailable, sessionEnv, describe, x11Displays, waylandSockets, PLATFORM };
|
|
4686
4753
|
}
|
|
4687
4754
|
});
|
|
4688
4755
|
|
|
@@ -4755,8 +4822,9 @@ var require_capability_profile = __commonJS({
|
|
|
4755
4822
|
autostart: true,
|
|
4756
4823
|
// 期望 schtasks(实测覆写)
|
|
4757
4824
|
frpExpose: true,
|
|
4758
|
-
// 可打开,但
|
|
4759
|
-
//
|
|
4825
|
+
// 可打开,但 Windows 没有可信调度器(系统调度器只有 darwin 的 open 与 linux 的 xdg-open),
|
|
4826
|
+
// 只能直启探测层解析出的浏览器本体;浏览器已在运行时本次进程只转交地址,退出码与窗口出现与否无关,
|
|
4827
|
+
// 故该平台每次调用最多到 handedOff(判据见 browser.js#ownsItsWindow)。能力位只声明「能交出去」。
|
|
4760
4828
|
openBrowser: true,
|
|
4761
4829
|
hostService: "windows-service",
|
|
4762
4830
|
guardAutostart: true,
|
|
@@ -4787,6 +4855,784 @@ var require_capability_profile = __commonJS({
|
|
|
4787
4855
|
}
|
|
4788
4856
|
});
|
|
4789
4857
|
|
|
4858
|
+
// src/platform/os/browser-inventory.js
|
|
4859
|
+
var require_browser_inventory = __commonJS({
|
|
4860
|
+
"src/platform/os/browser-inventory.js"(exports2, module2) {
|
|
4861
|
+
"use strict";
|
|
4862
|
+
var fs2 = require("node:fs");
|
|
4863
|
+
var path2 = require("node:path");
|
|
4864
|
+
var os2 = require("node:os");
|
|
4865
|
+
var exec = require_exec();
|
|
4866
|
+
var { isExecutableFile } = require_exec_path();
|
|
4867
|
+
var PROBE_TIMEOUT_MS = 1500;
|
|
4868
|
+
function engineOf(bin) {
|
|
4869
|
+
const base = String(bin || "").toLowerCase().split(/[\\/]/).pop();
|
|
4870
|
+
if (/(chrome|chromium|msedge|edge|brave|vivaldi|opera|thorium)/.test(base)) return "chromium";
|
|
4871
|
+
if (/(firefox|librewolf|waterfox)/.test(base)) return "firefox";
|
|
4872
|
+
return "other";
|
|
4873
|
+
}
|
|
4874
|
+
function tokenizeExec(line) {
|
|
4875
|
+
const toks = [];
|
|
4876
|
+
let cur = "";
|
|
4877
|
+
let q = null;
|
|
4878
|
+
let esc = false;
|
|
4879
|
+
let has = false;
|
|
4880
|
+
for (const ch of String(line)) {
|
|
4881
|
+
if (esc) {
|
|
4882
|
+
cur += ch;
|
|
4883
|
+
esc = false;
|
|
4884
|
+
continue;
|
|
4885
|
+
}
|
|
4886
|
+
if (ch === "\\") {
|
|
4887
|
+
esc = true;
|
|
4888
|
+
has = true;
|
|
4889
|
+
continue;
|
|
4890
|
+
}
|
|
4891
|
+
if (q) {
|
|
4892
|
+
if (ch === q) q = null;
|
|
4893
|
+
else cur += ch;
|
|
4894
|
+
continue;
|
|
4895
|
+
}
|
|
4896
|
+
if (ch === "'" || ch === '"') {
|
|
4897
|
+
q = ch;
|
|
4898
|
+
has = true;
|
|
4899
|
+
continue;
|
|
4900
|
+
}
|
|
4901
|
+
if (/\s/.test(ch)) {
|
|
4902
|
+
if (has) {
|
|
4903
|
+
toks.push(cur);
|
|
4904
|
+
cur = "";
|
|
4905
|
+
has = false;
|
|
4906
|
+
}
|
|
4907
|
+
continue;
|
|
4908
|
+
}
|
|
4909
|
+
cur += ch;
|
|
4910
|
+
has = true;
|
|
4911
|
+
}
|
|
4912
|
+
if (has) toks.push(cur);
|
|
4913
|
+
return toks;
|
|
4914
|
+
}
|
|
4915
|
+
function parseExecLine(line) {
|
|
4916
|
+
let toks = tokenizeExec(line).filter((t) => t !== "%%" && !/^%[a-zA-Z]$/.test(t));
|
|
4917
|
+
if (toks[0] === "env") {
|
|
4918
|
+
let i = 1;
|
|
4919
|
+
while (i < toks.length && /=/.test(toks[i])) i++;
|
|
4920
|
+
toks = toks.slice(i);
|
|
4921
|
+
}
|
|
4922
|
+
if (!toks.length) return null;
|
|
4923
|
+
return { bin: toks[0], baseArgs: toks.slice(1) };
|
|
4924
|
+
}
|
|
4925
|
+
function regValueOf(out) {
|
|
4926
|
+
const m = String(out || "").match(/REG_(?:EXPAND_SZ|SZ)\s+(.*)/);
|
|
4927
|
+
if (!m) return null;
|
|
4928
|
+
return m[1].trim() || null;
|
|
4929
|
+
}
|
|
4930
|
+
function expandEnvVars(value, env) {
|
|
4931
|
+
const e = env || process.env;
|
|
4932
|
+
return String(value).replace(/%([^%]+)%/g, (all, name) => e[name] === void 0 ? all : e[name]);
|
|
4933
|
+
}
|
|
4934
|
+
function exeFromCmdLine(cmdLine) {
|
|
4935
|
+
const s = String(cmdLine || "");
|
|
4936
|
+
let m = s.match(/^\s*"([^"]+\.exe)"/i);
|
|
4937
|
+
if (m) return m[1];
|
|
4938
|
+
m = s.match(/^\s*(.*?\.exe)/i);
|
|
4939
|
+
return m ? m[1] : null;
|
|
4940
|
+
}
|
|
4941
|
+
function safeRegKeyPart(s) {
|
|
4942
|
+
return typeof s === "string" && s.length > 0 && s.length <= 200 && /^[\x20-\x7e]+$/.test(s) && !/[;|&`$()<>^"'\r\n]/.test(s);
|
|
4943
|
+
}
|
|
4944
|
+
function regValue(runner, note, key, name) {
|
|
4945
|
+
const args = name ? ["query", key, "/v", name] : ["query", key, "/ve"];
|
|
4946
|
+
const out = runner("reg.exe", args);
|
|
4947
|
+
const v = regValueOf(out);
|
|
4948
|
+
note(name ? key + " /v " + name : key, v ? "ok" : "empty");
|
|
4949
|
+
return v;
|
|
4950
|
+
}
|
|
4951
|
+
var REG_HIVE_ALIAS = { HKLM: "HKEY_LOCAL_MACHINE", HKCU: "HKEY_CURRENT_USER", HKCR: "HKEY_CLASSES_ROOT", HKU: "HKEY_USERS", HKCC: "HKEY_CURRENT_CONFIG" };
|
|
4952
|
+
function regKeyFull(key) {
|
|
4953
|
+
const s = String(key || "");
|
|
4954
|
+
const i = s.indexOf("\\");
|
|
4955
|
+
const root = i < 0 ? s : s.slice(0, i);
|
|
4956
|
+
return (REG_HIVE_ALIAS[root.toUpperCase()] || root) + (i < 0 ? "" : s.slice(i));
|
|
4957
|
+
}
|
|
4958
|
+
function regSubkeys(runner, note, key) {
|
|
4959
|
+
const out = runner("reg.exe", ["query", key]);
|
|
4960
|
+
if (!out) {
|
|
4961
|
+
note(key, "unreadable");
|
|
4962
|
+
return [];
|
|
4963
|
+
}
|
|
4964
|
+
const prefix = regKeyFull(key) + "\\";
|
|
4965
|
+
const names = [];
|
|
4966
|
+
for (const line of String(out).split(/\r?\n/)) {
|
|
4967
|
+
const l = line.trim();
|
|
4968
|
+
if (!/^HKEY_/i.test(l) || l.length <= prefix.length) continue;
|
|
4969
|
+
if (l.slice(0, prefix.length).toUpperCase() !== prefix.toUpperCase()) continue;
|
|
4970
|
+
const rest = l.slice(prefix.length);
|
|
4971
|
+
if (rest && !rest.includes("\\") && safeRegKeyPart(rest)) names.push(rest);
|
|
4972
|
+
}
|
|
4973
|
+
note(key, names.length ? names.length + " \u9879" : "\u65E0\u5B50\u952E");
|
|
4974
|
+
return names;
|
|
4975
|
+
}
|
|
4976
|
+
var WIN_APP_PATHS = ["msedge.exe", "chrome.exe", "firefox.exe", "brave.exe", "opera.exe", "vivaldi.exe", "chromium.exe", "thorium.exe", "librewolf.exe"];
|
|
4977
|
+
function winExeOfProgId(runner, note, progId, env) {
|
|
4978
|
+
if (!safeRegKeyPart(progId)) return null;
|
|
4979
|
+
for (const root of ["HKCU\\Software\\Classes", "HKLM\\Software\\Classes"]) {
|
|
4980
|
+
const cmd2 = regValue(runner, note, root + "\\" + progId + "\\shell\\open\\command");
|
|
4981
|
+
const exe = cmd2 ? exeFromCmdLine(expandEnvVars(cmd2, env)) : null;
|
|
4982
|
+
if (exe) return exe;
|
|
4983
|
+
}
|
|
4984
|
+
return null;
|
|
4985
|
+
}
|
|
4986
|
+
function probeWin(d) {
|
|
4987
|
+
const { runOut, env, canExec } = d;
|
|
4988
|
+
const notes = [];
|
|
4989
|
+
const note = (source, detail) => {
|
|
4990
|
+
notes.push({ source, detail });
|
|
4991
|
+
};
|
|
4992
|
+
const found = /* @__PURE__ */ new Map();
|
|
4993
|
+
const keyOf = (exe) => String(exe || "").toLowerCase().replace(/[\\/]/g, "\\");
|
|
4994
|
+
const push = (exe, how) => {
|
|
4995
|
+
const full = expandEnvVars(exe, env).trim();
|
|
4996
|
+
if (!/\.exe$/i.test(full)) {
|
|
4997
|
+
note(how, "\u6765\u6E90\u7ED9\u51FA\u7684\u4E0D\u662F exe \u8DEF\u5F84: " + full);
|
|
4998
|
+
return null;
|
|
4999
|
+
}
|
|
5000
|
+
const k = keyOf(full);
|
|
5001
|
+
const hit = found.get(k);
|
|
5002
|
+
if (hit) {
|
|
5003
|
+
if (!hit.sources.includes(how)) hit.sources.push(how);
|
|
5004
|
+
return hit;
|
|
5005
|
+
}
|
|
5006
|
+
if (!canExec(full)) {
|
|
5007
|
+
note(how, "\u6307\u5411\u7684\u6587\u4EF6\u4E0D\u53EF\u6267\u884C: " + full);
|
|
5008
|
+
return null;
|
|
5009
|
+
}
|
|
5010
|
+
const item = { id: k, name: path2.basename(full).replace(/\.exe$/i, ""), engine: engineOf(full), bin: full, source: how, sources: [how] };
|
|
5011
|
+
found.set(k, item);
|
|
5012
|
+
note(how, item.name);
|
|
5013
|
+
return item;
|
|
5014
|
+
};
|
|
5015
|
+
const progIds = /* @__PURE__ */ new Map();
|
|
5016
|
+
const addProgId = (pid, how) => {
|
|
5017
|
+
const s = String(pid || "").trim();
|
|
5018
|
+
if (!safeRegKeyPart(s)) return;
|
|
5019
|
+
if (progIds.get(s) === "userchoice") return;
|
|
5020
|
+
progIds.set(s, how);
|
|
5021
|
+
};
|
|
5022
|
+
let defaultId = null;
|
|
5023
|
+
let defaultSource = null;
|
|
5024
|
+
const DEF_RANK = { userchoice: 1, "scheme-association": 2, "only-installed": 9 };
|
|
5025
|
+
let defRank = 99;
|
|
5026
|
+
const setDefault = (item, how) => {
|
|
5027
|
+
const r = DEF_RANK[how] === void 0 ? 99 : DEF_RANK[how];
|
|
5028
|
+
if (item && r < defRank) {
|
|
5029
|
+
defRank = r;
|
|
5030
|
+
defaultId = item.id;
|
|
5031
|
+
defaultSource = how;
|
|
5032
|
+
}
|
|
5033
|
+
};
|
|
5034
|
+
const cmdToExe = (raw) => raw ? exeFromCmdLine(expandEnvVars(raw, env)) : null;
|
|
5035
|
+
const uc = regValue(runOut, note, "HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\https\\UserChoice", "ProgId");
|
|
5036
|
+
if (uc) addProgId(uc, "userchoice");
|
|
5037
|
+
for (const root of ["HKCU\\Software\\Classes", "HKLM\\Software\\Classes"]) {
|
|
5038
|
+
const pid = regValue(runOut, note, root + "\\https");
|
|
5039
|
+
if (pid) addProgId(pid, "scheme-association");
|
|
5040
|
+
const exe = cmdToExe(regValue(runOut, note, root + "\\https\\shell\\open\\command"));
|
|
5041
|
+
if (exe) setDefault(push(exe, "scheme-association"), "scheme-association");
|
|
5042
|
+
}
|
|
5043
|
+
for (const name of regSubkeys(runOut, note, "HKLM\\SOFTWARE\\Clients\\StartMenuInternet")) {
|
|
5044
|
+
addProgId(name, "startmenu-catalog");
|
|
5045
|
+
const exe = cmdToExe(regValue(runOut, note, "HKLM\\SOFTWARE\\Clients\\StartMenuInternet\\" + name + "\\shell\\open\\command")) || winExeOfProgId(runOut, note, name, env);
|
|
5046
|
+
if (exe) push(exe, "startmenu-catalog");
|
|
5047
|
+
}
|
|
5048
|
+
for (const root of ["HKLM\\SOFTWARE", "HKCU\\SOFTWARE"]) {
|
|
5049
|
+
for (const capPath of regValueTargets(runOut, note, root + "\\RegisteredApplications")) {
|
|
5050
|
+
const https = regValue(runOut, note, capPath + "\\UrlAssociations\\https");
|
|
5051
|
+
const sid = regValue(runOut, note, capPath, "StartMenuInternet");
|
|
5052
|
+
const pid = https || sid;
|
|
5053
|
+
if (pid) addProgId(pid, "registered-apps");
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
for (const exe of WIN_APP_PATHS) {
|
|
5057
|
+
for (const root of ["HKCU", "HKLM"]) {
|
|
5058
|
+
const v = regValue(runOut, note, root + "\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + exe);
|
|
5059
|
+
if (v && push(v, "app-paths")) break;
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
for (const [pid, how] of progIds) {
|
|
5063
|
+
const exe = winExeOfProgId(runOut, note, pid, env);
|
|
5064
|
+
if (!exe) continue;
|
|
5065
|
+
const item = push(exe, how);
|
|
5066
|
+
if (how === "userchoice") setDefault(item, "userchoice");
|
|
5067
|
+
}
|
|
5068
|
+
if (found.size === 1) setDefault([...found.values()][0], "only-installed");
|
|
5069
|
+
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5070
|
+
}
|
|
5071
|
+
function regValueTargets(runOut, note, key) {
|
|
5072
|
+
const out = runOut("reg.exe", ["query", key]);
|
|
5073
|
+
if (!out) {
|
|
5074
|
+
note(key, "unreadable");
|
|
5075
|
+
return [];
|
|
5076
|
+
}
|
|
5077
|
+
const paths = [];
|
|
5078
|
+
for (const line of String(out).split(/\r?\n/)) {
|
|
5079
|
+
const m = line.trim().match(/REG_SZ\s+(.*)/);
|
|
5080
|
+
if (!m) continue;
|
|
5081
|
+
const rel = m[1].trim();
|
|
5082
|
+
if (!safeRegKeyPart(rel)) continue;
|
|
5083
|
+
const root = key.slice(0, key.indexOf("\\"));
|
|
5084
|
+
paths.push(root + "\\" + rel);
|
|
5085
|
+
}
|
|
5086
|
+
note(key, paths.length ? paths.length + " \u4E2A\u80FD\u529B\u8DEF\u5F84" : "\u65E0\u503C");
|
|
5087
|
+
return paths;
|
|
5088
|
+
}
|
|
5089
|
+
var MAC_JXA_LIST = [
|
|
5090
|
+
"ObjC.import('Foundation');",
|
|
5091
|
+
"var ws=$.NSWorkspace.sharedWorkspace;",
|
|
5092
|
+
"var u=$.NSURL.URLWithString('https://dsh.local/probe');",
|
|
5093
|
+
"var out=[];var def='';",
|
|
5094
|
+
"try{var d=ws.URLForApplicationToOpenURL(u); if(!d.isNil()) def=ObjC.unwrap(d.path)||'';}catch(e){}",
|
|
5095
|
+
"var list=null;",
|
|
5096
|
+
"try{list=ws.urlsForApplicationsToOpenURL(u);}catch(e){}",
|
|
5097
|
+
"if(list===null||typeof list.count!=='number'){if(def){out.push(def+'\\t\\t1');}}else{",
|
|
5098
|
+
"var n=Number(list.count);",
|
|
5099
|
+
"for(var i=0;i<n;i++){",
|
|
5100
|
+
"var p=ObjC.unwrap(list.objectAtIndex(i).path)||''; if(!p) continue;",
|
|
5101
|
+
"var exe='';var bid='';",
|
|
5102
|
+
"var b=$.NSBundle.bundleWithPath(p);",
|
|
5103
|
+
"if(!b.isNil()){exe=ObjC.unwrap(b.executablePath)||'';bid=ObjC.unwrap(b.bundleIdentifier)||'';}",
|
|
5104
|
+
"out.push((exe||p)+'\\t'+bid+'\\t'+(p&&def&&p===def?1:0));}",
|
|
5105
|
+
"}",
|
|
5106
|
+
// 末句必须是裸表达式:osascript 取的是最后一条**语句**的值,if/else 语句不产结果,
|
|
5107
|
+
// 写在分支里会让整段查询输出空字符串(表现为「系统未报任何可用应用」)。
|
|
5108
|
+
"out.join('\\n');"
|
|
5109
|
+
].join("");
|
|
5110
|
+
function probeMac(d) {
|
|
5111
|
+
const { runOut, canExec } = d;
|
|
5112
|
+
const notes = [];
|
|
5113
|
+
const note = (source, detail) => {
|
|
5114
|
+
notes.push({ source, detail });
|
|
5115
|
+
};
|
|
5116
|
+
const out = runOut("osascript", ["-l", "JavaScript", "-e", MAC_JXA_LIST]);
|
|
5117
|
+
if (!out || !out.trim()) {
|
|
5118
|
+
note("launchservices", "\u67E5\u8BE2\u65E0\u8F93\u51FA\uFF08\u65E7\u7CFB\u7EDF\u6216\u88AB\u6743\u9650\u62E6\u622A\uFF09");
|
|
5119
|
+
return { browsers: [], defaultId: null, defaultSource: null, probed: notes };
|
|
5120
|
+
}
|
|
5121
|
+
const keyOf = (exe) => String(exe || "").toLowerCase();
|
|
5122
|
+
const found = /* @__PURE__ */ new Map();
|
|
5123
|
+
let defaultId = null;
|
|
5124
|
+
let defaultSource = null;
|
|
5125
|
+
for (const line of out.trim().split("\n")) {
|
|
5126
|
+
const parts = line.split(" ");
|
|
5127
|
+
const bin = (parts[0] || "").trim();
|
|
5128
|
+
if (!bin) continue;
|
|
5129
|
+
if (!canExec(bin)) {
|
|
5130
|
+
note("launchservices", "\u4E0D\u53EF\u6267\u884C: " + bin);
|
|
5131
|
+
continue;
|
|
5132
|
+
}
|
|
5133
|
+
const k = keyOf(bin);
|
|
5134
|
+
if (!found.has(k)) found.set(k, { id: k, name: path2.basename(bin), engine: engineOf(bin), bin, source: "launchservices", sources: ["launchservices"], isDefault: false });
|
|
5135
|
+
if (parts[2] === "1") {
|
|
5136
|
+
found.get(k).isDefault = true;
|
|
5137
|
+
if (!defaultId) {
|
|
5138
|
+
defaultId = k;
|
|
5139
|
+
defaultSource = "launchservices";
|
|
5140
|
+
}
|
|
5141
|
+
}
|
|
5142
|
+
}
|
|
5143
|
+
note("launchservices", found.size ? found.size + " \u4E2A\u53EF\u6253\u5F00 https \u7684\u5E94\u7528" : "\u7CFB\u7EDF\u672A\u62A5\u4EFB\u4F55\u53EF\u7528\u5E94\u7528");
|
|
5144
|
+
if (!defaultId && found.size === 1) {
|
|
5145
|
+
defaultId = [...found.keys()][0];
|
|
5146
|
+
defaultSource = "only-installed";
|
|
5147
|
+
}
|
|
5148
|
+
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5149
|
+
}
|
|
5150
|
+
var PJ = path2.posix.join;
|
|
5151
|
+
function desktopDirs(env, home) {
|
|
5152
|
+
const dataHome = env.XDG_DATA_HOME || PJ(home, ".local", "share");
|
|
5153
|
+
const dataDirs = String(env.XDG_DATA_DIRS || "/usr/local/share:/usr/share").split(":").filter(Boolean);
|
|
5154
|
+
const dirs = [[dataHome, "xdg"], ...dataDirs.map((p) => [p, "xdg"])];
|
|
5155
|
+
dirs.push([PJ(home, ".local", "share"), "xdg"]);
|
|
5156
|
+
dirs.push(["/var/lib/flatpak/exports/share", "flatpak"]);
|
|
5157
|
+
dirs.push([PJ(home, ".local", "share", "flatpak", "exports", "share"), "flatpak"]);
|
|
5158
|
+
dirs.push(["/var/lib/snapd/desktop", "snap"]);
|
|
5159
|
+
const seen = [];
|
|
5160
|
+
return dirs.map(([root, kind]) => ({ dir: PJ(root, "applications"), kind })).filter((x) => {
|
|
5161
|
+
if (seen.includes(x.dir)) return false;
|
|
5162
|
+
seen.push(x.dir);
|
|
5163
|
+
return true;
|
|
5164
|
+
});
|
|
5165
|
+
}
|
|
5166
|
+
function browserFromDesktop(text, kind, file) {
|
|
5167
|
+
let inMain = false;
|
|
5168
|
+
const got = {};
|
|
5169
|
+
for (const line of String(text).split(/\r?\n/)) {
|
|
5170
|
+
if (/^\[Desktop Entry\]\s*$/.test(line)) {
|
|
5171
|
+
inMain = true;
|
|
5172
|
+
continue;
|
|
5173
|
+
}
|
|
5174
|
+
if (/^\[/.test(line)) break;
|
|
5175
|
+
if (!inMain) continue;
|
|
5176
|
+
const m = line.match(/^(Exec|Name|TryExec|Categories)=(.*)$/);
|
|
5177
|
+
if (!m) continue;
|
|
5178
|
+
if (m[1] === "Name" && got.Name) continue;
|
|
5179
|
+
got[m[1]] = m[2].trim();
|
|
5180
|
+
}
|
|
5181
|
+
if (!got.Exec) return null;
|
|
5182
|
+
const categories = String(got.Categories || "");
|
|
5183
|
+
const parsed = parseExecLine(got.Exec);
|
|
5184
|
+
if (!parsed) return null;
|
|
5185
|
+
const engine = engineOf(parsed.bin);
|
|
5186
|
+
const claimsBrowser = /(^|;)WebBrowser(;|$)/.test(categories);
|
|
5187
|
+
if (!claimsBrowser && engine === "other") return null;
|
|
5188
|
+
if (engine === "other") return null;
|
|
5189
|
+
return {
|
|
5190
|
+
// id 恒为归一后的可执行文件路径:defaultId 靠它在清单里定位条目,三平台同一契约
|
|
5191
|
+
id: parsed.bin.toLowerCase(),
|
|
5192
|
+
name: got.Name || path2.basename(file, ".desktop"),
|
|
5193
|
+
engine,
|
|
5194
|
+
bin: parsed.bin,
|
|
5195
|
+
baseArgs: parsed.baseArgs,
|
|
5196
|
+
source: kind,
|
|
5197
|
+
desktopFile: file
|
|
5198
|
+
};
|
|
5199
|
+
}
|
|
5200
|
+
function resolveLinuxBin(bin, canExec, env) {
|
|
5201
|
+
const b = String(bin || "").trim();
|
|
5202
|
+
if (!b) return null;
|
|
5203
|
+
if (b.startsWith("/")) return canExec(b) ? b : null;
|
|
5204
|
+
if (b.includes("/")) return null;
|
|
5205
|
+
for (const dir of String(env.PATH || "").split(":")) {
|
|
5206
|
+
if (!dir) continue;
|
|
5207
|
+
const p = PJ(dir.replace(/\/+$/, ""), b);
|
|
5208
|
+
if (canExec(p)) return p;
|
|
5209
|
+
}
|
|
5210
|
+
return null;
|
|
5211
|
+
}
|
|
5212
|
+
function probeLinux(d) {
|
|
5213
|
+
const { runOut, readFile, exists, listDir, canExec, env, home } = d;
|
|
5214
|
+
const notes = [];
|
|
5215
|
+
const note = (source, detail) => {
|
|
5216
|
+
notes.push({ source, detail });
|
|
5217
|
+
};
|
|
5218
|
+
const found = /* @__PURE__ */ new Map();
|
|
5219
|
+
const usable = (item) => {
|
|
5220
|
+
const resolved = resolveLinuxBin(item.bin, canExec, env);
|
|
5221
|
+
if (!resolved) {
|
|
5222
|
+
note(item.source, "\u4E0D\u53EF\u6267\u884C: " + item.bin);
|
|
5223
|
+
return null;
|
|
5224
|
+
}
|
|
5225
|
+
const k = resolved.toLowerCase();
|
|
5226
|
+
const hit = found.get(k);
|
|
5227
|
+
if (hit) {
|
|
5228
|
+
if (!hit.sources.includes(item.source)) hit.sources.push(item.source);
|
|
5229
|
+
return hit;
|
|
5230
|
+
}
|
|
5231
|
+
const v = Object.assign({}, item, { id: k, bin: resolved, sources: [item.source] });
|
|
5232
|
+
found.set(k, v);
|
|
5233
|
+
return v;
|
|
5234
|
+
};
|
|
5235
|
+
for (const { dir, kind } of desktopDirs(env, home)) {
|
|
5236
|
+
let names = [];
|
|
5237
|
+
try {
|
|
5238
|
+
names = listDir(dir).filter((f) => f.endsWith(".desktop"));
|
|
5239
|
+
} catch {
|
|
5240
|
+
continue;
|
|
5241
|
+
}
|
|
5242
|
+
for (const f of names) {
|
|
5243
|
+
let text = null;
|
|
5244
|
+
try {
|
|
5245
|
+
text = readFile(PJ(dir, f));
|
|
5246
|
+
} catch {
|
|
5247
|
+
continue;
|
|
5248
|
+
}
|
|
5249
|
+
const item = browserFromDesktop(text, kind, f);
|
|
5250
|
+
if (item) usable(item);
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
let defaultId = null;
|
|
5254
|
+
let defaultSource = null;
|
|
5255
|
+
const fromMime = linuxDefaultFromMimeApps(readFile, exists, env, home, note);
|
|
5256
|
+
if (fromMime) {
|
|
5257
|
+
const item = usable(fromMime);
|
|
5258
|
+
if (item) {
|
|
5259
|
+
defaultId = item.id;
|
|
5260
|
+
defaultSource = "mimeapps";
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5263
|
+
const id = runOut("xdg-settings", ["get", "default-web-browser"]);
|
|
5264
|
+
const desktopId = id && String(id).trim();
|
|
5265
|
+
if (!defaultId && desktopId && /^[A-Za-z0-9._-]+\.desktop$/.test(desktopId)) {
|
|
5266
|
+
for (const { dir } of desktopDirs(env, home)) {
|
|
5267
|
+
const p = PJ(dir, desktopId);
|
|
5268
|
+
let text = null;
|
|
5269
|
+
try {
|
|
5270
|
+
if (exists(p)) text = readFile(p);
|
|
5271
|
+
} catch {
|
|
5272
|
+
continue;
|
|
5273
|
+
}
|
|
5274
|
+
if (text === null) continue;
|
|
5275
|
+
const item = browserFromDesktop(text, "xdg-settings", desktopId);
|
|
5276
|
+
const used = item && usable(item);
|
|
5277
|
+
if (used) {
|
|
5278
|
+
defaultId = used.id;
|
|
5279
|
+
defaultSource = "xdg-settings";
|
|
5280
|
+
break;
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
}
|
|
5284
|
+
if (!desktopId) note("xdg-settings", "\u65E0\u8F93\u51FA");
|
|
5285
|
+
else if (defaultSource === "xdg-settings") note("xdg-settings", "\u9ED8\u8BA4=" + defaultId);
|
|
5286
|
+
else note("xdg-settings", "\u62A5\u51FA " + desktopId + (defaultId ? "\uFF08\u9ED8\u8BA4\u5DF2\u7531 " + defaultSource + " \u5B9A\u51FA\uFF09" : " \u4F46\u4E0D\u53EF\u7528"));
|
|
5287
|
+
if (!defaultId && found.size === 1) {
|
|
5288
|
+
defaultId = [...found.keys()][0];
|
|
5289
|
+
defaultSource = "only-installed";
|
|
5290
|
+
}
|
|
5291
|
+
return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
|
|
5292
|
+
}
|
|
5293
|
+
function linuxDefaultFromMimeApps(readFile, exists, env, home, note) {
|
|
5294
|
+
const cfgHome = env.XDG_CONFIG_HOME || PJ(home, ".config");
|
|
5295
|
+
const cfgDirs = String(env.XDG_CONFIG_DIRS || "/etc/xdg").split(":").filter(Boolean);
|
|
5296
|
+
const dataDirs = String(env.XDG_DATA_DIRS || "/usr/local/share:/usr/share").split(":").filter(Boolean);
|
|
5297
|
+
const files = [
|
|
5298
|
+
PJ(cfgHome, "mimeapps.list"),
|
|
5299
|
+
...cfgDirs.map((d) => PJ(d, "mimeapps.list")),
|
|
5300
|
+
...dataDirs.map((d) => PJ(d, "applications", "mimeapps.list"))
|
|
5301
|
+
];
|
|
5302
|
+
for (const f of files) {
|
|
5303
|
+
if (!exists(f)) continue;
|
|
5304
|
+
let text = null;
|
|
5305
|
+
try {
|
|
5306
|
+
text = readFile(f);
|
|
5307
|
+
} catch {
|
|
5308
|
+
continue;
|
|
5309
|
+
}
|
|
5310
|
+
const id = mimeAppsDefault(text);
|
|
5311
|
+
if (!id) continue;
|
|
5312
|
+
note("mimeapps", path2.basename(f) + " -> " + id);
|
|
5313
|
+
for (const { dir, kind } of desktopDirs(env, home)) {
|
|
5314
|
+
const p = PJ(dir, id);
|
|
5315
|
+
if (!exists(p)) continue;
|
|
5316
|
+
let dt = null;
|
|
5317
|
+
try {
|
|
5318
|
+
dt = readFile(p);
|
|
5319
|
+
} catch {
|
|
5320
|
+
continue;
|
|
5321
|
+
}
|
|
5322
|
+
const item = browserFromDesktop(dt, kind, id);
|
|
5323
|
+
if (item) return item;
|
|
5324
|
+
}
|
|
5325
|
+
return null;
|
|
5326
|
+
}
|
|
5327
|
+
note("mimeapps", "\u65E0\u9ED8\u8BA4\u9879");
|
|
5328
|
+
return null;
|
|
5329
|
+
}
|
|
5330
|
+
function mimeAppsDefault(text) {
|
|
5331
|
+
let inDefault = false;
|
|
5332
|
+
for (const line of String(text || "").split(/\r?\n/)) {
|
|
5333
|
+
if (/^\s*\[/.test(line)) {
|
|
5334
|
+
inDefault = /^\s*\[Default Applications\]\s*$/.test(line);
|
|
5335
|
+
continue;
|
|
5336
|
+
}
|
|
5337
|
+
if (!inDefault) continue;
|
|
5338
|
+
const m = line.match(/^\s*x-scheme-handler\/https?\s*=\s*(.*)$/i);
|
|
5339
|
+
if (!m) continue;
|
|
5340
|
+
const ids = m[1].split(";").map((s) => s.trim()).filter((s) => /^[A-Za-z0-9._-]+\.desktop$/.test(s));
|
|
5341
|
+
if (ids.length) return ids[0];
|
|
5342
|
+
}
|
|
5343
|
+
return null;
|
|
5344
|
+
}
|
|
5345
|
+
function probe(platform, d) {
|
|
5346
|
+
const pl = platform || process.platform;
|
|
5347
|
+
const dd = Object.assign({}, d, { canExec: d.canExec || ((p) => isExecutableFile(p, pl)) });
|
|
5348
|
+
if (pl === "win32") return probeWin(dd);
|
|
5349
|
+
if (pl === "darwin") return probeMac(dd);
|
|
5350
|
+
return probeLinux(dd);
|
|
5351
|
+
}
|
|
5352
|
+
var CACHE = /* @__PURE__ */ Object.create(null);
|
|
5353
|
+
function inventory(platform, o) {
|
|
5354
|
+
const ov = o || {};
|
|
5355
|
+
const pl = platform || process.platform;
|
|
5356
|
+
const now = ov.now || (() => Date.now());
|
|
5357
|
+
const ttl = ov.ttlMs === void 0 ? 6e4 : ov.ttlMs;
|
|
5358
|
+
const cached = CACHE[pl];
|
|
5359
|
+
if (!ov.force && cached && now() - cached.at < ttl) return Object.assign({ cached: true }, cached.value);
|
|
5360
|
+
const runOut = ov.runOut || ((bin, args) => exec.runOut(bin, args, { timeoutMs: PROBE_TIMEOUT_MS }));
|
|
5361
|
+
const readFile = ov.readFile || ((p) => fs2.readFileSync(p, "utf8"));
|
|
5362
|
+
const exists = ov.exists || ((p) => fs2.existsSync(p));
|
|
5363
|
+
const listDir = ov.listDir || ((p) => fs2.readdirSync(p));
|
|
5364
|
+
let value;
|
|
5365
|
+
try {
|
|
5366
|
+
value = probe(pl, { runOut, readFile, exists, listDir, canExec: ov.canExec, env: ov.env || process.env, home: ov.home || os2.homedir() });
|
|
5367
|
+
} catch (e) {
|
|
5368
|
+
value = { browsers: [], defaultId: null, defaultSource: null, probed: [{ source: "probe-error", detail: String(e && e.message || e) }] };
|
|
5369
|
+
}
|
|
5370
|
+
value.at = now();
|
|
5371
|
+
value.platform = pl;
|
|
5372
|
+
value.browsers.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
5373
|
+
CACHE[pl] = { at: now(), value };
|
|
5374
|
+
return Object.assign({ cached: false }, value);
|
|
5375
|
+
}
|
|
5376
|
+
function invalidate(platform) {
|
|
5377
|
+
if (platform) delete CACHE[platform];
|
|
5378
|
+
else for (const k of Object.keys(CACHE)) delete CACHE[k];
|
|
5379
|
+
}
|
|
5380
|
+
module2.exports = {
|
|
5381
|
+
inventory,
|
|
5382
|
+
invalidate,
|
|
5383
|
+
probe,
|
|
5384
|
+
probeWin,
|
|
5385
|
+
probeMac,
|
|
5386
|
+
probeLinux,
|
|
5387
|
+
engineOf,
|
|
5388
|
+
tokenizeExec,
|
|
5389
|
+
parseExecLine,
|
|
5390
|
+
regValueOf,
|
|
5391
|
+
expandEnvVars,
|
|
5392
|
+
exeFromCmdLine,
|
|
5393
|
+
regSubkeys,
|
|
5394
|
+
regKeyFull,
|
|
5395
|
+
regValueTargets,
|
|
5396
|
+
safeRegKeyPart,
|
|
5397
|
+
browserFromDesktop,
|
|
5398
|
+
desktopDirs,
|
|
5399
|
+
resolveLinuxBin,
|
|
5400
|
+
mimeAppsDefault,
|
|
5401
|
+
linuxDefaultFromMimeApps,
|
|
5402
|
+
WIN_APP_PATHS,
|
|
5403
|
+
PROBE_TIMEOUT_MS
|
|
5404
|
+
};
|
|
5405
|
+
}
|
|
5406
|
+
});
|
|
5407
|
+
|
|
5408
|
+
// src/platform/os/environment.js
|
|
5409
|
+
var require_environment = __commonJS({
|
|
5410
|
+
"src/platform/os/environment.js"(exports2, module2) {
|
|
5411
|
+
"use strict";
|
|
5412
|
+
var fs2 = require("node:fs");
|
|
5413
|
+
var os2 = require("node:os");
|
|
5414
|
+
var path2 = require("node:path");
|
|
5415
|
+
var stateRoot2 = require_state_root();
|
|
5416
|
+
var { writeAtomic } = require_fs();
|
|
5417
|
+
var desktop = require_desktop();
|
|
5418
|
+
var detector = require_browser_inventory();
|
|
5419
|
+
var { engineOf } = detector;
|
|
5420
|
+
var SCHEMA = 1;
|
|
5421
|
+
var FILE_NAME = "environment.json";
|
|
5422
|
+
var FORM_TTL_MS = 6e4;
|
|
5423
|
+
var _sources = {};
|
|
5424
|
+
function bind(sources) {
|
|
5425
|
+
_sources = Object.assign({}, _sources, sources || {});
|
|
5426
|
+
return _sources;
|
|
5427
|
+
}
|
|
5428
|
+
function preferenceId() {
|
|
5429
|
+
const f = _sources.preference;
|
|
5430
|
+
if (typeof f !== "function") return null;
|
|
5431
|
+
const v = f();
|
|
5432
|
+
return typeof v === "string" && v.trim() ? v.trim() : null;
|
|
5433
|
+
}
|
|
5434
|
+
function capabilities() {
|
|
5435
|
+
const f = _sources.capabilities;
|
|
5436
|
+
if (typeof f !== "function") return null;
|
|
5437
|
+
return f() || null;
|
|
5438
|
+
}
|
|
5439
|
+
function identity() {
|
|
5440
|
+
let user = null;
|
|
5441
|
+
try {
|
|
5442
|
+
user = os2.userInfo().username;
|
|
5443
|
+
} catch {
|
|
5444
|
+
user = process.env.USER || process.env.USERNAME || null;
|
|
5445
|
+
}
|
|
5446
|
+
return {
|
|
5447
|
+
platform: process.platform,
|
|
5448
|
+
arch: process.arch,
|
|
5449
|
+
hostname: os2.hostname(),
|
|
5450
|
+
user: user || null,
|
|
5451
|
+
home: os2.homedir(),
|
|
5452
|
+
node: process.version
|
|
5453
|
+
};
|
|
5454
|
+
}
|
|
5455
|
+
function paths() {
|
|
5456
|
+
return { root: stateRoot2.root(), supervisor: stateRoot2.supervisorDir(), shell: stateRoot2.shellDir() };
|
|
5457
|
+
}
|
|
5458
|
+
function normalizeInventory(inv, platform) {
|
|
5459
|
+
const list = inv && Array.isArray(inv.browsers) ? inv.browsers : [];
|
|
5460
|
+
const defaultId = inv && inv.defaultId ? inv.defaultId : null;
|
|
5461
|
+
return {
|
|
5462
|
+
platform: inv && inv.platform || platform || process.platform,
|
|
5463
|
+
cached: !!(inv && inv.cached),
|
|
5464
|
+
at: inv && inv.at !== void 0 ? inv.at : null,
|
|
5465
|
+
defaultId,
|
|
5466
|
+
defaultSource: inv && inv.defaultSource || null,
|
|
5467
|
+
browsers: list.map((b) => ({
|
|
5468
|
+
id: b.id,
|
|
5469
|
+
name: b.name,
|
|
5470
|
+
bin: b.bin,
|
|
5471
|
+
engine: b.engine || engineOf(b.bin),
|
|
5472
|
+
baseArgs: b.baseArgs || [],
|
|
5473
|
+
sources: b.sources && b.sources.length ? b.sources : [b.source || "unknown"],
|
|
5474
|
+
isDefault: !!defaultId && b.id === defaultId
|
|
5475
|
+
})),
|
|
5476
|
+
probed: inv && inv.probed || []
|
|
5477
|
+
};
|
|
5478
|
+
}
|
|
5479
|
+
function browsers(o) {
|
|
5480
|
+
const ov = o || {};
|
|
5481
|
+
const pl = ov.platform || process.platform;
|
|
5482
|
+
if (ov.inventory) return normalizeInventory(ov.inventory, pl);
|
|
5483
|
+
const resolve = typeof ov.resolveInventory === "function" ? ov.resolveInventory : ((platform, deps) => detector.inventory(platform, deps));
|
|
5484
|
+
return normalizeInventory(resolve(pl, ov.resolveDeps || {}), pl);
|
|
5485
|
+
}
|
|
5486
|
+
var ENGINE_RANK = { chromium: 0, firefox: 1, other: 2 };
|
|
5487
|
+
function rankCandidates(list) {
|
|
5488
|
+
const rankOf = (b) => {
|
|
5489
|
+
const r = ENGINE_RANK[b && b.engine];
|
|
5490
|
+
return r === void 0 ? ENGINE_RANK.other : r;
|
|
5491
|
+
};
|
|
5492
|
+
return (Array.isArray(list) ? list : []).slice().sort((a, b) => {
|
|
5493
|
+
if (rankOf(a) !== rankOf(b)) return rankOf(a) - rankOf(b);
|
|
5494
|
+
const ia = String(a && a.id || "");
|
|
5495
|
+
const ib = String(b && b.id || "");
|
|
5496
|
+
return ia < ib ? -1 : ia > ib ? 1 : 0;
|
|
5497
|
+
});
|
|
5498
|
+
}
|
|
5499
|
+
function pickLauncher(platform, inv, preference) {
|
|
5500
|
+
const list = inv && Array.isArray(inv.browsers) ? inv.browsers : [];
|
|
5501
|
+
const byId = /* @__PURE__ */ new Map();
|
|
5502
|
+
for (const b of list) byId.set(b.id, b);
|
|
5503
|
+
const wanted = preference === void 0 ? preferenceId() : typeof preference === "string" && preference ? preference : null;
|
|
5504
|
+
const stale = wanted !== null && !byId.has(wanted);
|
|
5505
|
+
const out = (browser, how) => ({ browser, how, wanted, stale });
|
|
5506
|
+
if (wanted !== null && byId.has(wanted)) return out(byId.get(wanted), "user-preference");
|
|
5507
|
+
const sys = inv && inv.defaultId ? byId.get(inv.defaultId) : null;
|
|
5508
|
+
if (sys) return out(sys, inv.defaultSource || "default");
|
|
5509
|
+
if (list.length === 1) return out(list[0], "only-installed");
|
|
5510
|
+
if (list.length > 1) return out(rankCandidates(list)[0], "candidate-rank");
|
|
5511
|
+
return out(null, "none-found");
|
|
5512
|
+
}
|
|
5513
|
+
function snapshotPath() {
|
|
5514
|
+
return path2.join(stateRoot2.supervisorDir(), FILE_NAME);
|
|
5515
|
+
}
|
|
5516
|
+
function readSnapshot() {
|
|
5517
|
+
try {
|
|
5518
|
+
const doc = JSON.parse(fs2.readFileSync(snapshotPath(), "utf8"));
|
|
5519
|
+
return doc && doc.schema === SCHEMA ? doc : null;
|
|
5520
|
+
} catch {
|
|
5521
|
+
return null;
|
|
5522
|
+
}
|
|
5523
|
+
}
|
|
5524
|
+
var _formCache = null;
|
|
5525
|
+
function form(o) {
|
|
5526
|
+
const ov = o || {};
|
|
5527
|
+
const now = typeof ov.now === "function" ? ov.now : (() => Date.now());
|
|
5528
|
+
const stamp = now();
|
|
5529
|
+
const ttl = ov.ttlMs === void 0 ? FORM_TTL_MS : ov.ttlMs;
|
|
5530
|
+
if (!ov.force && _formCache && stamp - _formCache.at < ttl) {
|
|
5531
|
+
return Object.assign({}, _formCache.value, { cached: true });
|
|
5532
|
+
}
|
|
5533
|
+
const inv = browsers(ov);
|
|
5534
|
+
const caps = capabilities();
|
|
5535
|
+
const session = desktop.describe();
|
|
5536
|
+
const prefId = preferenceId();
|
|
5537
|
+
const prefEntry = prefId ? inv.browsers.find((b) => b.id === prefId) || null : null;
|
|
5538
|
+
const preference = {
|
|
5539
|
+
id: prefId,
|
|
5540
|
+
configured: !!prefId,
|
|
5541
|
+
matched: !!prefEntry,
|
|
5542
|
+
browser: prefEntry ? { id: prefEntry.id, name: prefEntry.name, engine: prefEntry.engine } : null,
|
|
5543
|
+
reason: !prefId ? "not-set" : prefEntry ? "matched" : "stale"
|
|
5544
|
+
};
|
|
5545
|
+
const pick = pickLauncher(inv.platform, inv, prefId);
|
|
5546
|
+
const probed = inv.probed.map((p) => ({ section: "browsers", source: p.source, detail: p.detail }));
|
|
5547
|
+
probed.push({ section: "session", source: "desktop", detail: session.reason + (session.available ? "\uFF08\u53EF\u7528\uFF09" : "\uFF08\u4E0D\u53EF\u7528\uFF09") });
|
|
5548
|
+
probed.push({
|
|
5549
|
+
section: "capabilities",
|
|
5550
|
+
source: "profile",
|
|
5551
|
+
detail: caps ? "openBrowser=" + (caps.openBrowser === true) : "\u672A\u7ED1\u5B9A\u80FD\u529B\u77E9\u9635\uFF08\u7531 platform/os/index.js \u88C5\u914D\u671F\u6CE8\u5165\uFF09"
|
|
5552
|
+
});
|
|
5553
|
+
probed.push({
|
|
5554
|
+
section: "preference",
|
|
5555
|
+
source: "config",
|
|
5556
|
+
detail: preference.reason === "not-set" ? "\u672A\u8BBE\u7F6E\uFF0C\u6309\u7CFB\u7EDF\u9ED8\u8BA4\u6216\u5019\u9009\u6B21\u5E8F\u5206\u53D1" : preference.reason === "matched" ? "\u5DF2\u9009 " + preference.browser.name : "\u504F\u597D\u6240\u6307\u5DF2\u4E0D\u5728\u5019\u9009\u6E05\u5355: " + prefId
|
|
5557
|
+
});
|
|
5558
|
+
probed.push({
|
|
5559
|
+
section: "pick",
|
|
5560
|
+
source: "form",
|
|
5561
|
+
detail: pick.how + (pick.browser ? "\uFF08" + pick.browser.name + "\uFF09" : "\uFF08\u65E0\u5019\u9009\uFF09") + (pick.stale ? "\uFF0C\u504F\u597D\u5DF2\u5931\u6548\u9700\u91CD\u9009" : "")
|
|
5562
|
+
});
|
|
5563
|
+
const value = {
|
|
5564
|
+
schema: SCHEMA,
|
|
5565
|
+
at: stamp,
|
|
5566
|
+
platform: inv.platform,
|
|
5567
|
+
identity: identity(),
|
|
5568
|
+
paths: paths(),
|
|
5569
|
+
session,
|
|
5570
|
+
capabilities: caps,
|
|
5571
|
+
preference,
|
|
5572
|
+
default: inv.defaultId ? { id: inv.defaultId, source: inv.defaultSource } : null,
|
|
5573
|
+
browsers: inv.browsers,
|
|
5574
|
+
pick: { how: pick.how, id: pick.browser ? pick.browser.id : null, name: pick.browser ? pick.browser.name : null, wanted: pick.wanted, stale: pick.stale },
|
|
5575
|
+
probed
|
|
5576
|
+
};
|
|
5577
|
+
const snapshot = { path: snapshotPath(), written: false, error: null };
|
|
5578
|
+
if (ov.persist === true) {
|
|
5579
|
+
try {
|
|
5580
|
+
writeAtomic(snapshot.path, JSON.stringify(value, null, 2) + "\n", { mode: 384 });
|
|
5581
|
+
snapshot.written = true;
|
|
5582
|
+
} catch (e) {
|
|
5583
|
+
snapshot.error = String(e && e.message || e);
|
|
5584
|
+
}
|
|
5585
|
+
probed.push({
|
|
5586
|
+
section: "snapshot",
|
|
5587
|
+
source: FILE_NAME,
|
|
5588
|
+
detail: snapshot.written ? "\u5DF2\u843D\u76D8 " + snapshot.path : "\u843D\u76D8\u5931\u8D25: " + snapshot.error
|
|
5589
|
+
});
|
|
5590
|
+
}
|
|
5591
|
+
value.snapshot = snapshot;
|
|
5592
|
+
_formCache = { at: stamp, value };
|
|
5593
|
+
return Object.assign({ cached: false }, value);
|
|
5594
|
+
}
|
|
5595
|
+
function invalidate(platform) {
|
|
5596
|
+
_formCache = null;
|
|
5597
|
+
return detector.invalidate(platform);
|
|
5598
|
+
}
|
|
5599
|
+
function checkPreference(value, form2) {
|
|
5600
|
+
const candidates = (form2 && form2.browsers || []).map((b) => ({
|
|
5601
|
+
id: b.id,
|
|
5602
|
+
name: b.name,
|
|
5603
|
+
engine: b.engine,
|
|
5604
|
+
isDefault: b.isDefault === true
|
|
5605
|
+
}));
|
|
5606
|
+
const id = typeof value === "string" ? value.trim() : "";
|
|
5607
|
+
if (!id) return { ok: true, id: null, browser: null, candidates };
|
|
5608
|
+
const hit = candidates.find((c) => c.id === id);
|
|
5609
|
+
if (!hit) {
|
|
5610
|
+
return { ok: false, id: null, browser: null, candidates, error: "\u8BE5\u6D4F\u89C8\u5668\u4E0D\u5728\u672C\u673A\u5019\u9009\u6E05\u5355\u91CC\uFF08\u53EF\u80FD\u5DF2\u5378\u8F7D\u6216\u8DEF\u5F84\u5931\u6548\uFF09\uFF0C\u8BF7\u5148\u5237\u65B0\u73AF\u5883\u8868\u5355" };
|
|
5611
|
+
}
|
|
5612
|
+
return { ok: true, id: hit.id, browser: hit, candidates };
|
|
5613
|
+
}
|
|
5614
|
+
module2.exports = {
|
|
5615
|
+
SCHEMA,
|
|
5616
|
+
FILE_NAME,
|
|
5617
|
+
FORM_TTL_MS,
|
|
5618
|
+
bind,
|
|
5619
|
+
preferenceId,
|
|
5620
|
+
capabilities,
|
|
5621
|
+
identity,
|
|
5622
|
+
paths,
|
|
5623
|
+
browsers,
|
|
5624
|
+
normalizeInventory,
|
|
5625
|
+
rankCandidates,
|
|
5626
|
+
pickLauncher,
|
|
5627
|
+
checkPreference,
|
|
5628
|
+
form,
|
|
5629
|
+
snapshotPath,
|
|
5630
|
+
readSnapshot,
|
|
5631
|
+
invalidate
|
|
5632
|
+
};
|
|
5633
|
+
}
|
|
5634
|
+
});
|
|
5635
|
+
|
|
4790
5636
|
// src/platform/os/process.js
|
|
4791
5637
|
var require_process = __commonJS({
|
|
4792
5638
|
"src/platform/os/process.js"(exports2, module2) {
|
|
@@ -5456,14 +6302,15 @@ var require_notify = __commonJS({
|
|
|
5456
6302
|
var require_browser = __commonJS({
|
|
5457
6303
|
"src/platform/os/browser.js"(exports2, module2) {
|
|
5458
6304
|
"use strict";
|
|
5459
|
-
var fs2 = require("node:fs");
|
|
5460
6305
|
var path2 = require("node:path");
|
|
5461
|
-
var os2 = require("node:os");
|
|
5462
6306
|
var spawnOS = require_spawn();
|
|
5463
6307
|
var desktop = require_desktop();
|
|
5464
6308
|
var CAPABILITY_PROFILES = require_capability_profile();
|
|
5465
6309
|
var { resolveExecutable, isExecutableFile } = require_exec_path();
|
|
5466
|
-
var
|
|
6310
|
+
var environment = require_environment();
|
|
6311
|
+
var detector = require_browser_inventory();
|
|
6312
|
+
var { engineOf } = detector;
|
|
6313
|
+
var { allocTempDir, removeTreeDeferred } = require_fs();
|
|
5467
6314
|
function isSafeHttpUrl(url) {
|
|
5468
6315
|
try {
|
|
5469
6316
|
const u = new URL(String(url));
|
|
@@ -5475,7 +6322,7 @@ var require_browser = __commonJS({
|
|
|
5475
6322
|
function openCommand(platform, url) {
|
|
5476
6323
|
const pl = platform || process.platform;
|
|
5477
6324
|
if (pl === "darwin") return { cmd: "open", args: [url] };
|
|
5478
|
-
if (pl === "win32") return
|
|
6325
|
+
if (pl === "win32") return null;
|
|
5479
6326
|
return { cmd: "xdg-open", args: [url] };
|
|
5480
6327
|
}
|
|
5481
6328
|
var SUPPORTED_OPEN_PLATFORMS = Object.keys(CAPABILITY_PROFILES).filter((k) => CAPABILITY_PROFILES[k].openBrowser === true);
|
|
@@ -5499,7 +6346,7 @@ var require_browser = __commonJS({
|
|
|
5499
6346
|
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
6347
|
var FAILURE_TEXT = {
|
|
5501
6348
|
"unsafe-url": "\u5730\u5740\u4E0D\u662F http(s) \u7EDD\u5BF9 URL\uFF0C\u5DF2\u62D2\u7EDD\u4EA4\u7ED9\u6D4F\u89C8\u5668",
|
|
5502
|
-
"no-launcher": "\u672A\
|
|
6349
|
+
"no-launcher": "\u672C\u673A\u672A\u63A2\u5230\u53EF\u542F\u52A8\u7684\u6D4F\u89C8\u5668\uFF08\u6216\u6240\u9009\u6D4F\u89C8\u5668\u5DF2\u4E0D\u53EF\u6267\u884C\uFF09\uFF0C\u8BF7\u5728\u9762\u677F\u7684\u73AF\u5883\u8868\u5355\u91CC\u786E\u8BA4\uFF0C\u6216\u624B\u52A8\u6253\u5F00\u8BE5\u5730\u5740",
|
|
5503
6350
|
"spawn-failed": "\u6D4F\u89C8\u5668\u542F\u52A8\u5931\u8D25\uFF08\u7CFB\u7EDF\u62D2\u7EDD\u4E86\u8BE5\u547D\u4EE4\uFF09",
|
|
5504
6351
|
"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",
|
|
5505
6352
|
"killed-by-signal": "\u6D4F\u89C8\u5668\u542F\u52A8\u547D\u4EE4\u88AB\u7CFB\u7EDF\u7EC8\u6B62\uFF0C\u7A97\u53E3\u672A\u51FA\u73B0",
|
|
@@ -5507,19 +6354,128 @@ var require_browser = __commonJS({
|
|
|
5507
6354
|
"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
6355
|
};
|
|
5509
6356
|
function ownsItsWindow(via, platform) {
|
|
6357
|
+
if (via === "isolated") return true;
|
|
5510
6358
|
if (via !== "dispatcher") return false;
|
|
5511
6359
|
return platform !== "win32";
|
|
5512
6360
|
}
|
|
6361
|
+
function formOfBin(pl, b) {
|
|
6362
|
+
const engine = b && b.bin ? engineOf(b.bin) : "other";
|
|
6363
|
+
return { engine, direct: !!b && (engine !== "other" || pl === "win32") };
|
|
6364
|
+
}
|
|
5513
6365
|
function openPlan(platform, url, opts) {
|
|
5514
6366
|
const o = opts || {};
|
|
5515
6367
|
const pl = platform || process.platform;
|
|
5516
|
-
const
|
|
5517
|
-
const
|
|
5518
|
-
|
|
5519
|
-
|
|
6368
|
+
const picked = o.pick || environment.pickLauncher(pl, o.inventory, o.preference);
|
|
6369
|
+
const b = picked.browser;
|
|
6370
|
+
const form = formOfBin(pl, b);
|
|
6371
|
+
if (form.direct) {
|
|
6372
|
+
return {
|
|
6373
|
+
bin: b.bin,
|
|
6374
|
+
args: (b.baseArgs || []).concat([url]),
|
|
6375
|
+
engine: form.engine,
|
|
6376
|
+
via: "browser",
|
|
6377
|
+
isolated: false,
|
|
6378
|
+
watch: false,
|
|
6379
|
+
envKind: "sys",
|
|
6380
|
+
pick: picked.how,
|
|
6381
|
+
stale: picked.stale === true,
|
|
6382
|
+
exitIsEvidence: ownsItsWindow("browser", pl)
|
|
6383
|
+
};
|
|
6384
|
+
}
|
|
6385
|
+
const c = openCommand(pl, url);
|
|
6386
|
+
if (!c) return {
|
|
6387
|
+
bin: null,
|
|
6388
|
+
args: [url],
|
|
6389
|
+
engine: form.engine,
|
|
6390
|
+
via: "none",
|
|
6391
|
+
isolated: false,
|
|
6392
|
+
watch: false,
|
|
6393
|
+
envKind: "sys",
|
|
6394
|
+
pick: picked.how,
|
|
6395
|
+
stale: picked.stale === true,
|
|
6396
|
+
exitIsEvidence: false
|
|
6397
|
+
};
|
|
6398
|
+
return {
|
|
6399
|
+
bin: c.cmd,
|
|
6400
|
+
args: c.args,
|
|
6401
|
+
engine: "other",
|
|
6402
|
+
via: "dispatcher",
|
|
6403
|
+
isolated: false,
|
|
6404
|
+
watch: false,
|
|
6405
|
+
envKind: "sys",
|
|
6406
|
+
pick: picked.how,
|
|
6407
|
+
stale: picked.stale === true,
|
|
6408
|
+
exitIsEvidence: ownsItsWindow("dispatcher", pl)
|
|
6409
|
+
};
|
|
6410
|
+
}
|
|
6411
|
+
function isolatedPlan(platform, url, opts) {
|
|
6412
|
+
const o = opts || {};
|
|
6413
|
+
const pl = platform || process.platform;
|
|
6414
|
+
const picked = o.pick || environment.pickLauncher(pl, o.inventory, o.preference);
|
|
6415
|
+
const b = picked.browser;
|
|
6416
|
+
const form = formOfBin(pl, b);
|
|
6417
|
+
const baseArgs = b && b.baseArgs || [];
|
|
6418
|
+
const common = { pick: picked.how, stale: picked.stale === true, engine: form.engine };
|
|
6419
|
+
const plain = (bin, label) => Object.assign(common, {
|
|
6420
|
+
bin,
|
|
6421
|
+
args: baseArgs.concat([url]),
|
|
6422
|
+
via: "browser",
|
|
6423
|
+
isolated: false,
|
|
6424
|
+
watch: false,
|
|
6425
|
+
envKind: "sys",
|
|
6426
|
+
label,
|
|
6427
|
+
exitIsEvidence: ownsItsWindow("browser", pl)
|
|
6428
|
+
});
|
|
6429
|
+
if (form.direct && form.engine === "chromium" && o.profileDir) {
|
|
6430
|
+
const args = ["--incognito", "--user-data-dir=" + o.profileDir];
|
|
6431
|
+
if (Array.isArray(o.size) && o.size.length === 2) args.push("--window-size=" + o.size[0] + "," + o.size[1]);
|
|
6432
|
+
if (o.lang) args.push("--lang=" + o.lang);
|
|
6433
|
+
args.push("--no-first-run", "--no-default-browser-check", "--disable-session-crashed-bubble");
|
|
6434
|
+
return Object.assign(common, {
|
|
6435
|
+
bin: b.bin,
|
|
6436
|
+
args: [...baseArgs, ...args, url],
|
|
6437
|
+
via: "isolated",
|
|
6438
|
+
isolated: true,
|
|
6439
|
+
watch: true,
|
|
6440
|
+
envKind: "anti",
|
|
6441
|
+
label: "chromium",
|
|
6442
|
+
exitIsEvidence: ownsItsWindow("isolated", pl)
|
|
6443
|
+
});
|
|
5520
6444
|
}
|
|
6445
|
+
if (form.direct && form.engine === "firefox" && o.profileDir) {
|
|
6446
|
+
return Object.assign(common, {
|
|
6447
|
+
bin: b.bin,
|
|
6448
|
+
args: [...baseArgs, "--no-remote", "--profile", o.profileDir, "-private-window", url],
|
|
6449
|
+
via: "isolated",
|
|
6450
|
+
isolated: true,
|
|
6451
|
+
watch: true,
|
|
6452
|
+
envKind: "anti",
|
|
6453
|
+
label: "firefox",
|
|
6454
|
+
exitIsEvidence: ownsItsWindow("isolated", pl)
|
|
6455
|
+
});
|
|
6456
|
+
}
|
|
6457
|
+
if (form.direct) return plain(b.bin, path2.basename(b.bin));
|
|
5521
6458
|
const c = openCommand(pl, url);
|
|
5522
|
-
|
|
6459
|
+
if (!c) return Object.assign(common, {
|
|
6460
|
+
bin: null,
|
|
6461
|
+
args: [url],
|
|
6462
|
+
via: "none",
|
|
6463
|
+
isolated: false,
|
|
6464
|
+
watch: false,
|
|
6465
|
+
envKind: "sys",
|
|
6466
|
+
label: null,
|
|
6467
|
+
exitIsEvidence: false
|
|
6468
|
+
});
|
|
6469
|
+
return Object.assign(common, {
|
|
6470
|
+
bin: c.cmd,
|
|
6471
|
+
args: c.args,
|
|
6472
|
+
via: "dispatcher",
|
|
6473
|
+
isolated: false,
|
|
6474
|
+
watch: false,
|
|
6475
|
+
envKind: "sys",
|
|
6476
|
+
label: c.cmd,
|
|
6477
|
+
exitIsEvidence: ownsItsWindow("dispatcher", pl)
|
|
6478
|
+
});
|
|
5523
6479
|
}
|
|
5524
6480
|
function observeSpawn(child, windowMs, setTimeoutFn) {
|
|
5525
6481
|
return new Promise((resolve) => {
|
|
@@ -5531,63 +6487,40 @@ var require_browser = __commonJS({
|
|
|
5531
6487
|
clearTimeout(timer);
|
|
5532
6488
|
resolve(r);
|
|
5533
6489
|
};
|
|
5534
|
-
timer = (setTimeoutFn || setTimeout)(() => done({ stage: "alive" }), windowMs);
|
|
5535
|
-
if (timer && timer.unref) timer.unref();
|
|
5536
|
-
child.on("error", (e) => done({ stage: "error", code: e && e.code || String(e) }));
|
|
5537
|
-
child.on("exit", (code, signal) => done({ stage: "exit", code, signal }));
|
|
5538
|
-
});
|
|
5539
|
-
}
|
|
5540
|
-
var OPEN_OBSERVE_MS = 1500;
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
}
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
const
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
const
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
try {
|
|
5569
|
-
child = spawnWith(plan.bin, plan.baseArgs);
|
|
5570
|
-
} catch (e) {
|
|
5571
|
-
evidence.error = e && e.code || String(e);
|
|
5572
|
-
return outcome({ ok: false, reason: "spawn-failed", url, evidence });
|
|
5573
|
-
}
|
|
5574
|
-
if (!child) return outcome({ ok: false, reason: "spawn-failed", url, evidence });
|
|
5575
|
-
const seen = await observe(child, observeMs, opts.setTimeout);
|
|
5576
|
-
evidence.error = seen.stage === "error" ? String(seen.code) : null;
|
|
5577
|
-
evidence.exitCode = seen.code === void 0 ? null : seen.code;
|
|
5578
|
-
evidence.exitSignal = seen.signal === void 0 ? null : seen.signal;
|
|
5579
|
-
if (seen.stage === "error") return outcome({ ok: false, reason: "spawn-failed", url, evidence });
|
|
5580
|
-
const exitDecides = seen.stage === "exit" && plan.exitIsEvidence === true;
|
|
5581
|
-
if (exitDecides && (seen.code !== 0 || seen.signal)) {
|
|
5582
|
-
return outcome({
|
|
5583
|
-
ok: false,
|
|
5584
|
-
reason: seen.signal ? "killed-by-signal" : "exit-nonzero",
|
|
5585
|
-
url,
|
|
5586
|
-
evidence,
|
|
5587
|
-
error: FAILURE_TEXT[seen.signal ? "killed-by-signal" : "exit-nonzero"] + "\uFF08" + (seen.signal || seen.code) + "\uFF09"
|
|
5588
|
-
});
|
|
5589
|
-
}
|
|
5590
|
-
return outcome({ ok: true, confirmed: exitDecides, handedOff: !exitDecides, url, evidence });
|
|
6490
|
+
timer = (setTimeoutFn || setTimeout)(() => done({ stage: "alive" }), windowMs);
|
|
6491
|
+
if (timer && timer.unref) timer.unref();
|
|
6492
|
+
child.on("error", (e) => done({ stage: "error", code: e && e.code || String(e) }));
|
|
6493
|
+
child.on("exit", (code, signal) => done({ stage: "exit", code, signal }));
|
|
6494
|
+
});
|
|
6495
|
+
}
|
|
6496
|
+
var OPEN_OBSERVE_MS = 1500;
|
|
6497
|
+
var LOGIN_TZ_POOL = ["Asia/Shanghai", "Asia/Seoul", "Asia/Tokyo", "Asia/Singapore", "Europe/Berlin", "Europe/London", "Europe/Paris", "America/New_York", "America/Los_Angeles", "Australia/Sydney"];
|
|
6498
|
+
var LOGIN_LANG_POOL = ["zh-CN", "en-US", "en-GB", "ja-JP", "ko-KR", "de-DE", "fr-FR", "zh-TW"];
|
|
6499
|
+
var LOGIN_SIZE_POOL = [[1280, 800], [1366, 768], [1440, 900], [1536, 864], [1600, 900], [1680, 1050], [1920, 1080], [1024, 768], [1152, 864], [1280, 720]];
|
|
6500
|
+
function loginEnv(rand) {
|
|
6501
|
+
const pick = (arr) => arr[Math.floor((typeof rand === "function" ? rand() : Math.random()) * arr.length)];
|
|
6502
|
+
const size = pick(LOGIN_SIZE_POOL);
|
|
6503
|
+
const lang = pick(LOGIN_LANG_POOL);
|
|
6504
|
+
const tz = pick(LOGIN_TZ_POOL);
|
|
6505
|
+
const sysEnv = Object.assign({}, process.env, desktop.sessionEnv());
|
|
6506
|
+
return { size, lang, sysEnv, antiEnv: Object.assign({}, sysEnv, { TZ: tz, LANG: lang }) };
|
|
6507
|
+
}
|
|
6508
|
+
function launchDiagnostics(inv, plan, picked) {
|
|
6509
|
+
const found = (inv && inv.browsers || []).map((b) => ({
|
|
6510
|
+
name: b.name,
|
|
6511
|
+
engine: b.engine || engineOf(b.bin),
|
|
6512
|
+
via: (b.sources && b.sources.length ? b.sources : [b.source || "unknown"]).join("+")
|
|
6513
|
+
}));
|
|
6514
|
+
const pk = picked || {};
|
|
6515
|
+
return {
|
|
6516
|
+
platform: inv && inv.platform || null,
|
|
6517
|
+
pick: pk.how || plan && plan.pick || "none",
|
|
6518
|
+
bin: plan && plan.bin || null,
|
|
6519
|
+
default: inv && inv.defaultId ? { id: inv.defaultId, source: inv.defaultSource || null } : null,
|
|
6520
|
+
preference: pk.wanted ? { id: pk.wanted, matched: pk.stale !== true } : null,
|
|
6521
|
+
found,
|
|
6522
|
+
probed: inv && inv.probed || []
|
|
6523
|
+
};
|
|
5591
6524
|
}
|
|
5592
6525
|
function _spawnDetachedIgnored(bin, args) {
|
|
5593
6526
|
try {
|
|
@@ -5618,232 +6551,112 @@ var require_browser = __commonJS({
|
|
|
5618
6551
|
child.unref();
|
|
5619
6552
|
return child;
|
|
5620
6553
|
}
|
|
5621
|
-
function engineOf(bin) {
|
|
5622
|
-
const base = String(bin || "").toLowerCase().split(/[\\/]/).pop();
|
|
5623
|
-
if (/(chrome|chromium|msedge|edge|brave|vivaldi|opera|thorium)/.test(base)) return "chromium";
|
|
5624
|
-
if (/(firefox|librewolf|waterfox)/.test(base)) return "firefox";
|
|
5625
|
-
return "other";
|
|
5626
|
-
}
|
|
5627
|
-
function tokenizeExec(line) {
|
|
5628
|
-
const toks = [];
|
|
5629
|
-
let cur = "";
|
|
5630
|
-
let q = null;
|
|
5631
|
-
let esc = false;
|
|
5632
|
-
let has = false;
|
|
5633
|
-
for (const ch of String(line)) {
|
|
5634
|
-
if (esc) {
|
|
5635
|
-
cur += ch;
|
|
5636
|
-
esc = false;
|
|
5637
|
-
continue;
|
|
5638
|
-
}
|
|
5639
|
-
if (ch === "\\") {
|
|
5640
|
-
esc = true;
|
|
5641
|
-
has = true;
|
|
5642
|
-
continue;
|
|
5643
|
-
}
|
|
5644
|
-
if (q) {
|
|
5645
|
-
if (ch === q) q = null;
|
|
5646
|
-
else cur += ch;
|
|
5647
|
-
continue;
|
|
5648
|
-
}
|
|
5649
|
-
if (ch === "'" || ch === '"') {
|
|
5650
|
-
q = ch;
|
|
5651
|
-
has = true;
|
|
5652
|
-
continue;
|
|
5653
|
-
}
|
|
5654
|
-
if (/\s/.test(ch)) {
|
|
5655
|
-
if (has) {
|
|
5656
|
-
toks.push(cur);
|
|
5657
|
-
cur = "";
|
|
5658
|
-
has = false;
|
|
5659
|
-
}
|
|
5660
|
-
continue;
|
|
5661
|
-
}
|
|
5662
|
-
cur += ch;
|
|
5663
|
-
has = true;
|
|
5664
|
-
}
|
|
5665
|
-
if (has) toks.push(cur);
|
|
5666
|
-
return toks;
|
|
5667
|
-
}
|
|
5668
|
-
function parseExecLine(line) {
|
|
5669
|
-
let toks = tokenizeExec(line).filter((t) => t !== "%%" && !/^%[a-zA-Z]$/.test(t));
|
|
5670
|
-
if (toks[0] === "env") {
|
|
5671
|
-
let i = 1;
|
|
5672
|
-
while (i < toks.length && /=/.test(toks[i])) i++;
|
|
5673
|
-
toks = toks.slice(i);
|
|
5674
|
-
}
|
|
5675
|
-
if (!toks.length) return null;
|
|
5676
|
-
return { bin: toks[0], baseArgs: toks.slice(1) };
|
|
5677
|
-
}
|
|
5678
|
-
function regValueOf(out) {
|
|
5679
|
-
const m = String(out || "").match(/REG_SZ\s+(.*)/);
|
|
5680
|
-
return m ? m[1].trim() : null;
|
|
5681
|
-
}
|
|
5682
|
-
function exeFromCmdLine(cmdLine) {
|
|
5683
|
-
const s = String(cmdLine || "");
|
|
5684
|
-
let m = s.match(/^\s*"([^"]+\.exe)"/i);
|
|
5685
|
-
if (m) return m[1];
|
|
5686
|
-
m = s.match(/^\s*(\S+\.exe)/i);
|
|
5687
|
-
return m ? m[1] : null;
|
|
5688
|
-
}
|
|
5689
|
-
function resolveDefaultWin(runOut) {
|
|
5690
|
-
const roots = ["HKCU\\Software\\Clients\\StartMenuInternet", "HKLM\\Software\\Clients\\StartMenuInternet"];
|
|
5691
|
-
for (const root of roots) {
|
|
5692
|
-
const progId = regValueOf(runOut("reg.exe", ["query", root, "/ve"]));
|
|
5693
|
-
if (!progId || !/^[\x20-\x7e]+$/.test(progId)) continue;
|
|
5694
|
-
for (const r2 of roots) {
|
|
5695
|
-
const cmd2 = regValueOf(runOut("reg.exe", ["query", r2 + "\\" + progId + "\\shell\\open\\command", "/ve"]));
|
|
5696
|
-
const bin = exeFromCmdLine(cmd2);
|
|
5697
|
-
if (bin) return { bin, baseArgs: [] };
|
|
5698
|
-
}
|
|
5699
|
-
}
|
|
5700
|
-
return null;
|
|
5701
|
-
}
|
|
5702
|
-
var MAC_JXA = [
|
|
5703
|
-
"ObjC.import('CoreServices');ObjC.import('Foundation');",
|
|
5704
|
-
"var b=ObjC.unwrap($.LSCopyDefaultHandlerForURLScheme(null,'https'))||ObjC.unwrap($.LSCopyDefaultHandlerForURLScheme(null,'http'));",
|
|
5705
|
-
"if(!b){'EMPTY';}else{",
|
|
5706
|
-
"var u=$.NSWorkspace.workspace.URLForApplicationWithBundleIdentifier(b);",
|
|
5707
|
-
"if(u.isNil()){'EMPTY';}else{",
|
|
5708
|
-
"var e=ObjC.unwrap($.NSBundle.bundleWithURL(u).objectForInfoDictionaryKey('CFBundleExecutable'));",
|
|
5709
|
-
"b+'\\t'+ObjC.unwrap(u.path)+'\\t'+e;}}"
|
|
5710
|
-
].join("");
|
|
5711
|
-
function resolveDefaultMac(runOut) {
|
|
5712
|
-
const out = runOut("osascript", ["-l", "JavaScript", "-e", MAC_JXA]);
|
|
5713
|
-
if (!out) return null;
|
|
5714
|
-
const parts = out.trim().split(" ");
|
|
5715
|
-
if (parts.length < 3 || parts[0] === "EMPTY" || !parts[2]) return null;
|
|
5716
|
-
return { bin: path2.posix.join(parts[1], "Contents", "MacOS", parts[2]), baseArgs: [], bundleId: parts[0] };
|
|
5717
|
-
}
|
|
5718
|
-
function resolveDefaultLinux(runOut, readFile, exists, env, home) {
|
|
5719
|
-
const id = runOut("xdg-settings", ["get", "default-web-browser"]);
|
|
5720
|
-
const desktop2 = id && id.trim();
|
|
5721
|
-
if (!desktop2 || !/^[A-Za-z0-9._-]+\.desktop$/.test(desktop2)) return null;
|
|
5722
|
-
const dirs = [
|
|
5723
|
-
env.XDG_DATA_HOME || path2.join(home, ".local", "share"),
|
|
5724
|
-
"/usr/local/share",
|
|
5725
|
-
"/usr/share",
|
|
5726
|
-
"/var/lib/snapd/desktop"
|
|
5727
|
-
].map((d) => path2.join(d, "applications"));
|
|
5728
|
-
for (const dir of dirs) {
|
|
5729
|
-
const p = path2.join(dir, desktop2);
|
|
5730
|
-
let text = null;
|
|
5731
|
-
try {
|
|
5732
|
-
if (exists(p)) text = readFile(p);
|
|
5733
|
-
} catch {
|
|
5734
|
-
continue;
|
|
5735
|
-
}
|
|
5736
|
-
if (text === null) continue;
|
|
5737
|
-
let inMain = false;
|
|
5738
|
-
for (const line of text.split(/\r?\n/)) {
|
|
5739
|
-
if (/^\[Desktop Entry\]\s*$/.test(line)) {
|
|
5740
|
-
inMain = true;
|
|
5741
|
-
continue;
|
|
5742
|
-
}
|
|
5743
|
-
if (/^\[/.test(line)) break;
|
|
5744
|
-
if (inMain) {
|
|
5745
|
-
const m = line.match(/^Exec=(.+)/);
|
|
5746
|
-
if (m) return parseExecLine(m[1]);
|
|
5747
|
-
}
|
|
5748
|
-
}
|
|
5749
|
-
}
|
|
5750
|
-
return null;
|
|
5751
|
-
}
|
|
5752
|
-
function resolveDefaultBrowser(platform, o) {
|
|
5753
|
-
const ov = o || {};
|
|
5754
|
-
const pl = platform || process.platform;
|
|
5755
|
-
const runOut = ov.runOut || ((bin, args) => exec.runOut(bin, args, { timeoutMs: 5e3 }));
|
|
5756
|
-
const readFile = ov.readFile || ((p) => fs2.readFileSync(p, "utf8"));
|
|
5757
|
-
const exists = ov.exists || ((p) => fs2.existsSync(p));
|
|
5758
|
-
const env = ov.env || process.env;
|
|
5759
|
-
const home = ov.home || os2.homedir();
|
|
5760
|
-
try {
|
|
5761
|
-
if (pl === "win32") return resolveDefaultWin(runOut);
|
|
5762
|
-
if (pl === "darwin") return resolveDefaultMac(runOut);
|
|
5763
|
-
return resolveDefaultLinux(runOut, readFile, exists, env, home);
|
|
5764
|
-
} catch {
|
|
5765
|
-
return null;
|
|
5766
|
-
}
|
|
5767
|
-
}
|
|
5768
|
-
function isolatedPlan(platform, url, opts) {
|
|
5769
|
-
const o = opts || {};
|
|
5770
|
-
const pl = platform || process.platform;
|
|
5771
|
-
const db = o.defaultBrowser;
|
|
5772
|
-
const engine = db && db.bin ? engineOf(db.bin) : "other";
|
|
5773
|
-
const baseArgs = db && db.baseArgs || [];
|
|
5774
|
-
if (engine === "chromium" && o.profileDir) {
|
|
5775
|
-
const args = ["--incognito", "--user-data-dir=" + o.profileDir];
|
|
5776
|
-
if (Array.isArray(o.size) && o.size.length === 2) args.push("--window-size=" + o.size[0] + "," + o.size[1]);
|
|
5777
|
-
if (o.lang) args.push("--lang=" + o.lang);
|
|
5778
|
-
args.push("--no-first-run", "--no-default-browser-check", "--disable-session-crashed-bubble");
|
|
5779
|
-
return { bin: db.bin, args: [...baseArgs, ...args, url], isolated: true, watch: true, envKind: "anti", label: "chromium" };
|
|
5780
|
-
}
|
|
5781
|
-
if (engine === "firefox" && o.profileDir) {
|
|
5782
|
-
return {
|
|
5783
|
-
bin: db.bin,
|
|
5784
|
-
args: [...baseArgs, "--no-remote", "--profile", o.profileDir, "-private-window", url],
|
|
5785
|
-
isolated: true,
|
|
5786
|
-
watch: true,
|
|
5787
|
-
envKind: "anti",
|
|
5788
|
-
label: "firefox"
|
|
5789
|
-
};
|
|
5790
|
-
}
|
|
5791
|
-
const c = openCommand(pl, url);
|
|
5792
|
-
return { bin: c.cmd, args: c.args, isolated: false, watch: false, envKind: "sys", label: c.cmd };
|
|
5793
|
-
}
|
|
5794
6554
|
function binAvailable(bin) {
|
|
5795
6555
|
if (!bin) return false;
|
|
5796
6556
|
if (bin.includes("/") || bin.includes("\\") || /^[A-Za-z]:[\\/]/.test(bin)) return isExecutableFile(bin);
|
|
5797
6557
|
return resolveExecutable(bin) !== null;
|
|
5798
6558
|
}
|
|
5799
|
-
function
|
|
6559
|
+
async function openBrowser(url, o) {
|
|
5800
6560
|
const opts = o || {};
|
|
5801
|
-
|
|
5802
|
-
const
|
|
5803
|
-
|
|
5804
|
-
|
|
6561
|
+
const pl = opts.platform || process.platform;
|
|
6562
|
+
const intent = opts.intent === "isolated-login" ? "isolated-login" : "plain";
|
|
6563
|
+
if (!isSafeHttpUrl(url)) {
|
|
6564
|
+
return outcome({ ok: false, reason: "unsafe-url", url: String(url || ""), evidence: null });
|
|
6565
|
+
}
|
|
6566
|
+
if (!SUPPORTED_OPEN_PLATFORMS.includes(pl)) {
|
|
6567
|
+
return outcome({ ok: false, reason: "unsupported-platform", url, evidence: { platform: pl } });
|
|
6568
|
+
}
|
|
6569
|
+
const observeMs = opts.observeMs === void 0 ? OPEN_OBSERVE_MS : opts.observeMs;
|
|
6570
|
+
const spawnWith = typeof opts.spawn === "function" ? opts.spawn : intent === "isolated-login" ? _spawnDetached : _spawnDetachedIgnored;
|
|
5805
6571
|
const avail = typeof opts.binAvailable === "function" ? opts.binAvailable : binAvailable;
|
|
5806
|
-
const
|
|
5807
|
-
const
|
|
6572
|
+
const observe = typeof opts.observe === "function" ? opts.observe : observeSpawn;
|
|
6573
|
+
const resolveInv = typeof opts.resolveInventory === "function" ? opts.resolveInventory : ((platform, deps) => environment.browsers(Object.assign({ platform }, deps)));
|
|
6574
|
+
const inv = "inventory" in opts ? opts.inventory : resolveInv(pl, opts.resolveDeps || {});
|
|
6575
|
+
const pref = "preference" in opts ? opts.preference : void 0;
|
|
6576
|
+
const login = intent === "isolated-login" ? loginEnv(opts.rand) : null;
|
|
6577
|
+
const picked = opts.pick || environment.pickLauncher(pl, inv, pref);
|
|
6578
|
+
const form = formOfBin(pl, picked.browser);
|
|
6579
|
+
const canIsolate = intent === "isolated-login" && form.direct && (form.engine === "chromium" || form.engine === "firefox");
|
|
6580
|
+
let profile = null;
|
|
6581
|
+
if (canIsolate) {
|
|
6582
|
+
const alloc = typeof opts.allocProfile === "function" ? opts.allocProfile : (() => allocTempDir("dsh-login-"));
|
|
6583
|
+
try {
|
|
6584
|
+
profile = opts.profileDir || alloc();
|
|
6585
|
+
} catch {
|
|
6586
|
+
profile = null;
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
const plan = intent === "isolated-login" ? isolatedPlan(pl, url, { inventory: inv, pick: picked, profileDir: profile, size: login.size, lang: login.lang }) : openPlan(pl, url, { inventory: inv, pick: picked });
|
|
6590
|
+
const diagnostics = launchDiagnostics(inv, plan, picked);
|
|
6591
|
+
const evidence = {
|
|
6592
|
+
bin: plan.bin,
|
|
6593
|
+
engine: plan.engine,
|
|
6594
|
+
via: plan.via,
|
|
6595
|
+
ownsWindow: plan.exitIsEvidence === true,
|
|
6596
|
+
isolated: plan.isolated === true,
|
|
6597
|
+
profile: plan.isolated ? profile : null,
|
|
6598
|
+
watch: plan.watch === true,
|
|
6599
|
+
exitCode: null,
|
|
6600
|
+
exitSignal: null,
|
|
6601
|
+
error: null,
|
|
6602
|
+
diagnostics
|
|
6603
|
+
};
|
|
6604
|
+
const deferredRemove = typeof opts.rmTree === "function" ? opts.rmTree : removeTreeDeferred;
|
|
6605
|
+
const fail = (reason, patch) => {
|
|
6606
|
+
if (profile) deferredRemove(profile, 0);
|
|
6607
|
+
return outcome(Object.assign({ ok: false, reason, url, evidence }, patch));
|
|
6608
|
+
};
|
|
6609
|
+
const desktopAvailable = typeof opts.desktopAvailable === "function" ? opts.desktopAvailable : desktop.sessionAvailable;
|
|
6610
|
+
if (pl === "linux" && !desktopAvailable()) {
|
|
6611
|
+
return fail("no-desktop-session");
|
|
6612
|
+
}
|
|
6613
|
+
if (!plan.bin) return fail("no-launcher");
|
|
6614
|
+
if (!avail(plan.bin)) return fail("no-launcher");
|
|
6615
|
+
if (canIsolate && !profile) {
|
|
6616
|
+
evidence.error = "\u4E34\u65F6 profile \u76EE\u5F55\u5206\u914D\u5931\u8D25";
|
|
6617
|
+
return fail("spawn-failed");
|
|
6618
|
+
}
|
|
6619
|
+
let child;
|
|
5808
6620
|
try {
|
|
5809
|
-
|
|
5810
|
-
if ("defaultBrowser" in opts) db = opts.defaultBrowser;
|
|
5811
|
-
else if (typeof opts.resolveDefault === "function") db = opts.resolveDefault(process.platform, opts.resolveDeps || {});
|
|
5812
|
-
else db = resolveDefaultBrowser(process.platform, opts.resolveDeps || {});
|
|
5813
|
-
const plan = isolatedPlan(process.platform, url, {
|
|
5814
|
-
defaultBrowser: db,
|
|
5815
|
-
profileDir: opts.profileDir,
|
|
5816
|
-
size: opts.size,
|
|
5817
|
-
lang: opts.lang
|
|
5818
|
-
});
|
|
5819
|
-
if (!avail(plan.bin)) return fail("no-launcher", { evidence: { bin: plan.bin, engine: plan.label, via: plan.isolated ? "browser" : "dispatcher" } });
|
|
5820
|
-
const env = plan.envKind === "anti" ? antiEnv : sysEnv;
|
|
5821
|
-
const p = spawnWith(plan.bin, plan.args, env, plan.watch ? onExit : void 0);
|
|
5822
|
-
if (!p) return fail("spawn-failed");
|
|
5823
|
-
return Object.assign(outcome({ ok: true, confirmed: false, handedOff: true, url }), { bin: plan.label, isolated: plan.isolated });
|
|
6621
|
+
child = intent === "isolated-login" ? spawnWith(plan.bin, plan.args, plan.envKind === "anti" ? login.antiEnv : login.sysEnv, plan.watch ? opts.onExit : void 0) : spawnWith(plan.bin, plan.args);
|
|
5824
6622
|
} catch (e) {
|
|
5825
|
-
|
|
6623
|
+
evidence.error = e && e.code || String(e);
|
|
6624
|
+
return fail("spawn-failed");
|
|
6625
|
+
}
|
|
6626
|
+
if (!child) return fail("spawn-failed");
|
|
6627
|
+
if (evidence.profile) deferredRemove(evidence.profile, opts.profileMs === void 0 ? 30 * 60 * 1e3 : opts.profileMs);
|
|
6628
|
+
const seen = await observe(child, observeMs, opts.setTimeout);
|
|
6629
|
+
evidence.error = seen.stage === "error" ? String(seen.code) : null;
|
|
6630
|
+
evidence.exitCode = seen.code === void 0 ? null : seen.code;
|
|
6631
|
+
evidence.exitSignal = seen.signal === void 0 ? null : seen.signal;
|
|
6632
|
+
if (seen.stage === "error") return outcome({ ok: false, reason: "spawn-failed", url, evidence });
|
|
6633
|
+
const exitDecides = seen.stage === "exit" && plan.exitIsEvidence === true;
|
|
6634
|
+
if (exitDecides && (seen.code !== 0 || seen.signal)) {
|
|
6635
|
+
return outcome({
|
|
6636
|
+
ok: false,
|
|
6637
|
+
reason: seen.signal ? "killed-by-signal" : "exit-nonzero",
|
|
6638
|
+
url,
|
|
6639
|
+
evidence,
|
|
6640
|
+
error: FAILURE_TEXT[seen.signal ? "killed-by-signal" : "exit-nonzero"] + "\uFF08" + (seen.signal || seen.code) + "\uFF09"
|
|
6641
|
+
});
|
|
5826
6642
|
}
|
|
6643
|
+
return outcome({ ok: true, confirmed: exitDecides, handedOff: !exitDecides, url, evidence });
|
|
5827
6644
|
}
|
|
5828
6645
|
module2.exports = {
|
|
5829
6646
|
openBrowser,
|
|
5830
|
-
launchIsolated,
|
|
5831
6647
|
openCommand,
|
|
5832
6648
|
openPlan,
|
|
5833
|
-
ownsItsWindow,
|
|
5834
6649
|
isolatedPlan,
|
|
6650
|
+
ownsItsWindow,
|
|
5835
6651
|
observeSpawn,
|
|
5836
6652
|
isSafeHttpUrl,
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
6653
|
+
binAvailable,
|
|
6654
|
+
launchDiagnostics,
|
|
6655
|
+
loginEnv,
|
|
6656
|
+
// 探测层的解析原语经此转出(唯一实现处在 ./browser-inventory.js):门禁与消费方按同一出口取用,
|
|
6657
|
+
// 不在别处再写第二份平台解析。
|
|
5841
6658
|
engineOf,
|
|
5842
|
-
|
|
5843
|
-
tokenizeExec,
|
|
5844
|
-
regValueOf,
|
|
5845
|
-
exeFromCmdLine,
|
|
5846
|
-
binAvailable
|
|
6659
|
+
detector
|
|
5847
6660
|
};
|
|
5848
6661
|
}
|
|
5849
6662
|
});
|
|
@@ -6196,6 +7009,7 @@ var require_os = __commonJS({
|
|
|
6196
7009
|
var execPath = require_exec_path();
|
|
6197
7010
|
var desktop = require_desktop();
|
|
6198
7011
|
var CAPABILITY_PROFILES = require_capability_profile();
|
|
7012
|
+
var environment = require_environment();
|
|
6199
7013
|
var PLATFORM = process.platform;
|
|
6200
7014
|
var ARCH = process.arch;
|
|
6201
7015
|
var isLinux = PLATFORM === "linux";
|
|
@@ -6250,6 +7064,7 @@ var require_os = __commonJS({
|
|
|
6250
7064
|
}
|
|
6251
7065
|
return p;
|
|
6252
7066
|
}
|
|
7067
|
+
environment.bind({ capabilities });
|
|
6253
7068
|
module2.exports = {
|
|
6254
7069
|
PLATFORM,
|
|
6255
7070
|
ARCH,
|
|
@@ -6273,6 +7088,8 @@ var require_os = __commonJS({
|
|
|
6273
7088
|
// 导出模块对象会抛 platform.notify is not a function,把升级终态误判成失败。
|
|
6274
7089
|
notify: require_notify().notify,
|
|
6275
7090
|
browser: require_browser(),
|
|
7091
|
+
environment,
|
|
7092
|
+
// 环境表单(外部打开链路的事实底座 + 选路依据)
|
|
6276
7093
|
desktop,
|
|
6277
7094
|
// 图形会话可用性(Linux 需实测 socket)
|
|
6278
7095
|
autostart: require_autostart()
|
|
@@ -12391,6 +13208,60 @@ var require_access = __commonJS({
|
|
|
12391
13208
|
}
|
|
12392
13209
|
});
|
|
12393
13210
|
|
|
13211
|
+
// src/app/settings/browser.js
|
|
13212
|
+
var require_browser2 = __commonJS({
|
|
13213
|
+
"src/app/settings/browser.js"(exports2, module2) {
|
|
13214
|
+
"use strict";
|
|
13215
|
+
var platform = require_os();
|
|
13216
|
+
var { verifyPersisted } = require_access();
|
|
13217
|
+
module2.exports = {
|
|
13218
|
+
methods: {
|
|
13219
|
+
/** 当前偏好 + 候选清单 + 这一拍的分发依据(面板据此渲染选择器并说明「现在实际会用谁」)。 */
|
|
13220
|
+
externalBrowserStatus() {
|
|
13221
|
+
try {
|
|
13222
|
+
const form = platform.environment.form();
|
|
13223
|
+
const v = platform.environment.checkPreference(platform.environment.preferenceId(), form);
|
|
13224
|
+
return {
|
|
13225
|
+
ok: true,
|
|
13226
|
+
configured: !!form.preference && form.preference.configured === true,
|
|
13227
|
+
value: form.preference && form.preference.id || null,
|
|
13228
|
+
// stale=true:偏好所指已不在候选清单(被卸载/路径失效),本次分发已回落,需用户重选。
|
|
13229
|
+
stale: !!(form.pick && form.pick.stale),
|
|
13230
|
+
browser: v.browser,
|
|
13231
|
+
candidates: v.candidates,
|
|
13232
|
+
pick: form.pick || null,
|
|
13233
|
+
platform: form.platform
|
|
13234
|
+
};
|
|
13235
|
+
} catch (e) {
|
|
13236
|
+
return { ok: false, error: e.message };
|
|
13237
|
+
}
|
|
13238
|
+
},
|
|
13239
|
+
/** 设置/清除浏览器偏好(空串=清除,回到「按系统默认或候选次序分发」)。 */
|
|
13240
|
+
setExternalBrowser(id) {
|
|
13241
|
+
try {
|
|
13242
|
+
const form = platform.environment.form();
|
|
13243
|
+
const v = platform.environment.checkPreference(id, form);
|
|
13244
|
+
if (!v.ok) return { ok: false, error: v.error };
|
|
13245
|
+
const cfg = this.config || {};
|
|
13246
|
+
cfg.externalBrowser = v.id;
|
|
13247
|
+
const patch = { externalBrowser: v.id };
|
|
13248
|
+
if (this.configPath) {
|
|
13249
|
+
this.state.persistConfigPatch(patch);
|
|
13250
|
+
const persistError = verifyPersisted(this.configPath, patch);
|
|
13251
|
+
if (persistError) return { ok: false, error: persistError };
|
|
13252
|
+
}
|
|
13253
|
+
platform.environment.invalidate();
|
|
13254
|
+
if (this.events) this.events.append("external_browser_changed", { id: v.id, name: v.browser ? v.browser.name : null });
|
|
13255
|
+
return { ok: true, configured: !!v.id, value: v.id, browser: v.browser };
|
|
13256
|
+
} catch (e) {
|
|
13257
|
+
return { ok: false, error: e.message };
|
|
13258
|
+
}
|
|
13259
|
+
}
|
|
13260
|
+
}
|
|
13261
|
+
};
|
|
13262
|
+
}
|
|
13263
|
+
});
|
|
13264
|
+
|
|
12394
13265
|
// src/platform/os/netinfo.js
|
|
12395
13266
|
var require_netinfo = __commonJS({
|
|
12396
13267
|
"src/platform/os/netinfo.js"(exports2, module2) {
|
|
@@ -12608,6 +13479,7 @@ var require_facets = __commonJS({
|
|
|
12608
13479
|
{ name: "settings/node-lts", mod: require_node_lts() },
|
|
12609
13480
|
{ name: "settings/versions", mod: require_versions() },
|
|
12610
13481
|
{ name: "settings/access", mod: require_access() },
|
|
13482
|
+
{ name: "settings/browser", mod: require_browser2() },
|
|
12611
13483
|
{ name: "settings/lan-panel", mod: require_lan_panel() }
|
|
12612
13484
|
];
|
|
12613
13485
|
function installMethods(host2, methods) {
|
|
@@ -14150,6 +15022,7 @@ var require_core5 = __commonJS({
|
|
|
14150
15022
|
function composeCore(host2, rawConfig, configPath) {
|
|
14151
15023
|
host2.config = normalize(rawConfig, domainConfigExtension2());
|
|
14152
15024
|
host2.configPath = typeof configPath === "string" ? configPath : null;
|
|
15025
|
+
platform.environment.bind({ preference: () => host2.config && host2.config.externalBrowser || null });
|
|
14153
15026
|
host2._fileProtectStatus = null;
|
|
14154
15027
|
try {
|
|
14155
15028
|
const fp = platform.fileProtect;
|
|
@@ -17684,89 +18557,13 @@ var require_forward_core = __commonJS({
|
|
|
17684
18557
|
}
|
|
17685
18558
|
});
|
|
17686
18559
|
|
|
17687
|
-
// src/domains/router/ops/browser.js
|
|
17688
|
-
var require_browser2 = __commonJS({
|
|
17689
|
-
"src/domains/router/ops/browser.js"(exports2, module2) {
|
|
17690
|
-
"use strict";
|
|
17691
|
-
var platform = require_os();
|
|
17692
|
-
var fs2 = require("node:fs");
|
|
17693
|
-
var os2 = require("node:os");
|
|
17694
|
-
var path2 = require("node:path");
|
|
17695
|
-
var crypto = require("node:crypto");
|
|
17696
|
-
function graphicalEnv() {
|
|
17697
|
-
const out = {};
|
|
17698
|
-
try {
|
|
17699
|
-
const uid = process.getuid ? String(process.getuid()) : "";
|
|
17700
|
-
const xdgRun = process.env.XDG_RUNTIME_DIR || "/run/user/" + uid;
|
|
17701
|
-
if (!process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
|
|
17702
|
-
const x11 = "/tmp/.X11-unix";
|
|
17703
|
-
try {
|
|
17704
|
-
if (fs2.existsSync(x11)) {
|
|
17705
|
-
const socks = fs2.readdirSync(x11).filter((f) => /^X\d+$/.test(f)).map((f) => parseInt(f.slice(1), 10)).sort((a, b) => a - b);
|
|
17706
|
-
if (socks.length > 0) {
|
|
17707
|
-
out.DISPLAY = ":" + socks[0];
|
|
17708
|
-
const xauth = path2.join(os2.homedir(), ".Xauthority");
|
|
17709
|
-
if (fs2.existsSync(xauth)) out.XAUTHORITY = xauth;
|
|
17710
|
-
}
|
|
17711
|
-
}
|
|
17712
|
-
} catch {
|
|
17713
|
-
}
|
|
17714
|
-
if (!out.DISPLAY) {
|
|
17715
|
-
try {
|
|
17716
|
-
if (fs2.existsSync(xdgRun)) {
|
|
17717
|
-
const wl = fs2.readdirSync(xdgRun).filter((f) => f.startsWith("wayland-")).sort();
|
|
17718
|
-
if (wl.length > 0) out.WAYLAND_DISPLAY = wl[0];
|
|
17719
|
-
}
|
|
17720
|
-
} catch {
|
|
17721
|
-
}
|
|
17722
|
-
}
|
|
17723
|
-
}
|
|
17724
|
-
if (!process.env.DBUS_SESSION_BUS_ADDRESS && fs2.existsSync(path2.join(xdgRun, "bus"))) {
|
|
17725
|
-
out.DBUS_SESSION_BUS_ADDRESS = "unix:path=" + path2.join(xdgRun, "bus");
|
|
17726
|
-
}
|
|
17727
|
-
} catch {
|
|
17728
|
-
}
|
|
17729
|
-
return out;
|
|
17730
|
-
}
|
|
17731
|
-
function openInBrowser(url, onExit) {
|
|
17732
|
-
try {
|
|
17733
|
-
const tmpProfile = path2.join(os2.tmpdir(), "dsh-oauth-" + crypto.randomBytes(8).toString("hex"));
|
|
17734
|
-
const sysEnv = Object.assign({}, process.env, graphicalEnv());
|
|
17735
|
-
const TZ_POOL = ["Asia/Shanghai", "Asia/Seoul", "Asia/Tokyo", "Asia/Singapore", "Europe/Berlin", "Europe/London", "Europe/Paris", "America/New_York", "America/Los_Angeles", "Australia/Sydney"];
|
|
17736
|
-
const LANG_POOL = ["zh-CN", "en-US", "en-GB", "ja-JP", "ko-KR", "de-DE", "fr-FR", "zh-TW"];
|
|
17737
|
-
const SIZE_POOL = [[1280, 800], [1366, 768], [1440, 900], [1536, 864], [1600, 900], [1680, 1050], [1920, 1080], [1024, 768], [1152, 864], [1280, 720]];
|
|
17738
|
-
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
17739
|
-
const size = pick(SIZE_POOL);
|
|
17740
|
-
const lang = pick(LANG_POOL);
|
|
17741
|
-
const tz = pick(TZ_POOL);
|
|
17742
|
-
const antiEnv = Object.assign({}, sysEnv, { TZ: tz, LANG: lang });
|
|
17743
|
-
const r = platform.browser.launchIsolated(url, { profileDir: tmpProfile, size, lang, antiEnv, sysEnv, onExit });
|
|
17744
|
-
if (!r || !r.ok) return { profile: null, result: r || { ok: false, reason: "spawn-failed" } };
|
|
17745
|
-
if (r.isolated) {
|
|
17746
|
-
const t30 = setTimeout(() => {
|
|
17747
|
-
try {
|
|
17748
|
-
fs2.rmSync(tmpProfile, { recursive: true, force: true });
|
|
17749
|
-
} catch {
|
|
17750
|
-
}
|
|
17751
|
-
}, 30 * 60 * 1e3);
|
|
17752
|
-
if (t30.unref) t30.unref();
|
|
17753
|
-
}
|
|
17754
|
-
return { profile: tmpProfile, result: r };
|
|
17755
|
-
} catch (e) {
|
|
17756
|
-
return { profile: null, result: { ok: false, reason: "spawn-failed", error: "\u6D4F\u89C8\u5668\u542F\u52A8\u5931\u8D25\uFF1A" + (e && e.message || e) } };
|
|
17757
|
-
}
|
|
17758
|
-
}
|
|
17759
|
-
module2.exports = { graphicalEnv, openInBrowser };
|
|
17760
|
-
}
|
|
17761
|
-
});
|
|
17762
|
-
|
|
17763
18560
|
// src/domains/router/ops/oauth.js
|
|
17764
18561
|
var require_oauth = __commonJS({
|
|
17765
18562
|
"src/domains/router/ops/oauth.js"(exports2, module2) {
|
|
17766
18563
|
"use strict";
|
|
17767
|
-
var fs2 = require("node:fs");
|
|
17768
18564
|
var crypto = require("node:crypto");
|
|
17769
18565
|
var { createServer } = require("node:http");
|
|
18566
|
+
var { removeTreeDeferred } = require_fs();
|
|
17770
18567
|
function createOAuthOps(deps) {
|
|
17771
18568
|
const d = deps || {};
|
|
17772
18569
|
const ports = d.ports;
|
|
@@ -17931,20 +18728,21 @@ var require_oauth = __commonJS({
|
|
|
17931
18728
|
promise.catch(() => {
|
|
17932
18729
|
});
|
|
17933
18730
|
st._ccLoginPromise = promise;
|
|
17934
|
-
const opened = openInBrowser(authUrl, () => {
|
|
18731
|
+
const opened = await openInBrowser(authUrl, () => {
|
|
17935
18732
|
if (st._ccLoginRound !== roundId) return;
|
|
17936
18733
|
if (st._ccLoginReject) {
|
|
17937
|
-
const
|
|
18734
|
+
const r2 = st._ccLoginReject;
|
|
17938
18735
|
st._ccLoginReject = null;
|
|
17939
18736
|
st._ccLoginResolve = null;
|
|
17940
18737
|
try {
|
|
17941
|
-
|
|
18738
|
+
r2(new Error("\u6D4F\u89C8\u5668\u5DF2\u5173\u95ED\uFF0C\u767B\u5F55\u5DF2\u53D6\u6D88"));
|
|
17942
18739
|
} catch {
|
|
17943
18740
|
}
|
|
17944
18741
|
}
|
|
17945
18742
|
});
|
|
17946
|
-
const
|
|
17947
|
-
|
|
18743
|
+
const r = opened || { ok: false, reason: "spawn-failed" };
|
|
18744
|
+
const ev = r.evidence || {};
|
|
18745
|
+
if (!r.ok) {
|
|
17948
18746
|
st._ccLoginPromise = null;
|
|
17949
18747
|
st._ccLoginResolve = null;
|
|
17950
18748
|
st._ccLoginReject = null;
|
|
@@ -17964,12 +18762,13 @@ var require_oauth = __commonJS({
|
|
|
17964
18762
|
opened: false,
|
|
17965
18763
|
confirmed: false,
|
|
17966
18764
|
handedOff: false,
|
|
17967
|
-
reason:
|
|
17968
|
-
|
|
18765
|
+
reason: r.reason || "no-launcher",
|
|
18766
|
+
evidence: r.evidence || null,
|
|
18767
|
+
error: (r.error || "\u65E0\u6CD5\u8C03\u8D77\u7CFB\u7EDF\u6D4F\u89C8\u5668") + "\uFF0C\u8BF7\u624B\u52A8\u6253\u5F00\u4E0B\u65B9\u5730\u5740\u5B8C\u6210\u6388\u6743"
|
|
17969
18768
|
};
|
|
17970
18769
|
}
|
|
17971
|
-
st._ccLogin = { state, port, server, tmpProfile:
|
|
17972
|
-
return Object.assign({},
|
|
18770
|
+
st._ccLogin = { state, port, server, tmpProfile: ev.profile || null };
|
|
18771
|
+
return Object.assign({}, r, {
|
|
17973
18772
|
ok: true,
|
|
17974
18773
|
authUrl,
|
|
17975
18774
|
url: authUrl,
|
|
@@ -17977,8 +18776,8 @@ var require_oauth = __commonJS({
|
|
|
17977
18776
|
port,
|
|
17978
18777
|
waitMs: 18e4,
|
|
17979
18778
|
opened: true,
|
|
17980
|
-
// 非隔离引擎(Safari
|
|
17981
|
-
isolated:
|
|
18779
|
+
// 非隔离引擎(Safari/打包器包装)由平台层降级:账号隔离不成立,换账号只能靠超时重发或手动窗口。
|
|
18780
|
+
isolated: ev.isolated === true
|
|
17982
18781
|
});
|
|
17983
18782
|
}
|
|
17984
18783
|
async function commandcodeLoginWait(timeoutMs) {
|
|
@@ -18024,15 +18823,7 @@ var require_oauth = __commonJS({
|
|
|
18024
18823
|
st._ccLoginResolve = st._ccLoginReject = null;
|
|
18025
18824
|
return { ok: false, error: e.message };
|
|
18026
18825
|
} finally {
|
|
18027
|
-
if (tmpProfile)
|
|
18028
|
-
const t60 = setTimeout(() => {
|
|
18029
|
-
try {
|
|
18030
|
-
fs2.rmSync(tmpProfile, { recursive: true, force: true });
|
|
18031
|
-
} catch {
|
|
18032
|
-
}
|
|
18033
|
-
}, 60 * 1e3);
|
|
18034
|
-
if (t60.unref) t60.unref();
|
|
18035
|
-
}
|
|
18826
|
+
if (tmpProfile) removeTreeDeferred(tmpProfile, 60 * 1e3);
|
|
18036
18827
|
}
|
|
18037
18828
|
}
|
|
18038
18829
|
return { commandcodeLoginStart, commandcodeLoginWait };
|
|
@@ -18486,8 +19277,8 @@ var require_router_ops = __commonJS({
|
|
|
18486
19277
|
"use strict";
|
|
18487
19278
|
require_port_segments();
|
|
18488
19279
|
var ports = require_ports().shared;
|
|
19280
|
+
var platform = require_os();
|
|
18489
19281
|
var { maskKey } = require_base();
|
|
18490
|
-
var { openInBrowser } = require_browser2();
|
|
18491
19282
|
var { createOAuthOps } = require_oauth();
|
|
18492
19283
|
var { createAppsRegistryOps } = require_apps_registry();
|
|
18493
19284
|
var { createQuotaSyncOps } = require_quotasync();
|
|
@@ -18495,6 +19286,7 @@ var require_router_ops = __commonJS({
|
|
|
18495
19286
|
function createAuxCore(deps) {
|
|
18496
19287
|
const d = deps || {};
|
|
18497
19288
|
const getProviders = d.getProviders || (() => []);
|
|
19289
|
+
const openInBrowser = (url, onExit) => platform.browser.openBrowser(url, { intent: "isolated-login", onExit });
|
|
18498
19290
|
const oauth = createOAuthOps({ ports, openInBrowser });
|
|
18499
19291
|
const apps = createAppsRegistryOps({
|
|
18500
19292
|
getProviders,
|
|
@@ -25512,7 +26304,7 @@ var require_guard = __commonJS({
|
|
|
25512
26304
|
var fs2 = require("node:fs");
|
|
25513
26305
|
var path2 = require("node:path");
|
|
25514
26306
|
function owns(pathname) {
|
|
25515
|
-
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";
|
|
26307
|
+
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/environment" || pathname === "/ports" || pathname === "/shutdown";
|
|
25516
26308
|
}
|
|
25517
26309
|
function fetchDshChangelog(res, sup) {
|
|
25518
26310
|
const v = sup && sup.nativeManager ? sup.nativeManager.versionInfo() : {};
|
|
@@ -25524,7 +26316,7 @@ var require_guard = __commonJS({
|
|
|
25524
26316
|
return res.end(md);
|
|
25525
26317
|
}
|
|
25526
26318
|
function handle(ctx) {
|
|
25527
|
-
const { sup, req, res, pathname, identity, send, collectBody, originAllowed, browser } = ctx;
|
|
26319
|
+
const { sup, req, res, pathname, identity, send, collectBody, originAllowed, browser, environment } = ctx;
|
|
25528
26320
|
if (req.method === "GET" && pathname === "/changelog") {
|
|
25529
26321
|
return fetchDshChangelog(res, sup);
|
|
25530
26322
|
}
|
|
@@ -25630,6 +26422,31 @@ var require_guard = __commonJS({
|
|
|
25630
26422
|
});
|
|
25631
26423
|
return;
|
|
25632
26424
|
}
|
|
26425
|
+
if (req.method === "GET" && pathname === "/settings/external-browser") {
|
|
26426
|
+
return send(200, sup.externalBrowserStatus());
|
|
26427
|
+
}
|
|
26428
|
+
if (req.method === "POST" && pathname === "/settings/external-browser") {
|
|
26429
|
+
if (!originAllowed(req, sup.config.apiPort)) {
|
|
26430
|
+
req.resume();
|
|
26431
|
+
return send(403, {});
|
|
26432
|
+
}
|
|
26433
|
+
collectBody(req, res, 2048, (body) => {
|
|
26434
|
+
let id = null;
|
|
26435
|
+
let given = false;
|
|
26436
|
+
try {
|
|
26437
|
+
const j = body ? JSON.parse(body) : {};
|
|
26438
|
+
if (typeof j.id === "string") {
|
|
26439
|
+
id = j.id;
|
|
26440
|
+
given = true;
|
|
26441
|
+
}
|
|
26442
|
+
} catch {
|
|
26443
|
+
}
|
|
26444
|
+
if (!given) return send(400, { ok: false, error: '\u9700\u8981 {"id":"<\u5019\u9009 id>"}\uFF08\u7A7A\u4E32\u6E05\u9664\u504F\u597D\uFF09' });
|
|
26445
|
+
const r = sup.setExternalBrowser(id);
|
|
26446
|
+
return send(r.ok ? 200 : 500, r);
|
|
26447
|
+
});
|
|
26448
|
+
return;
|
|
26449
|
+
}
|
|
25633
26450
|
if (req.method === "POST" && pathname === "/shutdown") {
|
|
25634
26451
|
if (!originAllowed(req, sup.config.apiPort)) {
|
|
25635
26452
|
req.resume();
|
|
@@ -25688,6 +26505,14 @@ var require_guard = __commonJS({
|
|
|
25688
26505
|
if (req.method === "GET" && pathname === "/env/node-lts") {
|
|
25689
26506
|
return sup.nodeLtsStatus().then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: e.message }));
|
|
25690
26507
|
}
|
|
26508
|
+
if (req.method === "GET" && pathname === "/env/environment") {
|
|
26509
|
+
if (!originAllowed(req, sup.config.apiPort)) {
|
|
26510
|
+
req.resume();
|
|
26511
|
+
return send(403, { ok: false, error: "cross-origin request rejected" });
|
|
26512
|
+
}
|
|
26513
|
+
const force = /[?&]force=1/.test(String(req.url || ""));
|
|
26514
|
+
return Promise.resolve(environment.form({ force, persist: force })).then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: "\u73AF\u5883\u8868\u5355\u88C5\u914D\u5931\u8D25\uFF1A" + (e && e.message || e) }));
|
|
26515
|
+
}
|
|
25691
26516
|
if (req.method === "POST" && pathname === "/env/open-url") {
|
|
25692
26517
|
if (!identity.loopback) {
|
|
25693
26518
|
req.resume();
|
|
@@ -26823,6 +27648,7 @@ var require_server = __commonJS({
|
|
|
26823
27648
|
var { identify } = require_identity3();
|
|
26824
27649
|
var { originAllowed, requestHasAccessKey, isShellOrigin } = require_security();
|
|
26825
27650
|
var browserExit = require_browser();
|
|
27651
|
+
var environmentExit = require_environment();
|
|
26826
27652
|
function safeFail(res, err, where) {
|
|
26827
27653
|
try {
|
|
26828
27654
|
const body = JSON.stringify({ ok: false, error: err && err.message || String(err) });
|
|
@@ -26842,6 +27668,7 @@ var require_server = __commonJS({
|
|
|
26842
27668
|
}
|
|
26843
27669
|
function createServer(sup, deps) {
|
|
26844
27670
|
const browser = deps && deps.browser || browserExit;
|
|
27671
|
+
const environment = deps && deps.environment || environmentExit;
|
|
26845
27672
|
return http2.createServer((req, res) => {
|
|
26846
27673
|
const shellOrigin = (() => {
|
|
26847
27674
|
const o = req.headers.origin;
|
|
@@ -26909,7 +27736,7 @@ var require_server = __commonJS({
|
|
|
26909
27736
|
} catch (e) {
|
|
26910
27737
|
return send(400, { error: "bad request encoding" });
|
|
26911
27738
|
}
|
|
26912
|
-
const ctx = { sup, req, res, pathname: decodedPathname, identity, send, collectBody, originAllowed, tokOf, browser };
|
|
27739
|
+
const ctx = { sup, req, res, pathname: decodedPathname, identity, send, collectBody, originAllowed, tokOf, browser, environment };
|
|
26913
27740
|
for (const d of API_DOMAINS) {
|
|
26914
27741
|
if (d.owns(pathname)) {
|
|
26915
27742
|
try {
|