@dsh-sup/dsh-core-linux-x64 0.1.6-BETA.10 → 0.1.6-BETA.11
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 +384 -133
- package/package.json +1 -1
- package/ui-react/assets/InstancesPage--LhDhPDs.js +3 -0
- package/ui-react/assets/LanPage-D7soTx9V.js +4 -0
- package/ui-react/assets/OverviewPage-DxCKB6BV.js +2 -0
- package/ui-react/assets/PluginsPage-mISvN5b8.js +1 -0
- package/ui-react/assets/RouterPage-vhAx87Fo.js +1 -0
- package/ui-react/assets/SettingsPage-DgA5JCBo.js +1 -0
- package/ui-react/assets/{TasksPage-BsXiGMar.js → TasksPage-CGdHy0sy.js} +1 -1
- package/ui-react/assets/openExternal-CBH3SnvT.js +1 -0
- package/ui-react/assets/{refresh-cw-uOv8eoMN.js → refresh-cw-B-VAKpDt.js} +1 -1
- package/ui-react/assets/{rocket-BYxAkKOI.js → rocket-CLAmwatt.js} +1 -1
- package/ui-react/assets/{shield-check-DskEWpz7.js → shield-check-CMRwmPpk.js} +1 -1
- package/ui-react/assets/supervisor-B5Bq0rnN.css +2 -0
- package/ui-react/assets/supervisor-BbSavtNN.js +41 -0
- package/ui-react/assets/supervisor-C_6Efj6Z.js +11 -0
- package/ui-react/assets/useSupervisorAction-q0YJmhui.js +1 -0
- package/ui-react/assets/widgets-BbRkZm-Z.js +1 -0
- package/ui-react/supervisor.html +3 -3
- package/ui-react/assets/InstancesPage-Bv6gx6Pj.js +0 -3
- package/ui-react/assets/LanPage-BLdWpYNX.js +0 -4
- package/ui-react/assets/OverviewPage-GLglcmt5.js +0 -2
- package/ui-react/assets/PluginsPage-D0w7WSyx.js +0 -5
- package/ui-react/assets/RouterPage-CXHKQf2P.js +0 -1
- package/ui-react/assets/SettingsPage-OuiVCipQ.js +0 -5
- package/ui-react/assets/external-link-CnOCgHhe.js +0 -1
- package/ui-react/assets/supervisor-BnUm3AVQ.js +0 -41
- package/ui-react/assets/supervisor-DJuPMCY8.css +0 -2
- package/ui-react/assets/supervisor-xQMSEUga.js +0 -11
- package/ui-react/assets/useSupervisorAction-CSk4q5cT.js +0 -1
- package/ui-react/assets/widgets-CcAMVR4H.js +0 -1
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.11");
|
|
951
951
|
try {
|
|
952
952
|
return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
|
|
953
953
|
} catch {
|
|
@@ -4634,6 +4634,58 @@ var require_watchdog = __commonJS({
|
|
|
4634
4634
|
}
|
|
4635
4635
|
});
|
|
4636
4636
|
|
|
4637
|
+
// src/platform/os/desktop.js
|
|
4638
|
+
var require_desktop = __commonJS({
|
|
4639
|
+
"src/platform/os/desktop.js"(exports2, module2) {
|
|
4640
|
+
"use strict";
|
|
4641
|
+
var fs2 = require("node:fs");
|
|
4642
|
+
var PLATFORM = process.platform;
|
|
4643
|
+
function hasX11Socket() {
|
|
4644
|
+
try {
|
|
4645
|
+
return fs2.readdirSync("/tmp/.X11-unix").some((f) => /^X\d+$/.test(f));
|
|
4646
|
+
} catch {
|
|
4647
|
+
return false;
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
function hasWaylandSocket() {
|
|
4651
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
4652
|
+
const rt = process.env.XDG_RUNTIME_DIR || "/run/user/" + uid;
|
|
4653
|
+
try {
|
|
4654
|
+
return fs2.readdirSync(rt).some((f) => /^wayland-\d+$/.test(f));
|
|
4655
|
+
} catch {
|
|
4656
|
+
return false;
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
function sessionAvailable() {
|
|
4660
|
+
if (PLATFORM === "linux") {
|
|
4661
|
+
if (process.env.DISPLAY || process.env.WAYLAND_DISPLAY) return true;
|
|
4662
|
+
return hasX11Socket() || hasWaylandSocket();
|
|
4663
|
+
}
|
|
4664
|
+
return PLATFORM === "darwin" || PLATFORM === "win32";
|
|
4665
|
+
}
|
|
4666
|
+
function describe() {
|
|
4667
|
+
if (PLATFORM === "linux") {
|
|
4668
|
+
const byEnv = !!(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
|
|
4669
|
+
const byX = hasX11Socket();
|
|
4670
|
+
const byWl = hasWaylandSocket();
|
|
4671
|
+
return {
|
|
4672
|
+
platform: PLATFORM,
|
|
4673
|
+
available: byEnv || byX || byWl,
|
|
4674
|
+
reason: byEnv ? "env(DISPLAY/WAYLAND_DISPLAY)" : byX ? "x11-socket" : byWl ? "wayland-socket" : "none",
|
|
4675
|
+
display: process.env.DISPLAY || null,
|
|
4676
|
+
waylandDisplay: process.env.WAYLAND_DISPLAY || null
|
|
4677
|
+
};
|
|
4678
|
+
}
|
|
4679
|
+
return {
|
|
4680
|
+
platform: PLATFORM,
|
|
4681
|
+
available: sessionAvailable(),
|
|
4682
|
+
reason: "session-scoped-by-launcher"
|
|
4683
|
+
};
|
|
4684
|
+
}
|
|
4685
|
+
module2.exports = { sessionAvailable, describe, PLATFORM };
|
|
4686
|
+
}
|
|
4687
|
+
});
|
|
4688
|
+
|
|
4637
4689
|
// src/platform/os/capability-profile.js
|
|
4638
4690
|
var require_capability_profile = __commonJS({
|
|
4639
4691
|
"src/platform/os/capability-profile.js"(exports2, module2) {
|
|
@@ -4651,6 +4703,8 @@ var require_capability_profile = __commonJS({
|
|
|
4651
4703
|
autostart: true,
|
|
4652
4704
|
// 期望 systemctl(实测覆写)
|
|
4653
4705
|
frpExpose: true,
|
|
4706
|
+
openBrowser: true,
|
|
4707
|
+
// xdg-open / 解析到的默认浏览器;无图形会话时实测覆写成 false
|
|
4654
4708
|
hostService: "systemd",
|
|
4655
4709
|
guardAutostart: true,
|
|
4656
4710
|
// systemd --user enable + linger
|
|
@@ -4674,6 +4728,8 @@ var require_capability_profile = __commonJS({
|
|
|
4674
4728
|
autostart: true,
|
|
4675
4729
|
// launchctl/LaunchAgent 恒在
|
|
4676
4730
|
frpExpose: true,
|
|
4731
|
+
openBrowser: true,
|
|
4732
|
+
// LaunchServices 解析 + open 直启
|
|
4677
4733
|
hostService: "launchd",
|
|
4678
4734
|
guardAutostart: true,
|
|
4679
4735
|
// LaunchAgent RunAtLoad + KeepAlive
|
|
@@ -4699,6 +4755,9 @@ var require_capability_profile = __commonJS({
|
|
|
4699
4755
|
autostart: true,
|
|
4700
4756
|
// 期望 schtasks(实测覆写)
|
|
4701
4757
|
frpExpose: true,
|
|
4758
|
+
// 可打开,但只有注册表解析到默认浏览器时才有退出证据;退到 explorer.exe 调度器即恒返 0,
|
|
4759
|
+
// 每次调用的证据档位由 openBrowser 的 confirmed/handedOff 如实回报,不在此处宣称。
|
|
4760
|
+
openBrowser: true,
|
|
4702
4761
|
hostService: "windows-service",
|
|
4703
4762
|
guardAutostart: true,
|
|
4704
4763
|
// schtasks DSH-Supervisor(ONLOGON,由壳建立)
|
|
@@ -4717,6 +4776,7 @@ var require_capability_profile = __commonJS({
|
|
|
4717
4776
|
desktopNotify: false,
|
|
4718
4777
|
autostart: false,
|
|
4719
4778
|
frpExpose: false,
|
|
4779
|
+
openBrowser: false,
|
|
4720
4780
|
hostService: "none",
|
|
4721
4781
|
guardAutostart: false,
|
|
4722
4782
|
guardSelfHeal: false,
|
|
@@ -5400,6 +5460,8 @@ var require_browser = __commonJS({
|
|
|
5400
5460
|
var path2 = require("node:path");
|
|
5401
5461
|
var os2 = require("node:os");
|
|
5402
5462
|
var spawnOS = require_spawn();
|
|
5463
|
+
var desktop = require_desktop();
|
|
5464
|
+
var CAPABILITY_PROFILES = require_capability_profile();
|
|
5403
5465
|
var { resolveExecutable, isExecutableFile } = require_exec_path();
|
|
5404
5466
|
var exec = require_exec();
|
|
5405
5467
|
function isSafeHttpUrl(url) {
|
|
@@ -5416,17 +5478,122 @@ var require_browser = __commonJS({
|
|
|
5416
5478
|
if (pl === "win32") return { cmd: "explorer.exe", args: [url] };
|
|
5417
5479
|
return { cmd: "xdg-open", args: [url] };
|
|
5418
5480
|
}
|
|
5419
|
-
|
|
5420
|
-
|
|
5481
|
+
var SUPPORTED_OPEN_PLATFORMS = Object.keys(CAPABILITY_PROFILES).filter((k) => CAPABILITY_PROFILES[k].openBrowser === true);
|
|
5482
|
+
function outcome(p) {
|
|
5483
|
+
const ok = !!p.ok;
|
|
5484
|
+
const confirmed = ok && p.confirmed === true;
|
|
5485
|
+
const handedOff = ok && !confirmed;
|
|
5486
|
+
const reason = ok ? null : p.reason || "failed";
|
|
5487
|
+
return {
|
|
5488
|
+
ok,
|
|
5489
|
+
confirmed,
|
|
5490
|
+
handedOff,
|
|
5491
|
+
reason,
|
|
5492
|
+
error: ok ? null : p.error || FAILURE_TEXT[reason] || "\u6253\u5F00\u5931\u8D25\uFF08" + reason + "\uFF09",
|
|
5493
|
+
message: ok ? confirmed ? CONFIRMED_TEXT : p.message || HANDEDOFF_TEXT : null,
|
|
5494
|
+
url: p.url === void 0 ? null : p.url,
|
|
5495
|
+
evidence: p.evidence || null
|
|
5496
|
+
};
|
|
5497
|
+
}
|
|
5498
|
+
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\u65E0\u6CD5\u786E\u8BA4\u6D4F\u89C8\u5668\u7A97\u53E3\u662F\u5426\u51FA\u73B0";
|
|
5500
|
+
var FAILURE_TEXT = {
|
|
5501
|
+
"unsafe-url": "\u5730\u5740\u4E0D\u662F http(s) \u7EDD\u5BF9 URL\uFF0C\u5DF2\u62D2\u7EDD\u4EA4\u7ED9\u6D4F\u89C8\u5668",
|
|
5502
|
+
"no-launcher": "\u672A\u627E\u5230\u53EF\u7528\u7684\u6D4F\u89C8\u5668\u542F\u52A8\u547D\u4EE4\uFF0C\u8BF7\u624B\u52A8\u6253\u5F00\u8BE5\u5730\u5740",
|
|
5503
|
+
"spawn-failed": "\u6D4F\u89C8\u5668\u542F\u52A8\u5931\u8D25\uFF08\u7CFB\u7EDF\u62D2\u7EDD\u4E86\u8BE5\u547D\u4EE4\uFF09",
|
|
5504
|
+
"exit-nonzero": "\u6D4F\u89C8\u5668\u542F\u52A8\u547D\u4EE4\u4EE5\u975E 0 \u9000\u51FA\uFF0C\u7A97\u53E3\u672A\u51FA\u73B0",
|
|
5505
|
+
"killed-by-signal": "\u6D4F\u89C8\u5668\u542F\u52A8\u547D\u4EE4\u88AB\u7CFB\u7EDF\u7EC8\u6B62",
|
|
5506
|
+
"no-desktop-session": "\u5F53\u524D\u6CA1\u6709\u56FE\u5F62\u4F1A\u8BDD\uFF0C\u65E0\u6CD5\u8C03\u8D77\u6D4F\u89C8\u5668",
|
|
5507
|
+
"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
|
+
};
|
|
5509
|
+
function openPlan(platform, url, opts) {
|
|
5510
|
+
const o = opts || {};
|
|
5511
|
+
const pl = platform || process.platform;
|
|
5512
|
+
const db = o.defaultBrowser;
|
|
5513
|
+
const engine = db && db.bin ? engineOf(db.bin) : "other";
|
|
5514
|
+
if (engine === "chromium" || engine === "firefox") {
|
|
5515
|
+
return { bin: db.bin, engine, via: "browser", baseArgs: (db.baseArgs || []).concat([url]), trustExit: true };
|
|
5516
|
+
}
|
|
5517
|
+
const c = openCommand(pl, url);
|
|
5518
|
+
return { bin: c.cmd, engine: "other", via: "dispatcher", baseArgs: c.args, trustExit: pl !== "win32" };
|
|
5519
|
+
}
|
|
5520
|
+
function observeSpawn(child, windowMs, setTimeoutFn) {
|
|
5521
|
+
return new Promise((resolve) => {
|
|
5522
|
+
let settled = false;
|
|
5523
|
+
let timer;
|
|
5524
|
+
const done = (r) => {
|
|
5525
|
+
if (settled) return;
|
|
5526
|
+
settled = true;
|
|
5527
|
+
clearTimeout(timer);
|
|
5528
|
+
resolve(r);
|
|
5529
|
+
};
|
|
5530
|
+
timer = (setTimeoutFn || setTimeout)(() => done({ stage: "alive" }), windowMs);
|
|
5531
|
+
if (timer && timer.unref) timer.unref();
|
|
5532
|
+
child.on("error", (e) => done({ stage: "error", code: e && e.code || String(e) }));
|
|
5533
|
+
child.on("exit", (code, signal) => done({ stage: "exit", code, signal }));
|
|
5534
|
+
});
|
|
5535
|
+
}
|
|
5536
|
+
var OPEN_OBSERVE_MS = 1500;
|
|
5537
|
+
async function openBrowser(url, o) {
|
|
5538
|
+
const opts = o || {};
|
|
5539
|
+
const pl = opts.platform || process.platform;
|
|
5540
|
+
if (!isSafeHttpUrl(url)) {
|
|
5541
|
+
return outcome({ ok: false, reason: "unsafe-url", url: String(url || ""), evidence: null });
|
|
5542
|
+
}
|
|
5543
|
+
if (!SUPPORTED_OPEN_PLATFORMS.includes(pl)) {
|
|
5544
|
+
return outcome({ ok: false, reason: "unsupported-platform", url, evidence: { platform: pl } });
|
|
5545
|
+
}
|
|
5546
|
+
const observeMs = opts.observeMs === void 0 ? OPEN_OBSERVE_MS : opts.observeMs;
|
|
5547
|
+
const spawnWith = typeof opts.spawn === "function" ? opts.spawn : _spawnDetachedIgnored;
|
|
5548
|
+
const avail = typeof opts.binAvailable === "function" ? opts.binAvailable : binAvailable;
|
|
5549
|
+
const observe = typeof opts.observe === "function" ? opts.observe : observeSpawn;
|
|
5550
|
+
let db;
|
|
5551
|
+
if ("defaultBrowser" in opts) db = opts.defaultBrowser;
|
|
5552
|
+
else if (typeof opts.resolveDefault === "function") db = opts.resolveDefault(pl, opts.resolveDeps || {});
|
|
5553
|
+
else db = resolveDefaultBrowser(pl, opts.resolveDeps || {});
|
|
5554
|
+
const plan = openPlan(pl, url, { defaultBrowser: db });
|
|
5555
|
+
const evidence = { bin: plan.bin, engine: plan.engine, via: plan.via, exitCode: null, exitSignal: null, error: null };
|
|
5556
|
+
const desktopAvailable = typeof opts.desktopAvailable === "function" ? opts.desktopAvailable : desktop.sessionAvailable;
|
|
5557
|
+
if (pl === "linux" && !desktopAvailable()) {
|
|
5558
|
+
return outcome({ ok: false, reason: "no-desktop-session", url, evidence });
|
|
5559
|
+
}
|
|
5560
|
+
if (!avail(plan.bin)) {
|
|
5561
|
+
return outcome({ ok: false, reason: "no-launcher", url, evidence });
|
|
5562
|
+
}
|
|
5563
|
+
let child;
|
|
5564
|
+
try {
|
|
5565
|
+
child = spawnWith(plan.bin, plan.baseArgs);
|
|
5566
|
+
} catch (e) {
|
|
5567
|
+
evidence.error = e && e.code || String(e);
|
|
5568
|
+
return outcome({ ok: false, reason: "spawn-failed", url, evidence });
|
|
5569
|
+
}
|
|
5570
|
+
if (!child) return outcome({ ok: false, reason: "spawn-failed", url, evidence });
|
|
5571
|
+
const seen = await observe(child, observeMs, opts.setTimeout);
|
|
5572
|
+
evidence.error = seen.stage === "error" ? String(seen.code) : null;
|
|
5573
|
+
evidence.exitCode = seen.code === void 0 ? null : seen.code;
|
|
5574
|
+
evidence.exitSignal = seen.signal === void 0 ? null : seen.signal;
|
|
5575
|
+
if (seen.stage === "error") return outcome({ ok: false, reason: "spawn-failed", url, evidence });
|
|
5576
|
+
if (seen.stage === "exit" && (seen.code !== 0 || seen.signal)) {
|
|
5577
|
+
return outcome({
|
|
5578
|
+
ok: false,
|
|
5579
|
+
reason: seen.signal ? "killed-by-signal" : "exit-nonzero",
|
|
5580
|
+
url,
|
|
5581
|
+
evidence,
|
|
5582
|
+
error: FAILURE_TEXT[seen.signal ? "killed-by-signal" : "exit-nonzero"] + "\uFF08" + (seen.signal || seen.code) + "\uFF09"
|
|
5583
|
+
});
|
|
5584
|
+
}
|
|
5585
|
+
const exitEvidence = seen.stage === "exit" && plan.trustExit;
|
|
5586
|
+
return outcome({ ok: true, confirmed: exitEvidence, handedOff: !exitEvidence, url, evidence });
|
|
5587
|
+
}
|
|
5588
|
+
function _spawnDetachedIgnored(bin, args) {
|
|
5421
5589
|
try {
|
|
5422
|
-
const
|
|
5423
|
-
const p = spawnOS.detachedIgnored(c.cmd, c.args);
|
|
5590
|
+
const p = spawnOS.detachedIgnored(bin, args);
|
|
5424
5591
|
p.on("error", () => {
|
|
5425
5592
|
});
|
|
5426
5593
|
p.unref();
|
|
5427
|
-
return
|
|
5594
|
+
return p;
|
|
5428
5595
|
} catch {
|
|
5429
|
-
return
|
|
5596
|
+
return null;
|
|
5430
5597
|
}
|
|
5431
5598
|
}
|
|
5432
5599
|
function _spawnDetached(bin, args, env, onExit) {
|
|
@@ -5546,8 +5713,8 @@ var require_browser = __commonJS({
|
|
|
5546
5713
|
}
|
|
5547
5714
|
function resolveDefaultLinux(runOut, readFile, exists, env, home) {
|
|
5548
5715
|
const id = runOut("xdg-settings", ["get", "default-web-browser"]);
|
|
5549
|
-
const
|
|
5550
|
-
if (!
|
|
5716
|
+
const desktop2 = id && id.trim();
|
|
5717
|
+
if (!desktop2 || !/^[A-Za-z0-9._-]+\.desktop$/.test(desktop2)) return null;
|
|
5551
5718
|
const dirs = [
|
|
5552
5719
|
env.XDG_DATA_HOME || path2.join(home, ".local", "share"),
|
|
5553
5720
|
"/usr/local/share",
|
|
@@ -5555,7 +5722,7 @@ var require_browser = __commonJS({
|
|
|
5555
5722
|
"/var/lib/snapd/desktop"
|
|
5556
5723
|
].map((d) => path2.join(d, "applications"));
|
|
5557
5724
|
for (const dir of dirs) {
|
|
5558
|
-
const p = path2.join(dir,
|
|
5725
|
+
const p = path2.join(dir, desktop2);
|
|
5559
5726
|
let text = null;
|
|
5560
5727
|
try {
|
|
5561
5728
|
if (exists(p)) text = readFile(p);
|
|
@@ -5627,12 +5794,13 @@ var require_browser = __commonJS({
|
|
|
5627
5794
|
}
|
|
5628
5795
|
function launchIsolated(url, o) {
|
|
5629
5796
|
const opts = o || {};
|
|
5630
|
-
if (!isSafeHttpUrl(url)) return { ok: false, bin: null, isolated: false };
|
|
5797
|
+
if (!isSafeHttpUrl(url)) return Object.assign(outcome({ ok: false, reason: "unsafe-url", url: String(url || "") }), { bin: null, isolated: false });
|
|
5631
5798
|
const antiEnv = opts.antiEnv || opts.sysEnv || process.env;
|
|
5632
5799
|
const sysEnv = opts.sysEnv || process.env;
|
|
5633
5800
|
const onExit = opts.onExit;
|
|
5634
5801
|
const avail = typeof opts.binAvailable === "function" ? opts.binAvailable : binAvailable;
|
|
5635
5802
|
const spawnWith = typeof opts.spawn === "function" ? opts.spawn : _spawnDetached;
|
|
5803
|
+
const fail = (reason, extra) => Object.assign(outcome(Object.assign({ ok: false, reason, url }, extra)), { bin: null, isolated: false });
|
|
5636
5804
|
try {
|
|
5637
5805
|
let db;
|
|
5638
5806
|
if ("defaultBrowser" in opts) db = opts.defaultBrowser;
|
|
@@ -5644,19 +5812,22 @@ var require_browser = __commonJS({
|
|
|
5644
5812
|
size: opts.size,
|
|
5645
5813
|
lang: opts.lang
|
|
5646
5814
|
});
|
|
5647
|
-
if (!avail(plan.bin)) return {
|
|
5815
|
+
if (!avail(plan.bin)) return fail("no-launcher", { evidence: { bin: plan.bin, engine: plan.label, via: plan.isolated ? "browser" : "dispatcher" } });
|
|
5648
5816
|
const env = plan.envKind === "anti" ? antiEnv : sysEnv;
|
|
5649
5817
|
const p = spawnWith(plan.bin, plan.args, env, plan.watch ? onExit : void 0);
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
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 });
|
|
5820
|
+
} catch (e) {
|
|
5821
|
+
return fail("spawn-failed", { error: FAILURE_TEXT["spawn-failed"] + "\uFF08" + (e && e.code || e) + "\uFF09" });
|
|
5653
5822
|
}
|
|
5654
5823
|
}
|
|
5655
5824
|
module2.exports = {
|
|
5656
|
-
|
|
5825
|
+
openBrowser,
|
|
5657
5826
|
launchIsolated,
|
|
5658
5827
|
openCommand,
|
|
5828
|
+
openPlan,
|
|
5659
5829
|
isolatedPlan,
|
|
5830
|
+
observeSpawn,
|
|
5660
5831
|
isSafeHttpUrl,
|
|
5661
5832
|
resolveDefaultBrowser,
|
|
5662
5833
|
resolveDefaultWin,
|
|
@@ -5672,58 +5843,6 @@ var require_browser = __commonJS({
|
|
|
5672
5843
|
}
|
|
5673
5844
|
});
|
|
5674
5845
|
|
|
5675
|
-
// src/platform/os/desktop.js
|
|
5676
|
-
var require_desktop = __commonJS({
|
|
5677
|
-
"src/platform/os/desktop.js"(exports2, module2) {
|
|
5678
|
-
"use strict";
|
|
5679
|
-
var fs2 = require("node:fs");
|
|
5680
|
-
var PLATFORM = process.platform;
|
|
5681
|
-
function hasX11Socket() {
|
|
5682
|
-
try {
|
|
5683
|
-
return fs2.readdirSync("/tmp/.X11-unix").some((f) => /^X\d+$/.test(f));
|
|
5684
|
-
} catch {
|
|
5685
|
-
return false;
|
|
5686
|
-
}
|
|
5687
|
-
}
|
|
5688
|
-
function hasWaylandSocket() {
|
|
5689
|
-
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
5690
|
-
const rt = process.env.XDG_RUNTIME_DIR || "/run/user/" + uid;
|
|
5691
|
-
try {
|
|
5692
|
-
return fs2.readdirSync(rt).some((f) => /^wayland-\d+$/.test(f));
|
|
5693
|
-
} catch {
|
|
5694
|
-
return false;
|
|
5695
|
-
}
|
|
5696
|
-
}
|
|
5697
|
-
function sessionAvailable() {
|
|
5698
|
-
if (PLATFORM === "linux") {
|
|
5699
|
-
if (process.env.DISPLAY || process.env.WAYLAND_DISPLAY) return true;
|
|
5700
|
-
return hasX11Socket() || hasWaylandSocket();
|
|
5701
|
-
}
|
|
5702
|
-
return PLATFORM === "darwin" || PLATFORM === "win32";
|
|
5703
|
-
}
|
|
5704
|
-
function describe() {
|
|
5705
|
-
if (PLATFORM === "linux") {
|
|
5706
|
-
const byEnv = !!(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
|
|
5707
|
-
const byX = hasX11Socket();
|
|
5708
|
-
const byWl = hasWaylandSocket();
|
|
5709
|
-
return {
|
|
5710
|
-
platform: PLATFORM,
|
|
5711
|
-
available: byEnv || byX || byWl,
|
|
5712
|
-
reason: byEnv ? "env(DISPLAY/WAYLAND_DISPLAY)" : byX ? "x11-socket" : byWl ? "wayland-socket" : "none",
|
|
5713
|
-
display: process.env.DISPLAY || null,
|
|
5714
|
-
waylandDisplay: process.env.WAYLAND_DISPLAY || null
|
|
5715
|
-
};
|
|
5716
|
-
}
|
|
5717
|
-
return {
|
|
5718
|
-
platform: PLATFORM,
|
|
5719
|
-
available: sessionAvailable(),
|
|
5720
|
-
reason: "session-scoped-by-launcher"
|
|
5721
|
-
};
|
|
5722
|
-
}
|
|
5723
|
-
module2.exports = { sessionAvailable, describe, PLATFORM };
|
|
5724
|
-
}
|
|
5725
|
-
});
|
|
5726
|
-
|
|
5727
5846
|
// src/platform/os/autostart/win32.js
|
|
5728
5847
|
var require_win32 = __commonJS({
|
|
5729
5848
|
"src/platform/os/autostart/win32.js"(exports2, module2) {
|
|
@@ -6070,6 +6189,7 @@ var require_os = __commonJS({
|
|
|
6070
6189
|
var path2 = require("node:path");
|
|
6071
6190
|
var ex2 = require_exec();
|
|
6072
6191
|
var execPath = require_exec_path();
|
|
6192
|
+
var desktop = require_desktop();
|
|
6073
6193
|
var CAPABILITY_PROFILES = require_capability_profile();
|
|
6074
6194
|
var PLATFORM = process.platform;
|
|
6075
6195
|
var ARCH = process.arch;
|
|
@@ -6115,6 +6235,7 @@ var require_os = __commonJS({
|
|
|
6115
6235
|
p.sandboxEnforcement = hasTool("systemd-run") ? "cgroup" : "supervise";
|
|
6116
6236
|
p.desktopNotify = hasTool("notify-send");
|
|
6117
6237
|
p.autostart = hasTool("systemctl");
|
|
6238
|
+
p.openBrowser = desktop.sessionAvailable();
|
|
6118
6239
|
} else if (pl === "darwin") {
|
|
6119
6240
|
p.desktopNotify = hasTool("osascript");
|
|
6120
6241
|
} else if (pl === "win32") {
|
|
@@ -6147,7 +6268,7 @@ var require_os = __commonJS({
|
|
|
6147
6268
|
// 导出模块对象会抛 platform.notify is not a function,把升级终态误判成失败。
|
|
6148
6269
|
notify: require_notify().notify,
|
|
6149
6270
|
browser: require_browser(),
|
|
6150
|
-
desktop
|
|
6271
|
+
desktop,
|
|
6151
6272
|
// 图形会话可用性(Linux 需实测 socket)
|
|
6152
6273
|
autostart: require_autostart()
|
|
6153
6274
|
};
|
|
@@ -10916,6 +11037,7 @@ var require_lan = __commonJS({
|
|
|
10916
11037
|
module2.exports = { methods: {
|
|
10917
11038
|
// 远程控制委托:全部转发给 LanManager;daemon 监督模式经 43108 ctl 委托(异步),本地模式走 LanManager(同步)。
|
|
10918
11039
|
// 令牌收敛:listLan 输出必须剔除 token/dshToken —— /lan-access 允许 LAN/私网 Host 访问,直出会把 DSH 会话令牌泄漏给局域网,权威仍在 DshTokenService。
|
|
11040
|
+
// 远程访问令牌的明文也不在此下发:它是实例意图字段,只随 /instances 的回环分支交给本机面板(api/domains/instances.js#decorate)。
|
|
10919
11041
|
// remote(projectRemoteView 产物)为后端单一推导视图 {mode,ready,accessUrl,reasons},不含机密,整段放行给 UI。返回形如 {items,addresses}。
|
|
10920
11042
|
listLan() {
|
|
10921
11043
|
const d = depsOf(this);
|
|
@@ -10928,7 +11050,7 @@ var require_lan = __commonJS({
|
|
|
10928
11050
|
dshPort: it.dshPort,
|
|
10929
11051
|
wanPort: it.wanPort,
|
|
10930
11052
|
running: !!it.running,
|
|
10931
|
-
// 令牌状态(布尔,不泄明文):
|
|
11053
|
+
// 令牌状态(布尔,不泄明文):UI 据此引导,明文的查看/修改走 /instances 的回环分支。
|
|
10932
11054
|
tokenSet: !!String(it.token || "").trim(),
|
|
10933
11055
|
remote: it.remote || null
|
|
10934
11056
|
};
|
|
@@ -11097,7 +11219,7 @@ var require_main = __commonJS({
|
|
|
11097
11219
|
guardian: m.guardian,
|
|
11098
11220
|
remoteMode: m.remoteMode,
|
|
11099
11221
|
remoteToken: m.remoteToken,
|
|
11100
|
-
// 进程内消费(LanManager mainOf);API
|
|
11222
|
+
// 进程内消费(LanManager mainOf);API 边界按回环判据决定去留(api/domains/instances.js#decorate)
|
|
11101
11223
|
unitName: null,
|
|
11102
11224
|
// systemd 托管已废弃:main 由守卫 spawn/观测
|
|
11103
11225
|
// 实时运行态:native 条目缺 state 会导致远程控制页误判「实例已停止」
|
|
@@ -11463,6 +11585,9 @@ if (typeof crypto.randomUUID !== 'function') {
|
|
|
11463
11585
|
}
|
|
11464
11586
|
return { ok: true };
|
|
11465
11587
|
}
|
|
11588
|
+
function generateRemoteToken() {
|
|
11589
|
+
return crypto.randomBytes(12).toString("base64url");
|
|
11590
|
+
}
|
|
11466
11591
|
function normalizeRemoteMode(v) {
|
|
11467
11592
|
return v === "lan" || v === "wan" ? v : "off";
|
|
11468
11593
|
}
|
|
@@ -11472,9 +11597,9 @@ if (typeof crypto.randomUUID !== 'function') {
|
|
|
11472
11597
|
if (mode === "off") return { mode, ready: false, accessUrl: null, reasons: [] };
|
|
11473
11598
|
const reasons = [];
|
|
11474
11599
|
if (!x.relayListening) reasons.push("\u8FDC\u7A0B\u670D\u52A1\u672A\u5C31\u7EEA\uFF08relay \u672A\u76D1\u542C\uFF09");
|
|
11475
|
-
if (!x.tokenSet) reasons.push("\u672A\u8BBE\u8BBF\u95EE\u4EE4\u724C");
|
|
11476
11600
|
else if (!x.cookieReady) reasons.push("\u6B63\u5728\u6CE8\u5165 DSH \u4F1A\u8BDD\u2026");
|
|
11477
11601
|
if (mode === "wan") {
|
|
11602
|
+
if (!x.tokenSet) reasons.push("\u672A\u8BBE\u8BBF\u95EE\u4EE4\u724C");
|
|
11478
11603
|
if (!String(x.serverAddr || "").trim()) reasons.push("\u672A\u914D\u7F6E frps \u670D\u52A1\u5668\u5730\u5740");
|
|
11479
11604
|
if (!x.frpcRunning) reasons.push("\u516C\u7F51\u96A7\u9053\u672A\u5EFA\u7ACB\uFF08frpc \u672A\u8FD0\u884C\uFF09");
|
|
11480
11605
|
}
|
|
@@ -11498,6 +11623,7 @@ if (typeof crypto.randomUUID !== 'function') {
|
|
|
11498
11623
|
buildFrpcToml,
|
|
11499
11624
|
normalizeFrpSettings,
|
|
11500
11625
|
normalizeRemoteMode,
|
|
11626
|
+
generateRemoteToken,
|
|
11501
11627
|
validateFrpServerSettings,
|
|
11502
11628
|
validateWanAccess,
|
|
11503
11629
|
projectRemoteView
|
|
@@ -11509,7 +11635,7 @@ if (typeof crypto.randomUUID !== 'function') {
|
|
|
11509
11635
|
var require_lan2 = __commonJS({
|
|
11510
11636
|
"src/app/domain-actions/lan.js"(exports2, module2) {
|
|
11511
11637
|
"use strict";
|
|
11512
|
-
var { validateWanAccess } = require_core4();
|
|
11638
|
+
var { validateWanAccess, generateRemoteToken } = require_core4();
|
|
11513
11639
|
var { remoteTokenStrength } = require_credential();
|
|
11514
11640
|
function lanModule(deps) {
|
|
11515
11641
|
const lm = typeof deps.getLifecycleManager === "function" ? deps.getLifecycleManager() : null;
|
|
@@ -11563,26 +11689,49 @@ var require_lan2 = __commonJS({
|
|
|
11563
11689
|
}
|
|
11564
11690
|
return {
|
|
11565
11691
|
/** 远程控制模式唯一写入口(off|lan|wan)。mode 必须显式给出——缺省归 'off' 会让
|
|
11566
|
-
* 漏字段的请求静默关闭远程控制。
|
|
11692
|
+
* 漏字段的请求静默关闭远程控制。
|
|
11693
|
+
* 开启(lan|wan)时若该实例压根没有访问令牌,就在这里分配一个并随模式一次落盘:
|
|
11694
|
+
* 「开启远程控制」是用户唯一的开远程动作,把「先去别处设令牌」留在流程里,产出的是开关已开、
|
|
11695
|
+
* 屏幕无二维码、用户也不知凭据为何的半截状态。已有令牌(含过弱的)一律不覆盖——静默改写
|
|
11696
|
+
* 用户自设凭据是另一类事故,弱令牌交给 wan 闸显式拒绝并把用户引到令牌框。
|
|
11697
|
+
* wan 前置闸按**补齐后**的令牌复判:分配在复判之前完成、落盘在复判之后发生,被拒仍零写入。 */
|
|
11567
11698
|
setRemoteMode(id, mode) {
|
|
11568
11699
|
if (mode !== "off" && mode !== "lan" && mode !== "wan") {
|
|
11569
11700
|
return { ok: false, error: "mode \u5FC5\u987B\u663E\u5F0F\u7ED9\u51FA\uFF08off|lan|wan\uFF09" };
|
|
11570
11701
|
}
|
|
11571
11702
|
const target = resolveTarget(id);
|
|
11572
11703
|
if (!target) return { ok: false, error: "\u5B9E\u4F8B\u4E0D\u5B58\u5728" };
|
|
11704
|
+
const allocate = mode !== "off" && !String(target.remoteToken || "").trim();
|
|
11705
|
+
const nextToken = allocate ? generateRemoteToken() : target.remoteToken;
|
|
11573
11706
|
if (mode === "wan") {
|
|
11574
|
-
const v = validateWanAccess({ remoteToken:
|
|
11707
|
+
const v = validateWanAccess({ remoteToken: nextToken });
|
|
11575
11708
|
if (!v.ok) return { ok: false, error: v.error };
|
|
11576
11709
|
}
|
|
11577
11710
|
if (target.kind === "main") {
|
|
11578
|
-
|
|
11579
|
-
|
|
11711
|
+
const patch = { remoteMode: mode };
|
|
11712
|
+
if (allocate) patch.remoteToken = nextToken;
|
|
11713
|
+
if (allocate || target.mode !== mode) {
|
|
11714
|
+
applyMainIntent(patch, { id: "main", name: "\u539F\u751F DSH", mode });
|
|
11715
|
+
if (allocate) {
|
|
11716
|
+
const events = g.getEvents();
|
|
11717
|
+
if (events) {
|
|
11718
|
+
try {
|
|
11719
|
+
events.append("dsh_remote_token_changed", { id: "main", tokenSet: true, autoAllocated: true });
|
|
11720
|
+
} catch {
|
|
11721
|
+
}
|
|
11722
|
+
}
|
|
11723
|
+
}
|
|
11724
|
+
}
|
|
11725
|
+
return { ok: true, tokenAutoAllocated: allocate };
|
|
11580
11726
|
}
|
|
11581
|
-
|
|
11727
|
+
const r = allocate ? g.getInstances().updateInstance(id, { remoteMode: mode, remoteToken: nextToken }) : g.getInstances().updateInstance(id, { remoteMode: mode });
|
|
11728
|
+
if (r && r.ok !== false) r.tokenAutoAllocated = allocate;
|
|
11729
|
+
return r;
|
|
11582
11730
|
},
|
|
11583
|
-
/**
|
|
11584
|
-
* 拒绝而非当作清除(漏 token 字段清掉访问凭据是事故,不是语义)。
|
|
11585
|
-
*
|
|
11731
|
+
/** 访问令牌唯一显式写入口。token 必须是字符串:空串=显式清除;缺字段/非字符串=请求方缺陷,
|
|
11732
|
+
* 拒绝而非当作清除(漏 token 字段清掉访问凭据是事故,不是语义)。
|
|
11733
|
+
* lan 模式清除后仍然可用(relay 空令牌放行),但下一次写入远程控制模式会由 setRemoteMode 重新分配;
|
|
11734
|
+
* wan 模式的守门由执行边界闸兜住(令牌清空后 syncFrpc 复判不过闸即停隧道)。 */
|
|
11586
11735
|
setRemoteToken(id, token) {
|
|
11587
11736
|
if (typeof token !== "string") {
|
|
11588
11737
|
return { ok: false, error: "token \u5FC5\u987B\u663E\u5F0F\u7ED9\u51FA\uFF08\u7A7A\u4E32=\u6E05\u9664\uFF09" };
|
|
@@ -17587,7 +17736,7 @@ var require_browser2 = __commonJS({
|
|
|
17587
17736
|
const tz = pick(TZ_POOL);
|
|
17588
17737
|
const antiEnv = Object.assign({}, sysEnv, { TZ: tz, LANG: lang });
|
|
17589
17738
|
const r = platform.browser.launchIsolated(url, { profileDir: tmpProfile, size, lang, antiEnv, sysEnv, onExit });
|
|
17590
|
-
if (!r || !r.ok) return null;
|
|
17739
|
+
if (!r || !r.ok) return { profile: null, result: r || { ok: false, reason: "spawn-failed" } };
|
|
17591
17740
|
if (r.isolated) {
|
|
17592
17741
|
const t30 = setTimeout(() => {
|
|
17593
17742
|
try {
|
|
@@ -17597,9 +17746,9 @@ var require_browser2 = __commonJS({
|
|
|
17597
17746
|
}, 30 * 60 * 1e3);
|
|
17598
17747
|
if (t30.unref) t30.unref();
|
|
17599
17748
|
}
|
|
17600
|
-
return tmpProfile;
|
|
17601
|
-
} catch {
|
|
17602
|
-
return null;
|
|
17749
|
+
return { profile: tmpProfile, result: r };
|
|
17750
|
+
} catch (e) {
|
|
17751
|
+
return { profile: null, result: { ok: false, reason: "spawn-failed", error: "\u6D4F\u89C8\u5668\u542F\u52A8\u5931\u8D25\uFF1A" + (e && e.message || e) } };
|
|
17603
17752
|
}
|
|
17604
17753
|
}
|
|
17605
17754
|
module2.exports = { graphicalEnv, openInBrowser };
|
|
@@ -17777,7 +17926,7 @@ var require_oauth = __commonJS({
|
|
|
17777
17926
|
promise.catch(() => {
|
|
17778
17927
|
});
|
|
17779
17928
|
st._ccLoginPromise = promise;
|
|
17780
|
-
const
|
|
17929
|
+
const opened = openInBrowser(authUrl, () => {
|
|
17781
17930
|
if (st._ccLoginRound !== roundId) return;
|
|
17782
17931
|
if (st._ccLoginReject) {
|
|
17783
17932
|
const r = st._ccLoginReject;
|
|
@@ -17789,7 +17938,8 @@ var require_oauth = __commonJS({
|
|
|
17789
17938
|
}
|
|
17790
17939
|
}
|
|
17791
17940
|
});
|
|
17792
|
-
|
|
17941
|
+
const evidence = opened.result || {};
|
|
17942
|
+
if (!opened.profile) {
|
|
17793
17943
|
st._ccLoginPromise = null;
|
|
17794
17944
|
st._ccLoginResolve = null;
|
|
17795
17945
|
st._ccLoginReject = null;
|
|
@@ -17802,10 +17952,29 @@ var require_oauth = __commonJS({
|
|
|
17802
17952
|
} catch {
|
|
17803
17953
|
}
|
|
17804
17954
|
st._ccLogin = null;
|
|
17805
|
-
return {
|
|
17955
|
+
return {
|
|
17956
|
+
ok: false,
|
|
17957
|
+
authUrl,
|
|
17958
|
+
url: authUrl,
|
|
17959
|
+
opened: false,
|
|
17960
|
+
confirmed: false,
|
|
17961
|
+
handedOff: false,
|
|
17962
|
+
reason: evidence.reason || "no-launcher",
|
|
17963
|
+
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
|
+
};
|
|
17806
17965
|
}
|
|
17807
|
-
st._ccLogin = { state, port, server, tmpProfile };
|
|
17808
|
-
return {
|
|
17966
|
+
st._ccLogin = { state, port, server, tmpProfile: opened.profile };
|
|
17967
|
+
return Object.assign({}, evidence, {
|
|
17968
|
+
ok: true,
|
|
17969
|
+
authUrl,
|
|
17970
|
+
url: authUrl,
|
|
17971
|
+
state,
|
|
17972
|
+
port,
|
|
17973
|
+
waitMs: 18e4,
|
|
17974
|
+
opened: true,
|
|
17975
|
+
// 非隔离引擎(Safari/snap 包装器)由平台层降级:账号隔离不成立,换账号只能靠超时重发或手动窗口。
|
|
17976
|
+
isolated: evidence.isolated === true
|
|
17977
|
+
});
|
|
17809
17978
|
}
|
|
17810
17979
|
async function commandcodeLoginWait(timeoutMs) {
|
|
17811
17980
|
const p = st._ccLoginPromise;
|
|
@@ -21545,6 +21714,9 @@ var require_market = __commonJS({
|
|
|
21545
21714
|
this._cache = null;
|
|
21546
21715
|
this._ts = 0;
|
|
21547
21716
|
this._inFlight = null;
|
|
21717
|
+
this._lastError = null;
|
|
21718
|
+
this._nextAllowAt = 0;
|
|
21719
|
+
this.retryBackoffMs = opts.retryBackoffMs || 6e4;
|
|
21548
21720
|
this.buildBudgetMs = opts.buildBudgetMs || 24e4;
|
|
21549
21721
|
this.loadFromDisk();
|
|
21550
21722
|
}
|
|
@@ -21558,38 +21730,51 @@ var require_market = __commonJS({
|
|
|
21558
21730
|
saveToDisk() {
|
|
21559
21731
|
marketCache.saveIndex(this.cacheDir, this.indexFile, this._cache, this.logger);
|
|
21560
21732
|
}
|
|
21561
|
-
/**
|
|
21562
|
-
|
|
21563
|
-
|
|
21564
|
-
|
|
21565
|
-
|
|
21566
|
-
|
|
21567
|
-
|
|
21568
|
-
|
|
21733
|
+
/** 索引快照,耗时上限必须是「读内存」:构建(默认预算 4 分钟)交 _requestBuild 在后台跑。
|
|
21734
|
+
* 挂到请求上等构建,面板 15s 计时会先放弃而服务端仍在跑 —— 用户见失败、结论却是好的。
|
|
21735
|
+
* 无缓存且上次构建刚失败时按 retryBackoffMs 退避,免得每次读都点燃一轮 4 分钟构建;force 不受退避约束。 */
|
|
21736
|
+
getIndex(force = false) {
|
|
21737
|
+
const need = !this._cache || force || Date.now() - this._ts >= this.ttl;
|
|
21738
|
+
if (need && (force || Date.now() >= this._nextAllowAt)) this._requestBuild();
|
|
21739
|
+
return Promise.resolve(this._view());
|
|
21740
|
+
}
|
|
21741
|
+
/** 快照视图(无缓存也返回合法空索引,绝不为取数据而触网)。 */
|
|
21742
|
+
_view() {
|
|
21743
|
+
const c = this._cache;
|
|
21744
|
+
return {
|
|
21745
|
+
ok: true,
|
|
21746
|
+
indexedAt: c ? c.indexedAt : 0,
|
|
21747
|
+
sources: c ? c.sources : { npm: 0, github: 0, community: 0 },
|
|
21748
|
+
total: c ? c.total : 0,
|
|
21749
|
+
plugins: c ? c.plugins : [],
|
|
21750
|
+
building: !!this._inFlight,
|
|
21751
|
+
error: this._lastError
|
|
21752
|
+
};
|
|
21569
21753
|
}
|
|
21570
|
-
/**
|
|
21571
|
-
* (a)
|
|
21572
|
-
* (b)
|
|
21573
|
-
*
|
|
21574
|
-
|
|
21754
|
+
/** 启动一次构建(无消费者 await)并登记为在飞引用;两条不变量:
|
|
21755
|
+
* (a) 无人等待的失败不得成为进程级 unhandledRejection —— 给 raw 挂 no-op handler「标记已处理」;
|
|
21756
|
+
* (b) 去重:已有在飞构建就直接复用,force 连点不得叠加并发构建(M-i)。
|
|
21757
|
+
* 失败原因记入 _lastError 并由快照如实上报 —— 取不到不能显示成「没有插件」。 */
|
|
21758
|
+
_requestBuild() {
|
|
21759
|
+
if (this._inFlight) return this._inFlight;
|
|
21575
21760
|
const raw = this.buildIndex();
|
|
21576
21761
|
raw.catch(() => {
|
|
21577
21762
|
});
|
|
21578
21763
|
this._inFlight = raw;
|
|
21579
|
-
raw.then(
|
|
21580
|
-
|
|
21581
|
-
|
|
21764
|
+
raw.then(
|
|
21765
|
+
() => {
|
|
21766
|
+
this._lastError = null;
|
|
21767
|
+
},
|
|
21768
|
+
(e) => {
|
|
21769
|
+
this._lastError = e && e.message || String(e);
|
|
21770
|
+
if (!this._cache) this._nextAllowAt = Date.now() + this.retryBackoffMs;
|
|
21771
|
+
this.logger.warn && this.logger.warn("market: \u7D22\u5F15\u6784\u5EFA\u5931\u8D25\uFF08\u6CBF\u7528\u65E7\u7F13\u5B58\uFF09: " + this._lastError);
|
|
21772
|
+
}
|
|
21773
|
+
).then(() => {
|
|
21582
21774
|
if (this._inFlight === raw) this._inFlight = null;
|
|
21583
21775
|
});
|
|
21584
21776
|
return raw;
|
|
21585
21777
|
}
|
|
21586
|
-
_refreshIfStale() {
|
|
21587
|
-
if (Date.now() - this._ts < this.ttl) return;
|
|
21588
|
-
if (this._inFlight) return;
|
|
21589
|
-
this._startBuild().catch((e) => {
|
|
21590
|
-
this.logger.warn && this.logger.warn("market: \u540E\u53F0\u5237\u65B0\u7D22\u5F15\u5931\u8D25\uFF08\u6CBF\u7528\u65E7\u7F13\u5B58\uFF09: " + (e && e.message || e));
|
|
21591
|
-
});
|
|
21592
|
-
}
|
|
21593
21778
|
async buildIndex() {
|
|
21594
21779
|
const start = Date.now();
|
|
21595
21780
|
const bctx = { deadline: start + this.buildBudgetMs, truncated: /* @__PURE__ */ new Set() };
|
|
@@ -22753,22 +22938,57 @@ var require_updater = __commonJS({
|
|
|
22753
22938
|
if (latest !== null) ctx._updCache[name] = { latest, at: Date.now() };
|
|
22754
22939
|
return { latest, error };
|
|
22755
22940
|
}
|
|
22756
|
-
|
|
22941
|
+
function checkUpdates(ctx, force) {
|
|
22942
|
+
if (!ctx._updSnapshot || force) _requestCheck(ctx, force);
|
|
22943
|
+
const s = ctx._updSnapshot;
|
|
22944
|
+
return Promise.resolve({
|
|
22945
|
+
ok: true,
|
|
22946
|
+
checkedAt: s ? s.checkedAt : 0,
|
|
22947
|
+
plugins: s ? s.plugins : [],
|
|
22948
|
+
refreshing: !!ctx._updInFlight,
|
|
22949
|
+
error: s ? s.error : null
|
|
22950
|
+
});
|
|
22951
|
+
}
|
|
22952
|
+
function _requestCheck(ctx, force) {
|
|
22953
|
+
if (ctx._updInFlight) return ctx._updInFlight;
|
|
22954
|
+
const raw = refreshUpdates(ctx, force);
|
|
22955
|
+
raw.catch(() => {
|
|
22956
|
+
});
|
|
22957
|
+
ctx._updInFlight = raw;
|
|
22958
|
+
raw.catch((e) => {
|
|
22959
|
+
const msg = e && e.message || String(e);
|
|
22960
|
+
if (ctx.logger && ctx.logger.warn) ctx.logger.warn("plugin check-updates \u5931\u8D25: " + msg);
|
|
22961
|
+
if (!ctx._updSnapshot) ctx._updSnapshot = { checkedAt: 0, plugins: [], error: msg };
|
|
22962
|
+
}).then(() => {
|
|
22963
|
+
if (ctx._updInFlight === raw) ctx._updInFlight = null;
|
|
22964
|
+
});
|
|
22965
|
+
return raw;
|
|
22966
|
+
}
|
|
22967
|
+
async function refreshUpdates(ctx, force) {
|
|
22757
22968
|
const targets = [ctx._nativeTarget(), ...ctx._allSandboxTargets()];
|
|
22758
22969
|
const meta = /* @__PURE__ */ new Map();
|
|
22759
22970
|
for (const t of targets) {
|
|
22760
22971
|
for (const p of ctx.installedOn(t)) {
|
|
22761
22972
|
if (meta.has(p.name)) continue;
|
|
22762
|
-
|
|
22763
|
-
let latest = null;
|
|
22764
|
-
if (st === "npm" && ctx.dist) latest = (await latestCached(ctx, p.name, force)).latest;
|
|
22765
|
-
meta.set(p.name, { specType: st, latest });
|
|
22973
|
+
meta.set(p.name, { specType: specType(p.source), latest: null, error: null });
|
|
22766
22974
|
}
|
|
22767
22975
|
}
|
|
22976
|
+
const npmNames = [...meta.entries()].filter(([, m]) => m.specType === "npm" && ctx.dist).map(([name]) => name);
|
|
22977
|
+
const errors = [];
|
|
22978
|
+
for (let i = 0; i < npmNames.length; i += 6) {
|
|
22979
|
+
const slice = npmNames.slice(i, i + 6);
|
|
22980
|
+
await Promise.all(slice.map(async (name) => {
|
|
22981
|
+
const r = await latestCached(ctx, name, force);
|
|
22982
|
+
const m = meta.get(name);
|
|
22983
|
+
m.latest = r.latest;
|
|
22984
|
+
m.error = r.error;
|
|
22985
|
+
if (r.error) errors.push(name + ": " + r.error);
|
|
22986
|
+
}));
|
|
22987
|
+
}
|
|
22768
22988
|
const rows = [];
|
|
22769
22989
|
for (const t of targets) {
|
|
22770
22990
|
for (const p of ctx.installedOn(t)) {
|
|
22771
|
-
const m = meta.get(p.name) || { specType: "npm", latest: null };
|
|
22991
|
+
const m = meta.get(p.name) || { specType: "npm", latest: null, error: null };
|
|
22772
22992
|
const updateAvailable = m.specType === "npm" && isUpdateAvailable(m.latest, p.version);
|
|
22773
22993
|
rows.push({ name: p.name, target: t.id, targetName: t.name, installed: p.version || null, latest: m.latest || null, updateAvailable, specType: m.specType, bundle: p.bundle });
|
|
22774
22994
|
}
|
|
@@ -22777,13 +22997,15 @@ var require_updater = __commonJS({
|
|
|
22777
22997
|
for (const row of rows) {
|
|
22778
22998
|
let rec = byName.get(row.name);
|
|
22779
22999
|
if (!rec) {
|
|
22780
|
-
byName.set(row.name, { name: row.name, specType: row.specType, targets: [] });
|
|
23000
|
+
byName.set(row.name, { name: row.name, specType: row.specType, error: meta.get(row.name) ? meta.get(row.name).error : null, targets: [] });
|
|
22781
23001
|
rec = byName.get(row.name);
|
|
22782
23002
|
}
|
|
22783
23003
|
rec.targets.push({ id: row.target, name: row.targetName, installed: row.installed, latest: row.latest, updateAvailable: row.updateAvailable });
|
|
22784
23004
|
}
|
|
22785
|
-
const plugins = [...byName.values()].map((x) => ({ name: x.name, specType: x.specType, updateAvailable: x.targets.some((t) => t.updateAvailable), targets: x.targets })).sort((a, b) => a.name.localeCompare(b.name));
|
|
22786
|
-
|
|
23005
|
+
const plugins = [...byName.values()].map((x) => ({ name: x.name, specType: x.specType, error: x.error, updateAvailable: x.targets.some((t) => t.updateAvailable), targets: x.targets })).sort((a, b) => a.name.localeCompare(b.name));
|
|
23006
|
+
const snap = { checkedAt: Date.now(), plugins, error: errors.length ? errors.join("; ") : null };
|
|
23007
|
+
ctx._updSnapshot = snap;
|
|
23008
|
+
return snap;
|
|
22787
23009
|
}
|
|
22788
23010
|
async function update(ctx, name, targetStr) {
|
|
22789
23011
|
if (!name) return { ok: false, error: "missing plugin name" };
|
|
@@ -22885,6 +23107,8 @@ var require_plugin = __commonJS({
|
|
|
22885
23107
|
this.tasks = opts.tasks || null;
|
|
22886
23108
|
this._updCache = {};
|
|
22887
23109
|
this._updTTL = 6 * 3600 * 1e3;
|
|
23110
|
+
this._updSnapshot = null;
|
|
23111
|
+
this._updInFlight = null;
|
|
22888
23112
|
this.jobs = createJobs({ tasks: this.tasks });
|
|
22889
23113
|
this.layers = createLayers({ overlayFile: this.overlayFile, logger: this.logger });
|
|
22890
23114
|
this.store = new store.PluginStore({ getInventory: () => this.inventory() });
|
|
@@ -25283,7 +25507,7 @@ var require_guard = __commonJS({
|
|
|
25283
25507
|
var fs2 = require("node:fs");
|
|
25284
25508
|
var path2 = require("node:path");
|
|
25285
25509
|
function owns(pathname) {
|
|
25286
|
-
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 === "/ports" || pathname === "/shutdown";
|
|
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";
|
|
25287
25511
|
}
|
|
25288
25512
|
function fetchDshChangelog(res, sup) {
|
|
25289
25513
|
const v = sup && sup.nativeManager ? sup.nativeManager.versionInfo() : {};
|
|
@@ -25295,7 +25519,7 @@ var require_guard = __commonJS({
|
|
|
25295
25519
|
return res.end(md);
|
|
25296
25520
|
}
|
|
25297
25521
|
function handle(ctx) {
|
|
25298
|
-
const { sup, req, res, pathname, send, collectBody, originAllowed } = ctx;
|
|
25522
|
+
const { sup, req, res, pathname, identity, send, collectBody, originAllowed, browser } = ctx;
|
|
25299
25523
|
if (req.method === "GET" && pathname === "/changelog") {
|
|
25300
25524
|
return fetchDshChangelog(res, sup);
|
|
25301
25525
|
}
|
|
@@ -25459,6 +25683,27 @@ var require_guard = __commonJS({
|
|
|
25459
25683
|
if (req.method === "GET" && pathname === "/env/node-lts") {
|
|
25460
25684
|
return sup.nodeLtsStatus().then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: e.message }));
|
|
25461
25685
|
}
|
|
25686
|
+
if (req.method === "POST" && pathname === "/env/open-url") {
|
|
25687
|
+
if (!identity.loopback) {
|
|
25688
|
+
req.resume();
|
|
25689
|
+
return send(403, { ok: false, error: "\u4EC5\u5185\u6838\u6240\u5728\u673A\u5668\u53EF\u8BF7\u5185\u6838\u8C03\u8D77\u6D4F\u89C8\u5668\uFF0C\u8BF7\u590D\u5236\u6216\u81EA\u884C\u6253\u5F00\u8BE5\u5730\u5740" });
|
|
25690
|
+
}
|
|
25691
|
+
if (!originAllowed(req, sup.config.apiPort)) {
|
|
25692
|
+
req.resume();
|
|
25693
|
+
return send(403, { ok: false, error: "cross-origin request rejected" });
|
|
25694
|
+
}
|
|
25695
|
+
collectBody(req, res, 4096, (body) => {
|
|
25696
|
+
let url = null;
|
|
25697
|
+
try {
|
|
25698
|
+
const j = body ? JSON.parse(body) : {};
|
|
25699
|
+
if (typeof j.url === "string") url = j.url;
|
|
25700
|
+
} catch {
|
|
25701
|
+
}
|
|
25702
|
+
if (!url) return send(400, { ok: false, error: '\u9700\u8981 {"url":"http(s)://\u2026"}' });
|
|
25703
|
+
return Promise.resolve(browser.openBrowser(url)).then((r) => send(r.ok ? 200 : 500, r)).catch((e) => send(500, { ok: false, reason: "spawn-failed", error: "\u6253\u5F00\u6D4F\u89C8\u5668\u5931\u8D25\uFF1A" + (e && e.message || e), url }));
|
|
25704
|
+
});
|
|
25705
|
+
return;
|
|
25706
|
+
}
|
|
25462
25707
|
if (req.method === "GET" && pathname === "/ports") {
|
|
25463
25708
|
return Promise.resolve(sup.listPorts()).then((r) => send(200, r)).catch((e) => send(500, { error: e && e.message }));
|
|
25464
25709
|
}
|
|
@@ -25953,7 +26198,6 @@ var require_exchange = __commonJS({
|
|
|
25953
26198
|
var require_instances = __commonJS({
|
|
25954
26199
|
"src/api/domains/instances.js"(exports2, module2) {
|
|
25955
26200
|
"use strict";
|
|
25956
|
-
var platform = require_os();
|
|
25957
26201
|
var execPath = require_exec_path();
|
|
25958
26202
|
var crypto = require("node:crypto");
|
|
25959
26203
|
var { bootstrapDshCookie } = require_exchange();
|
|
@@ -26055,17 +26299,18 @@ var require_instances = __commonJS({
|
|
|
26055
26299
|
return sharedErr + "\uFF1B" + FORMS + "\uFF1B\u9700\u8981\u5176\u5B83\u53EF\u6267\u884C\u8BF7\u8D70\u63D2\u4EF6\u5B89\u88C5\u901A\u9053";
|
|
26056
26300
|
}
|
|
26057
26301
|
function handle(ctx) {
|
|
26058
|
-
const { sup, req, res, pathname, identity, send, collectBody, originAllowed, tokOf } = ctx;
|
|
26302
|
+
const { sup, req, res, pathname, identity, send, collectBody, originAllowed, tokOf, browser } = ctx;
|
|
26059
26303
|
function openInSystemBrowser(url) {
|
|
26060
|
-
return
|
|
26304
|
+
return browser.openBrowser(url);
|
|
26061
26305
|
}
|
|
26062
26306
|
if (req.method === "GET" && pathname === "/open") return handleOpen(ctx);
|
|
26063
26307
|
if (req.method === "GET" && pathname === "/instances") {
|
|
26064
26308
|
const decorate = (it) => {
|
|
26065
26309
|
const tok = tokOf(it.id);
|
|
26066
26310
|
const out = Object.assign({}, it);
|
|
26067
|
-
delete out.remoteToken;
|
|
26068
26311
|
const loopback = identity.loopback;
|
|
26312
|
+
out.tokenSet = !!String(it.remoteToken || "").trim();
|
|
26313
|
+
if (!loopback) delete out.remoteToken;
|
|
26069
26314
|
out.authUrl = tok && loopback ? "http://127.0.0.1:" + it.port + "/?token=" + encodeURIComponent(tok) : "http://127.0.0.1:" + it.port + "/";
|
|
26070
26315
|
out.tokenPresent = loopback && !!tok;
|
|
26071
26316
|
return out;
|
|
@@ -26121,9 +26366,13 @@ var require_instances = __commonJS({
|
|
|
26121
26366
|
if (!(Number(it.port) > 0)) return send(400, { ok: false, error: "\u975E\u6CD5\u7AEF\u53E3" });
|
|
26122
26367
|
const code = issueOpenWebCode(j.id);
|
|
26123
26368
|
const url = "http://127.0.0.1:" + sup.config.apiPort + "/open?code=" + code;
|
|
26124
|
-
|
|
26125
|
-
|
|
26126
|
-
|
|
26369
|
+
return Promise.resolve(openInSystemBrowser(url)).then((r) => {
|
|
26370
|
+
if (!r.ok) dropOpenWebCode(code);
|
|
26371
|
+
return send(r.ok ? 200 : 500, r);
|
|
26372
|
+
}).catch((e) => {
|
|
26373
|
+
dropOpenWebCode(code);
|
|
26374
|
+
return send(500, { ok: false, reason: "spawn-failed", error: "\u6253\u5F00\u6D4F\u89C8\u5668\u5931\u8D25\uFF1A" + (e && e.message || e), url });
|
|
26375
|
+
});
|
|
26127
26376
|
} catch (e) {
|
|
26128
26377
|
return send(500, { ok: false, error: e.message });
|
|
26129
26378
|
}
|
|
@@ -26568,6 +26817,7 @@ var require_server = __commonJS({
|
|
|
26568
26817
|
var { serveStatic } = require_static();
|
|
26569
26818
|
var { identify } = require_identity3();
|
|
26570
26819
|
var { originAllowed, requestHasAccessKey, isShellOrigin } = require_security();
|
|
26820
|
+
var browserExit = require_browser();
|
|
26571
26821
|
function safeFail(res, err, where) {
|
|
26572
26822
|
try {
|
|
26573
26823
|
const body = JSON.stringify({ ok: false, error: err && err.message || String(err) });
|
|
@@ -26585,7 +26835,8 @@ var require_server = __commonJS({
|
|
|
26585
26835
|
} catch {
|
|
26586
26836
|
}
|
|
26587
26837
|
}
|
|
26588
|
-
function createServer(sup) {
|
|
26838
|
+
function createServer(sup, deps) {
|
|
26839
|
+
const browser = deps && deps.browser || browserExit;
|
|
26589
26840
|
return http2.createServer((req, res) => {
|
|
26590
26841
|
const shellOrigin = (() => {
|
|
26591
26842
|
const o = req.headers.origin;
|
|
@@ -26653,7 +26904,7 @@ var require_server = __commonJS({
|
|
|
26653
26904
|
} catch (e) {
|
|
26654
26905
|
return send(400, { error: "bad request encoding" });
|
|
26655
26906
|
}
|
|
26656
|
-
const ctx = { sup, req, res, pathname: decodedPathname, identity, send, collectBody, originAllowed, tokOf };
|
|
26907
|
+
const ctx = { sup, req, res, pathname: decodedPathname, identity, send, collectBody, originAllowed, tokOf, browser };
|
|
26657
26908
|
for (const d of API_DOMAINS) {
|
|
26658
26909
|
if (d.owns(pathname)) {
|
|
26659
26910
|
try {
|