dsh-mobile 0.2.2 → 0.3.0
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/CHANGELOG.md +11 -0
- package/README.en.md +8 -4
- package/README.md +14 -10
- package/assets/brand/app-icon-master.png +0 -0
- package/cordis.patch.yml +1 -1
- package/lib/client.js +436 -113
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +16 -3
- package/lib/index.mjs +619 -32
- package/package.json +8 -5
package/lib/client.js
CHANGED
|
@@ -76,6 +76,13 @@ window.__ModuleLoader__.load({
|
|
|
76
76
|
[data-dsh-mobile-settings-options] :is(input,select,textarea,button) { max-width:100%; }
|
|
77
77
|
[data-dsh-mobile-settings-options] :is(input,select,textarea) { box-sizing:border-box; width:100%; min-width:0; }
|
|
78
78
|
[data-dsh-mobile-settings-options] [class*="_head"] { min-width:0; flex-wrap:wrap; }
|
|
79
|
+
/* Provider names may shrink, but their edit/delete actions remain horizontal
|
|
80
|
+
and retain a full touch target on narrow screens. */
|
|
81
|
+
[data-dsh-mobile-settings-options] [class*="_rowHead"]:has(> [class*="_rowIdentity"]) { flex-wrap:nowrap !important; align-items:center !important; }
|
|
82
|
+
[data-dsh-mobile-settings-options] [class*="_rowIdentity"] { flex:1 1 auto !important; min-width:0 !important; overflow:hidden !important; }
|
|
83
|
+
[data-dsh-mobile-settings-options] [class*="_rowName"] { min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; }
|
|
84
|
+
[data-dsh-mobile-settings-options] [class*="_rowActions"] { flex:0 0 auto !important; flex-wrap:nowrap !important; width:max-content !important; min-width:max-content !important; max-width:none !important; }
|
|
85
|
+
[data-dsh-mobile-settings-options] [class*="_rowActions"] button { flex:none !important; width:auto !important; min-width:44px !important; max-width:none !important; min-height:44px !important; padding-inline:10px !important; white-space:nowrap !important; word-break:keep-all !important; writing-mode:horizontal-tb !important; }
|
|
79
86
|
[data-dsh-mobile-settings-content][data-dsh-mobile-view-transition="true"],
|
|
80
87
|
[data-dsh-mobile-view][data-dsh-mobile-view-transition="true"] { animation:dsh-mobile-view-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }
|
|
81
88
|
[data-dsh-mobile-center] textarea { font-size:16px !important; }
|
|
@@ -444,17 +451,38 @@ window.__ModuleLoader__.load({
|
|
|
444
451
|
if (className !== void 0) node.className = className;
|
|
445
452
|
return node;
|
|
446
453
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
454
|
+
const CONTROL_REQUEST_TIMEOUT_MS = 15e3;
|
|
455
|
+
const LONG_CONTROL_REQUEST_TIMEOUT_MS = 13e4;
|
|
456
|
+
async function requestJson(path, init, timeoutMs = CONTROL_REQUEST_TIMEOUT_MS) {
|
|
457
|
+
const controller = new AbortController();
|
|
458
|
+
const upstreamSignal = init?.signal;
|
|
459
|
+
const abortFromUpstream = () => {
|
|
460
|
+
controller.abort(upstreamSignal?.reason);
|
|
461
|
+
};
|
|
462
|
+
if (upstreamSignal?.aborted === true) abortFromUpstream();
|
|
463
|
+
else upstreamSignal?.addEventListener("abort", abortFromUpstream, { once: true });
|
|
464
|
+
const timer = window.setTimeout(() => {
|
|
465
|
+
controller.abort();
|
|
466
|
+
}, timeoutMs);
|
|
467
|
+
try {
|
|
468
|
+
const response = await fetch(path, {
|
|
469
|
+
...init,
|
|
470
|
+
signal: controller.signal,
|
|
471
|
+
headers: {
|
|
472
|
+
"content-type": "application/json",
|
|
473
|
+
...init?.headers
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
const body = await response.json();
|
|
477
|
+
if (!response.ok) throw new Error(typeof body.error === "string" ? body.error : `HTTP ${String(response.status)}`);
|
|
478
|
+
return body;
|
|
479
|
+
} catch (error) {
|
|
480
|
+
if (controller.signal.aborted && upstreamSignal?.aborted !== true) throw new Error("操作超时,请确认 DSH 仍在运行后重试。");
|
|
481
|
+
throw error;
|
|
482
|
+
} finally {
|
|
483
|
+
clearTimeout(timer);
|
|
484
|
+
upstreamSignal?.removeEventListener("abort", abortFromUpstream);
|
|
485
|
+
}
|
|
458
486
|
}
|
|
459
487
|
function officialFunnelSetupUrl(value) {
|
|
460
488
|
if (typeof value !== "string" || value.length > 2048) return "";
|
|
@@ -477,10 +505,17 @@ window.__ModuleLoader__.load({
|
|
|
477
505
|
const header = element("header", "dsh-mobile-control__header");
|
|
478
506
|
const title = element("h2");
|
|
479
507
|
title.textContent = "移动访问";
|
|
508
|
+
const headerActions = element("div", "dsh-mobile-control__header-actions");
|
|
509
|
+
const diagnosticsEntry = element("button", "dsh-mobile-control__diagnostic-entry");
|
|
510
|
+
diagnosticsEntry.type = "button";
|
|
511
|
+
diagnosticsEntry.textContent = "诊断";
|
|
512
|
+
diagnosticsEntry.setAttribute("aria-label", "打开连接诊断");
|
|
513
|
+
diagnosticsEntry.setAttribute("aria-pressed", "false");
|
|
480
514
|
const close = element("button", "dsh-mobile-control__close");
|
|
481
515
|
close.type = "button";
|
|
482
516
|
close.textContent = "×";
|
|
483
517
|
close.setAttribute("aria-label", "收起移动访问");
|
|
518
|
+
headerActions.append(diagnosticsEntry, close);
|
|
484
519
|
const appDownload = element("a", "dsh-mobile-control__app-download");
|
|
485
520
|
appDownload.href = "https://github.com/saya-ch/dsh-mobile/releases/latest";
|
|
486
521
|
appDownload.target = "_blank";
|
|
@@ -588,7 +623,7 @@ window.__ModuleLoader__.load({
|
|
|
588
623
|
cpolarChoiceDescription.textContent = "按需安装官方组件,适合国内网络环境。";
|
|
589
624
|
cpolarChoiceTop.append(cpolarChoiceName, cpolarChoiceBadge);
|
|
590
625
|
cpolarChoice.append(cpolarChoiceTop, cpolarChoiceDescription);
|
|
591
|
-
providerChoices.append(
|
|
626
|
+
providerChoices.append(cpolarChoice, tailscaleChoice);
|
|
592
627
|
providerSection.append(providerHeading, providerInfo, providerChoices);
|
|
593
628
|
const cpolarSetup = element("section", "dsh-mobile-control__cpolar-setup");
|
|
594
629
|
cpolarSetup.hidden = true;
|
|
@@ -728,11 +763,53 @@ window.__ModuleLoader__.load({
|
|
|
728
763
|
remoteManageRow.append(remoteDevices, remoteReset);
|
|
729
764
|
const remoteDevicePanel = element("div", "dsh-mobile-control__devices");
|
|
730
765
|
remoteDevicePanel.hidden = true;
|
|
731
|
-
|
|
766
|
+
const diagnosticsView = element("div", "dsh-mobile-control__view is-diagnostics");
|
|
767
|
+
diagnosticsView.hidden = true;
|
|
768
|
+
const diagnosticsIntro = element("p", "dsh-mobile-control__intro");
|
|
769
|
+
diagnosticsIntro.textContent = "检查版本、网关、网卡、防火墙和远程通道。报告自动脱敏,不读取对话或凭据。";
|
|
770
|
+
const diagnosticsSummary = element("section", "dsh-mobile-control__diagnostic-summary is-idle");
|
|
771
|
+
diagnosticsSummary.setAttribute("aria-live", "polite");
|
|
772
|
+
const diagnosticsSummaryMain = element("div", "dsh-mobile-control__diagnostic-summary-main");
|
|
773
|
+
const diagnosticsSummaryIcon = element("span", "dsh-mobile-control__diagnostic-summary-icon");
|
|
774
|
+
diagnosticsSummaryIcon.setAttribute("aria-hidden", "true");
|
|
775
|
+
const diagnosticsSummaryBody = element("div", "dsh-mobile-control__diagnostic-summary-body");
|
|
776
|
+
const diagnosticsSummaryTitle = element("strong");
|
|
777
|
+
diagnosticsSummaryTitle.textContent = "尚未检查";
|
|
778
|
+
const diagnosticsSummaryText = element("span");
|
|
779
|
+
diagnosticsSummaryText.textContent = "点击下方按钮开始。";
|
|
780
|
+
const diagnosticsSummaryMeta = element("span", "dsh-mobile-control__diagnostic-summary-meta");
|
|
781
|
+
diagnosticsSummaryMeta.textContent = "等待运行 · 仅收集连接状态";
|
|
782
|
+
diagnosticsSummaryBody.append(diagnosticsSummaryTitle, diagnosticsSummaryText);
|
|
783
|
+
diagnosticsSummaryMain.append(diagnosticsSummaryIcon, diagnosticsSummaryBody);
|
|
784
|
+
diagnosticsSummary.append(diagnosticsSummaryMain, diagnosticsSummaryMeta);
|
|
785
|
+
const diagnosticsToolbar = element("div", "dsh-mobile-control__diagnostic-toolbar");
|
|
786
|
+
const diagnosticsRun = element("button", "dsh-mobile-control__primary dsh-mobile-control__diagnostic-run");
|
|
787
|
+
diagnosticsRun.type = "button";
|
|
788
|
+
diagnosticsRun.textContent = "开始检查";
|
|
789
|
+
const diagnosticsCopy = element("button", "dsh-mobile-control__secondary dsh-mobile-control__diagnostic-copy");
|
|
790
|
+
diagnosticsCopy.type = "button";
|
|
791
|
+
diagnosticsCopy.textContent = "复制脱敏报告";
|
|
792
|
+
diagnosticsCopy.disabled = true;
|
|
793
|
+
diagnosticsCopy.hidden = true;
|
|
794
|
+
diagnosticsToolbar.append(diagnosticsRun, diagnosticsCopy);
|
|
795
|
+
const diagnosticsFeedback = element("p", "dsh-mobile-control__diagnostic-feedback");
|
|
796
|
+
diagnosticsFeedback.hidden = true;
|
|
797
|
+
diagnosticsFeedback.setAttribute("role", "status");
|
|
798
|
+
diagnosticsFeedback.setAttribute("aria-live", "polite");
|
|
799
|
+
const diagnosticsChecks = element("div", "dsh-mobile-control__diagnostic-checks");
|
|
800
|
+
diagnosticsChecks.hidden = true;
|
|
801
|
+
const diagnosticsDetails = element("details", "dsh-mobile-control__details dsh-mobile-control__diagnostic-details");
|
|
802
|
+
diagnosticsDetails.hidden = true;
|
|
803
|
+
const diagnosticsDetailsSummary = element("summary");
|
|
804
|
+
diagnosticsDetailsSummary.textContent = "高级诊断详情";
|
|
805
|
+
const diagnosticsReport = element("pre", "dsh-mobile-control__diagnostic-report");
|
|
806
|
+
diagnosticsDetails.append(diagnosticsDetailsSummary, diagnosticsReport);
|
|
807
|
+
header.append(title, headerActions);
|
|
732
808
|
actions.append(toggle, pair, linkPair);
|
|
733
809
|
lanView.append(access, qrBox, status, extensionStatus, actions, manageRow, devicePanel);
|
|
734
810
|
remoteView.append(remoteIntro, providerSection, cpolarSetup, tailscaleInfo, remoteAccess, remoteQr, remoteStatus, remoteGuide, remoteActions, remoteManageRow, remoteDevicePanel);
|
|
735
|
-
|
|
811
|
+
diagnosticsView.append(diagnosticsIntro, diagnosticsSummary, diagnosticsToolbar, diagnosticsFeedback, diagnosticsChecks, diagnosticsDetails);
|
|
812
|
+
panel.append(header, appDownload, switcher, lanView, remoteView, diagnosticsView);
|
|
736
813
|
root.append(panel);
|
|
737
814
|
document.body.append(root);
|
|
738
815
|
let running = false;
|
|
@@ -750,6 +827,9 @@ window.__ModuleLoader__.load({
|
|
|
750
827
|
let cpolarConfigured = false;
|
|
751
828
|
let providerInfoPinned = false;
|
|
752
829
|
let providerInfoHovered = false;
|
|
830
|
+
let previousAccessView = "lan";
|
|
831
|
+
let diagnosticsBusy = false;
|
|
832
|
+
let copiedDiagnosticReport = "";
|
|
753
833
|
const syncProviderInfo = () => {
|
|
754
834
|
const open = providerInfoPinned || providerInfoHovered || providerInfo.contains(document.activeElement);
|
|
755
835
|
providerInfoPopover.hidden = !open;
|
|
@@ -778,20 +858,27 @@ window.__ModuleLoader__.load({
|
|
|
778
858
|
providerInfoPopover.hidden = true;
|
|
779
859
|
providerInfoButton.setAttribute("aria-expanded", "false");
|
|
780
860
|
});
|
|
781
|
-
const selectView = (
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
lanTab.
|
|
787
|
-
remoteTab.
|
|
788
|
-
|
|
861
|
+
const selectView = (view) => {
|
|
862
|
+
if (view !== "diagnostics") previousAccessView = view;
|
|
863
|
+
lanView.hidden = view !== "lan";
|
|
864
|
+
remoteView.hidden = view !== "remote";
|
|
865
|
+
diagnosticsView.hidden = view !== "diagnostics";
|
|
866
|
+
lanTab.classList.toggle("is-active", view === "lan");
|
|
867
|
+
remoteTab.classList.toggle("is-active", view === "remote");
|
|
868
|
+
lanTab.setAttribute("aria-pressed", String(view === "lan"));
|
|
869
|
+
remoteTab.setAttribute("aria-pressed", String(view === "remote"));
|
|
870
|
+
diagnosticsEntry.setAttribute("aria-pressed", String(view === "diagnostics"));
|
|
871
|
+
diagnosticsEntry.textContent = view === "diagnostics" ? "返回" : "诊断";
|
|
872
|
+
diagnosticsEntry.setAttribute("aria-label", view === "diagnostics" ? "返回移动访问" : "打开连接诊断");
|
|
873
|
+
appDownload.hidden = view === "diagnostics";
|
|
874
|
+
switcher.hidden = view === "diagnostics";
|
|
875
|
+
title.textContent = view === "lan" ? "局域网访问" : view === "remote" ? "远程访问" : "连接诊断";
|
|
789
876
|
};
|
|
790
877
|
lanTab.addEventListener("click", () => {
|
|
791
|
-
selectView(
|
|
878
|
+
selectView("lan");
|
|
792
879
|
});
|
|
793
880
|
remoteTab.addEventListener("click", () => {
|
|
794
|
-
selectView(
|
|
881
|
+
selectView("remote");
|
|
795
882
|
loadRemote();
|
|
796
883
|
});
|
|
797
884
|
const setOpen = (open) => {
|
|
@@ -984,6 +1071,7 @@ window.__ModuleLoader__.load({
|
|
|
984
1071
|
funnel_permission_required: "登录已完成。请继续授权 Funnel,完成后会自动建立远程连接。",
|
|
985
1072
|
funnel_https_required: "登录已完成。请继续授权 Funnel,官方页面会同时启用 HTTPS。",
|
|
986
1073
|
funnel_start_failed: "登录已完成。请继续完成 Tailscale Funnel 的首次授权。",
|
|
1074
|
+
funnel_start_timeout: "Tailscale 组件启动超时,请检查网络后重新连接。",
|
|
987
1075
|
tailscale_dns_missing: "Tailscale 暂未提供远程地址。请重新连接并确认已完成登录。",
|
|
988
1076
|
gateway_start_failed: "远程网关启动失败。请重新连接,局域网访问不受影响。",
|
|
989
1077
|
control_channel_failed: "远程组件连接中断。请重新连接。",
|
|
@@ -1012,9 +1100,14 @@ window.__ModuleLoader__.load({
|
|
|
1012
1100
|
if (!remoteReady) remoteQr.hidden = true;
|
|
1013
1101
|
if (!needsFunnelSetup) remoteSetupPending = false;
|
|
1014
1102
|
};
|
|
1103
|
+
let remoteLoadInFlight = false;
|
|
1015
1104
|
const loadRemote = () => {
|
|
1105
|
+
if (remoteLoadInFlight) return;
|
|
1106
|
+
remoteLoadInFlight = true;
|
|
1016
1107
|
requestJson("/api/mobile-access/remote/control").then(renderRemote, (error) => {
|
|
1017
1108
|
remoteStatus.textContent = String(error);
|
|
1109
|
+
}).finally(() => {
|
|
1110
|
+
remoteLoadInFlight = false;
|
|
1018
1111
|
});
|
|
1019
1112
|
};
|
|
1020
1113
|
const chooseRemoteProvider = (provider) => {
|
|
@@ -1050,7 +1143,7 @@ window.__ModuleLoader__.load({
|
|
|
1050
1143
|
requestJson("/api/mobile-access/remote/cpolar/component/install", {
|
|
1051
1144
|
method: "POST",
|
|
1052
1145
|
body: JSON.stringify({ confirm: true })
|
|
1053
|
-
}).then(renderRemote, (error) => {
|
|
1146
|
+
}, LONG_CONTROL_REQUEST_TIMEOUT_MS).then(renderRemote, (error) => {
|
|
1054
1147
|
remoteStatus.textContent = `组件安装失败:${String(error)}`;
|
|
1055
1148
|
}).finally(() => {
|
|
1056
1149
|
remoteProviderBusy = false;
|
|
@@ -1072,7 +1165,7 @@ window.__ModuleLoader__.load({
|
|
|
1072
1165
|
requestJson("/api/mobile-access/remote/cpolar/configure", {
|
|
1073
1166
|
method: "POST",
|
|
1074
1167
|
body: JSON.stringify({ authtoken })
|
|
1075
|
-
}).then(() => {
|
|
1168
|
+
}, LONG_CONTROL_REQUEST_TIMEOUT_MS).then(() => {
|
|
1076
1169
|
cpolarToken.value = "";
|
|
1077
1170
|
remoteStatus.textContent = "账号配置已保存,正在建立 cpolar 远程通道…";
|
|
1078
1171
|
return requestJson("/api/mobile-access/remote/control", {
|
|
@@ -1097,7 +1190,7 @@ window.__ModuleLoader__.load({
|
|
|
1097
1190
|
requestJson("/api/mobile-access/remote/cpolar/component/purge", {
|
|
1098
1191
|
method: "POST",
|
|
1099
1192
|
body: JSON.stringify({ confirm: true })
|
|
1100
|
-
}).then(renderRemote, (error) => {
|
|
1193
|
+
}, LONG_CONTROL_REQUEST_TIMEOUT_MS).then(renderRemote, (error) => {
|
|
1101
1194
|
remoteStatus.textContent = `清理失败:${String(error)}`;
|
|
1102
1195
|
}).finally(() => {
|
|
1103
1196
|
remoteProviderBusy = false;
|
|
@@ -1224,6 +1317,120 @@ window.__ModuleLoader__.load({
|
|
|
1224
1317
|
remoteStatus.textContent = String(error);
|
|
1225
1318
|
});
|
|
1226
1319
|
});
|
|
1320
|
+
const renderDiagnostics = (data) => {
|
|
1321
|
+
const overall = data.overall === "error" ? "error" : data.overall === "attention" ? "attention" : "ok";
|
|
1322
|
+
diagnosticsSummary.className = `dsh-mobile-control__diagnostic-summary is-${overall}`;
|
|
1323
|
+
diagnosticsSummaryTitle.textContent = overall === "ok" ? "检查完成" : overall === "attention" ? "有项目需要留意" : "发现连接问题";
|
|
1324
|
+
diagnosticsSummaryText.textContent = typeof data.summary === "string" ? data.summary : "检查已完成。";
|
|
1325
|
+
const entries = Array.isArray(data.checks) ? data.checks : [];
|
|
1326
|
+
diagnosticsChecks.replaceChildren();
|
|
1327
|
+
const statusLabels = {
|
|
1328
|
+
ok: "正常",
|
|
1329
|
+
warning: "注意",
|
|
1330
|
+
error: "问题",
|
|
1331
|
+
info: "说明"
|
|
1332
|
+
};
|
|
1333
|
+
const statusOf = (entry) => entry.status === "ok" || entry.status === "warning" || entry.status === "error" ? entry.status : "info";
|
|
1334
|
+
const appendGroup = (label, groupEntries) => {
|
|
1335
|
+
if (groupEntries.length === 0) return;
|
|
1336
|
+
const group = element("section", "dsh-mobile-control__diagnostic-group");
|
|
1337
|
+
const groupHeader = element("header", "dsh-mobile-control__diagnostic-group-header");
|
|
1338
|
+
const groupTitle = element("h3");
|
|
1339
|
+
groupTitle.textContent = label;
|
|
1340
|
+
const groupCount = element("span");
|
|
1341
|
+
groupCount.textContent = `${String(groupEntries.length)} 项`;
|
|
1342
|
+
const list = element("div", "dsh-mobile-control__diagnostic-list");
|
|
1343
|
+
list.setAttribute("role", "list");
|
|
1344
|
+
groupHeader.append(groupTitle, groupCount);
|
|
1345
|
+
for (const entry of groupEntries) {
|
|
1346
|
+
const state = statusOf(entry);
|
|
1347
|
+
const row = element("section", `dsh-mobile-control__diagnostic-check is-${state}`);
|
|
1348
|
+
row.setAttribute("role", "listitem");
|
|
1349
|
+
const marker = element("span", "dsh-mobile-control__diagnostic-marker");
|
|
1350
|
+
marker.setAttribute("aria-hidden", "true");
|
|
1351
|
+
const rowBody = element("div", "dsh-mobile-control__diagnostic-check-body");
|
|
1352
|
+
const rowHeader = element("div", "dsh-mobile-control__diagnostic-check-header");
|
|
1353
|
+
const rowTitle = element("strong");
|
|
1354
|
+
rowTitle.textContent = typeof entry.label === "string" ? entry.label : "检查项";
|
|
1355
|
+
const badge = element("span", "dsh-mobile-control__diagnostic-badge");
|
|
1356
|
+
badge.textContent = statusLabels[state];
|
|
1357
|
+
const detail = element("p");
|
|
1358
|
+
detail.textContent = typeof entry.detail === "string" ? entry.detail : "";
|
|
1359
|
+
rowHeader.append(rowTitle, badge);
|
|
1360
|
+
rowBody.append(rowHeader, detail);
|
|
1361
|
+
if (typeof entry.action === "string" && entry.action !== "") {
|
|
1362
|
+
const action = element("p", "dsh-mobile-control__diagnostic-action");
|
|
1363
|
+
const actionLabel = element("span");
|
|
1364
|
+
actionLabel.textContent = "建议";
|
|
1365
|
+
action.append(actionLabel, document.createTextNode(entry.action));
|
|
1366
|
+
rowBody.append(action);
|
|
1367
|
+
}
|
|
1368
|
+
row.append(marker, rowBody);
|
|
1369
|
+
list.append(row);
|
|
1370
|
+
}
|
|
1371
|
+
group.append(groupHeader, list);
|
|
1372
|
+
diagnosticsChecks.append(group);
|
|
1373
|
+
};
|
|
1374
|
+
const issues = entries.filter((entry) => statusOf(entry) === "error" || statusOf(entry) === "warning");
|
|
1375
|
+
const otherChecks = entries.filter((entry) => statusOf(entry) !== "error" && statusOf(entry) !== "warning");
|
|
1376
|
+
appendGroup("需要处理", issues);
|
|
1377
|
+
appendGroup(issues.length === 0 ? "检查详情" : "其他检查", otherChecks);
|
|
1378
|
+
diagnosticsSummaryMeta.textContent = issues.length === 0 ? `${String(entries.length)} 项检查 · 未发现阻断问题` : `${String(entries.length)} 项检查 · ${String(issues.length)} 项需要处理`;
|
|
1379
|
+
diagnosticsChecks.hidden = entries.length === 0;
|
|
1380
|
+
copiedDiagnosticReport = typeof data.report === "string" ? data.report : "";
|
|
1381
|
+
diagnosticsReport.textContent = copiedDiagnosticReport;
|
|
1382
|
+
diagnosticsDetails.hidden = copiedDiagnosticReport === "";
|
|
1383
|
+
diagnosticsCopy.disabled = copiedDiagnosticReport === "";
|
|
1384
|
+
diagnosticsCopy.hidden = copiedDiagnosticReport === "";
|
|
1385
|
+
diagnosticsToolbar.classList.toggle("has-report", copiedDiagnosticReport !== "");
|
|
1386
|
+
};
|
|
1387
|
+
const loadDiagnostics = () => {
|
|
1388
|
+
if (diagnosticsBusy) return;
|
|
1389
|
+
diagnosticsBusy = true;
|
|
1390
|
+
diagnosticsRun.disabled = true;
|
|
1391
|
+
diagnosticsRun.setAttribute("aria-busy", "true");
|
|
1392
|
+
diagnosticsRun.textContent = "正在检查…";
|
|
1393
|
+
diagnosticsSummary.className = "dsh-mobile-control__diagnostic-summary is-running";
|
|
1394
|
+
diagnosticsSummaryTitle.textContent = "正在检查连接";
|
|
1395
|
+
diagnosticsSummaryText.textContent = "通常几秒内完成。远程通道会执行一次真实可达性测试。";
|
|
1396
|
+
diagnosticsSummaryMeta.textContent = "正在运行 · 请保持 DSH 在线";
|
|
1397
|
+
diagnosticsFeedback.hidden = true;
|
|
1398
|
+
diagnosticsChecks.classList.add("is-refreshing");
|
|
1399
|
+
diagnosticsChecks.setAttribute("aria-busy", "true");
|
|
1400
|
+
requestJson("/api/mobile-access/diagnostics").then(renderDiagnostics, (error) => {
|
|
1401
|
+
diagnosticsSummary.className = "dsh-mobile-control__diagnostic-summary is-error";
|
|
1402
|
+
diagnosticsSummaryTitle.textContent = "检查未完成";
|
|
1403
|
+
diagnosticsSummaryText.textContent = `无法读取诊断结果:${String(error)}`;
|
|
1404
|
+
diagnosticsSummaryMeta.textContent = "诊断服务暂不可用 · 请稍后重试";
|
|
1405
|
+
}).finally(() => {
|
|
1406
|
+
diagnosticsBusy = false;
|
|
1407
|
+
diagnosticsRun.disabled = false;
|
|
1408
|
+
diagnosticsRun.setAttribute("aria-busy", "false");
|
|
1409
|
+
diagnosticsRun.textContent = "重新检查";
|
|
1410
|
+
diagnosticsChecks.classList.remove("is-refreshing");
|
|
1411
|
+
diagnosticsChecks.setAttribute("aria-busy", "false");
|
|
1412
|
+
});
|
|
1413
|
+
};
|
|
1414
|
+
diagnosticsEntry.addEventListener("click", () => {
|
|
1415
|
+
if (!diagnosticsView.hidden) {
|
|
1416
|
+
selectView(previousAccessView);
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
selectView("diagnostics");
|
|
1420
|
+
loadDiagnostics();
|
|
1421
|
+
});
|
|
1422
|
+
diagnosticsRun.addEventListener("click", loadDiagnostics);
|
|
1423
|
+
diagnosticsCopy.addEventListener("click", () => {
|
|
1424
|
+
if (copiedDiagnosticReport === "") return;
|
|
1425
|
+
navigator.clipboard.writeText(copiedDiagnosticReport).then(() => {
|
|
1426
|
+
diagnosticsFeedback.textContent = "脱敏报告已复制,可直接粘贴到 Issue。";
|
|
1427
|
+
diagnosticsFeedback.hidden = false;
|
|
1428
|
+
}, () => {
|
|
1429
|
+
diagnosticsDetails.open = true;
|
|
1430
|
+
diagnosticsFeedback.textContent = "浏览器未允许复制,已展开详情,请手动复制。";
|
|
1431
|
+
diagnosticsFeedback.hidden = false;
|
|
1432
|
+
});
|
|
1433
|
+
});
|
|
1227
1434
|
pair.addEventListener("click", () => {
|
|
1228
1435
|
pair.disabled = true;
|
|
1229
1436
|
openPairing("key");
|
|
@@ -1296,6 +1503,9 @@ window.__ModuleLoader__.load({
|
|
|
1296
1503
|
const styleNodes = /* @__PURE__ */ new Map();
|
|
1297
1504
|
const styleEtags = /* @__PURE__ */ new Map();
|
|
1298
1505
|
const scriptDigests = /* @__PURE__ */ new Map();
|
|
1506
|
+
const manifestExtensionIds = /* @__PURE__ */ new Set();
|
|
1507
|
+
const managedDefinitionIds = /* @__PURE__ */ new Set();
|
|
1508
|
+
const activationQueues = /* @__PURE__ */ new Map();
|
|
1299
1509
|
let manifestEtag = "";
|
|
1300
1510
|
let expectedDefinitionId;
|
|
1301
1511
|
const SURFACE_HOST_STYLES = {
|
|
@@ -1435,7 +1645,7 @@ window.__ModuleLoader__.load({
|
|
|
1435
1645
|
window
|
|
1436
1646
|
};
|
|
1437
1647
|
};
|
|
1438
|
-
const
|
|
1648
|
+
const activateDefinitionNow = async (definition) => {
|
|
1439
1649
|
const previousActive = active.get(definition.id);
|
|
1440
1650
|
const controller = new AbortController();
|
|
1441
1651
|
const surfaces = /* @__PURE__ */ new Map();
|
|
@@ -1453,7 +1663,7 @@ window.__ModuleLoader__.load({
|
|
|
1453
1663
|
const current = active.get(definition.id);
|
|
1454
1664
|
if (current === void 0 || current.controller !== controller) {
|
|
1455
1665
|
if (typeof cleanup === "function") cleanup();
|
|
1456
|
-
return;
|
|
1666
|
+
return false;
|
|
1457
1667
|
}
|
|
1458
1668
|
const oldDispose = current.dispose;
|
|
1459
1669
|
active.set(definition.id, {
|
|
@@ -1464,17 +1674,30 @@ window.__ModuleLoader__.load({
|
|
|
1464
1674
|
}
|
|
1465
1675
|
});
|
|
1466
1676
|
previousActive?.dispose();
|
|
1677
|
+
return true;
|
|
1467
1678
|
} catch {
|
|
1468
|
-
active.get(definition.id)
|
|
1469
|
-
|
|
1470
|
-
|
|
1679
|
+
const current = active.get(definition.id);
|
|
1680
|
+
if (current?.controller === controller) {
|
|
1681
|
+
current.dispose();
|
|
1682
|
+
active.delete(definition.id);
|
|
1683
|
+
if (previousActive !== void 0) active.set(definition.id, previousActive);
|
|
1684
|
+
}
|
|
1685
|
+
return false;
|
|
1471
1686
|
}
|
|
1472
1687
|
};
|
|
1688
|
+
const activateDefinition = (definition) => {
|
|
1689
|
+
const task = (activationQueues.get(definition.id) ?? Promise.resolve(true)).then(() => definitions.get(definition.id) === definition ? activateDefinitionNow(definition) : false, () => definitions.get(definition.id) === definition ? activateDefinitionNow(definition) : false);
|
|
1690
|
+
activationQueues.set(definition.id, task);
|
|
1691
|
+
task.finally(() => {
|
|
1692
|
+
if (activationQueues.get(definition.id) === task) activationQueues.delete(definition.id);
|
|
1693
|
+
});
|
|
1694
|
+
return task;
|
|
1695
|
+
};
|
|
1473
1696
|
const define = (definition) => {
|
|
1474
1697
|
if (definition.apiVersion !== 1 || !/^[a-z][a-z0-9-]{0,63}$/u.test(definition.id) || typeof definition.activate !== "function") return;
|
|
1475
1698
|
if (expectedDefinitionId !== void 0 && definition.id !== expectedDefinitionId) return;
|
|
1476
1699
|
definitions.set(definition.id, definition);
|
|
1477
|
-
if (started) activateDefinition(definition);
|
|
1700
|
+
if (started && expectedDefinitionId === void 0) activateDefinition(definition);
|
|
1478
1701
|
};
|
|
1479
1702
|
let started = false;
|
|
1480
1703
|
window.dshMobile = Object.freeze({
|
|
@@ -1486,7 +1709,9 @@ window.__ModuleLoader__.load({
|
|
|
1486
1709
|
for (const definition of queuedDefinitions.splice(0)) define(definition);
|
|
1487
1710
|
let legacyJsEtag = "";
|
|
1488
1711
|
let legacyJsModified = "";
|
|
1489
|
-
const refreshLegacy = async () => {
|
|
1712
|
+
const refreshLegacy = async (signal) => {
|
|
1713
|
+
const previousMount = legacyMount;
|
|
1714
|
+
let pendingRoot;
|
|
1490
1715
|
try {
|
|
1491
1716
|
const headers = {};
|
|
1492
1717
|
if (legacyJsEtag !== "") headers["if-none-match"] = legacyJsEtag;
|
|
@@ -1494,23 +1719,27 @@ window.__ModuleLoader__.load({
|
|
|
1494
1719
|
const response = await fetch("/mobile-access/custom.js", {
|
|
1495
1720
|
credentials: "same-origin",
|
|
1496
1721
|
cache: "no-store",
|
|
1497
|
-
headers
|
|
1722
|
+
headers,
|
|
1723
|
+
...signal === void 0 ? {} : { signal }
|
|
1498
1724
|
});
|
|
1499
|
-
if (response.status === 304) return;
|
|
1500
|
-
if (!response.ok) return;
|
|
1725
|
+
if (response.status === 304) return true;
|
|
1726
|
+
if (!response.ok) return false;
|
|
1501
1727
|
legacyJsEtag = response.headers.get("etag") ?? "";
|
|
1502
1728
|
legacyJsModified = response.headers.get("last-modified") ?? "";
|
|
1503
1729
|
const next = await response.text();
|
|
1504
|
-
if (next === legacySource) return;
|
|
1505
|
-
legacySource = next;
|
|
1730
|
+
if (next === legacySource) return true;
|
|
1506
1731
|
legacyMount = void 0;
|
|
1507
1732
|
const script = element("script");
|
|
1508
1733
|
script.textContent = `${next}\n//# sourceURL=dsh-mobile-custom.js`;
|
|
1509
1734
|
document.head.append(script);
|
|
1510
1735
|
script.remove();
|
|
1511
1736
|
const mount = legacyMount;
|
|
1512
|
-
if (mount === void 0)
|
|
1737
|
+
if (mount === void 0) {
|
|
1738
|
+
legacySource = next;
|
|
1739
|
+
return true;
|
|
1740
|
+
}
|
|
1513
1741
|
const nextRoot = element("div");
|
|
1742
|
+
pendingRoot = nextRoot;
|
|
1514
1743
|
nextRoot.dataset.dshMobileExtension = "true";
|
|
1515
1744
|
document.body.append(nextRoot);
|
|
1516
1745
|
const nextDispose = mount({
|
|
@@ -1522,105 +1751,188 @@ window.__ModuleLoader__.load({
|
|
|
1522
1751
|
legacyDispose?.();
|
|
1523
1752
|
legacyRoot?.remove();
|
|
1524
1753
|
legacyRoot = nextRoot;
|
|
1754
|
+
pendingRoot = void 0;
|
|
1525
1755
|
legacyDispose = typeof nextDispose === "function" ? nextDispose : void 0;
|
|
1526
|
-
|
|
1756
|
+
legacySource = next;
|
|
1757
|
+
return true;
|
|
1758
|
+
} catch {
|
|
1759
|
+
pendingRoot?.remove();
|
|
1760
|
+
legacyMount = previousMount;
|
|
1761
|
+
return false;
|
|
1762
|
+
}
|
|
1527
1763
|
};
|
|
1528
|
-
|
|
1764
|
+
let legacyScriptRevision = "";
|
|
1765
|
+
let legacyStyleRevision = "";
|
|
1766
|
+
const refreshExtensions = async (signal) => {
|
|
1529
1767
|
try {
|
|
1530
1768
|
const headers = {};
|
|
1531
1769
|
if (manifestEtag !== "") headers["if-none-match"] = manifestEtag;
|
|
1532
1770
|
const response = await fetch("/mobile-access/extensions/manifest", {
|
|
1533
1771
|
credentials: "same-origin",
|
|
1534
1772
|
cache: "no-store",
|
|
1535
|
-
headers
|
|
1773
|
+
headers,
|
|
1774
|
+
...signal === void 0 ? {} : { signal }
|
|
1536
1775
|
});
|
|
1537
|
-
if (response.status ===
|
|
1538
|
-
if (
|
|
1539
|
-
|
|
1776
|
+
if (response.status === 404) return (await Promise.all([refreshLegacy(signal), refreshCssLegacy(legacyStyle, signal)])).every(Boolean);
|
|
1777
|
+
if (response.status === 304) return true;
|
|
1778
|
+
if (!response.ok) return false;
|
|
1779
|
+
const nextManifestEtag = response.headers.get("etag") ?? "";
|
|
1540
1780
|
const payload = await response.json();
|
|
1781
|
+
const scriptRevision = typeof payload.legacy?.scriptRevision === "string" ? payload.legacy.scriptRevision : "";
|
|
1782
|
+
const styleRevision = typeof payload.legacy?.styleRevision === "string" ? payload.legacy.styleRevision : "";
|
|
1783
|
+
let refreshComplete = true;
|
|
1784
|
+
if (scriptRevision === "" || scriptRevision !== legacyScriptRevision) {
|
|
1785
|
+
if (await refreshLegacy(signal)) legacyScriptRevision = scriptRevision;
|
|
1786
|
+
else refreshComplete = false;
|
|
1787
|
+
}
|
|
1788
|
+
if (styleRevision === "" || styleRevision !== legacyStyleRevision) {
|
|
1789
|
+
if (await refreshCssLegacy(legacyStyle, signal)) legacyStyleRevision = styleRevision;
|
|
1790
|
+
else refreshComplete = false;
|
|
1791
|
+
}
|
|
1541
1792
|
const entries = Array.isArray(payload.extensions) ? payload.extensions : [];
|
|
1542
1793
|
const seen = /* @__PURE__ */ new Set();
|
|
1543
1794
|
for (const entry of entries) {
|
|
1544
1795
|
if (typeof entry.id !== "string") continue;
|
|
1545
1796
|
seen.add(entry.id);
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
const
|
|
1550
|
-
if (
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1797
|
+
try {
|
|
1798
|
+
let pendingCss;
|
|
1799
|
+
let pendingStyleEtag;
|
|
1800
|
+
const cssUrl = typeof entry.styleUrl === "string" ? entry.styleUrl : void 0;
|
|
1801
|
+
if (cssUrl !== void 0) {
|
|
1802
|
+
const cssHeaders = {};
|
|
1803
|
+
const storedEtag = styleEtags.get(entry.id);
|
|
1804
|
+
if (storedEtag !== void 0) cssHeaders["if-none-match"] = storedEtag;
|
|
1805
|
+
const cssResponse = await fetch(cssUrl, {
|
|
1806
|
+
credentials: "same-origin",
|
|
1807
|
+
cache: "no-store",
|
|
1808
|
+
headers: cssHeaders,
|
|
1809
|
+
...signal === void 0 ? {} : { signal }
|
|
1810
|
+
});
|
|
1811
|
+
if (cssResponse.status !== 304) {
|
|
1812
|
+
if (!cssResponse.ok) throw new Error("mobile extension style failed to load");
|
|
1813
|
+
pendingStyleEtag = cssResponse.headers.get("etag") ?? void 0;
|
|
1814
|
+
pendingCss = await cssResponse.text();
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
const scriptUrl = typeof entry.scriptUrl === "string" ? entry.scriptUrl : void 0;
|
|
1818
|
+
if (scriptUrl !== void 0) {
|
|
1819
|
+
const scriptHeaders = {};
|
|
1820
|
+
const storedDigest = scriptDigests.get(entry.id);
|
|
1821
|
+
if (storedDigest !== void 0) scriptHeaders["if-none-match"] = storedDigest;
|
|
1822
|
+
const scriptResponse = await fetch(scriptUrl, {
|
|
1823
|
+
credentials: "same-origin",
|
|
1824
|
+
cache: "no-store",
|
|
1825
|
+
headers: scriptHeaders,
|
|
1826
|
+
...signal === void 0 ? {} : { signal }
|
|
1827
|
+
});
|
|
1828
|
+
if (scriptResponse.status !== 304) {
|
|
1829
|
+
if (!scriptResponse.ok) throw new Error("mobile extension script failed to load");
|
|
1830
|
+
const source = await scriptResponse.text();
|
|
1831
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(source));
|
|
1832
|
+
const key = [...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
1833
|
+
if (scriptDigests.get(entry.id) !== key) {
|
|
1834
|
+
const previousDefinition = definitions.get(entry.id);
|
|
1835
|
+
try {
|
|
1836
|
+
expectedDefinitionId = entry.id;
|
|
1837
|
+
try {
|
|
1838
|
+
const script = element("script");
|
|
1839
|
+
script.textContent = `${source}\n//# sourceURL=dsh-mobile-extension-${entry.id}.js`;
|
|
1840
|
+
document.head.append(script);
|
|
1841
|
+
script.remove();
|
|
1842
|
+
} finally {
|
|
1843
|
+
expectedDefinitionId = void 0;
|
|
1844
|
+
}
|
|
1845
|
+
const nextDefinition = definitions.get(entry.id);
|
|
1846
|
+
if (nextDefinition === void 0 || nextDefinition === previousDefinition) throw new Error("mobile extension did not define its manifest id");
|
|
1847
|
+
if (!await activateDefinition(nextDefinition)) throw new Error("mobile extension activation failed");
|
|
1848
|
+
managedDefinitionIds.add(entry.id);
|
|
1849
|
+
scriptDigests.set(entry.id, key);
|
|
1850
|
+
} catch (error) {
|
|
1851
|
+
if (previousDefinition === void 0) definitions.delete(entry.id);
|
|
1852
|
+
else definitions.set(entry.id, previousDefinition);
|
|
1853
|
+
throw error;
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
const definition = definitions.get(entry.id);
|
|
1858
|
+
if (definition !== void 0 && !active.has(entry.id) && !await activateDefinition(definition)) throw new Error("mobile extension activation failed");
|
|
1859
|
+
}
|
|
1860
|
+
if (pendingCss !== void 0) {
|
|
1560
1861
|
const oldStyle = styleNodes.get(entry.id);
|
|
1561
|
-
if (oldStyle?.textContent !==
|
|
1862
|
+
if (oldStyle?.textContent !== pendingCss) {
|
|
1562
1863
|
const node = element("style");
|
|
1563
1864
|
node.dataset.dshMobileExtensionStyle = entry.id;
|
|
1564
|
-
node.textContent =
|
|
1865
|
+
node.textContent = pendingCss;
|
|
1565
1866
|
document.head.append(node);
|
|
1566
1867
|
styleNodes.set(entry.id, node);
|
|
1567
1868
|
oldStyle?.remove();
|
|
1568
1869
|
}
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
const scriptHeaders = {};
|
|
1574
|
-
const storedDigest = scriptDigests.get(entry.id);
|
|
1575
|
-
if (storedDigest !== void 0) scriptHeaders["if-none-match"] = storedDigest;
|
|
1576
|
-
const scriptResponse = await fetch(scriptUrl, {
|
|
1577
|
-
credentials: "same-origin",
|
|
1578
|
-
cache: "no-store",
|
|
1579
|
-
headers: scriptHeaders
|
|
1580
|
-
});
|
|
1581
|
-
if (scriptResponse.status === 304) {} else if (scriptResponse.ok) {
|
|
1582
|
-
const source = await scriptResponse.text();
|
|
1583
|
-
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(source));
|
|
1584
|
-
const key = [...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
1585
|
-
if (scriptDigests.get(entry.id) !== key) {
|
|
1586
|
-
scriptDigests.set(entry.id, key);
|
|
1587
|
-
expectedDefinitionId = entry.id;
|
|
1588
|
-
try {
|
|
1589
|
-
const script = element("script");
|
|
1590
|
-
script.textContent = `${source}\n//# sourceURL=dsh-mobile-extension-${entry.id}.js`;
|
|
1591
|
-
document.head.append(script);
|
|
1592
|
-
script.remove();
|
|
1593
|
-
} finally {
|
|
1594
|
-
expectedDefinitionId = void 0;
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
} else continue;
|
|
1870
|
+
if (pendingStyleEtag !== void 0 && pendingStyleEtag !== "") styleEtags.set(entry.id, pendingStyleEtag);
|
|
1871
|
+
}
|
|
1872
|
+
} catch {
|
|
1873
|
+
refreshComplete = false;
|
|
1598
1874
|
}
|
|
1599
|
-
const definition = definitions.get(entry.id);
|
|
1600
|
-
if (definition !== void 0 && !active.has(entry.id)) await activateDefinition(definition);
|
|
1601
1875
|
}
|
|
1602
|
-
for (const
|
|
1603
|
-
|
|
1876
|
+
for (const id of manifestExtensionIds) {
|
|
1877
|
+
if (seen.has(id)) continue;
|
|
1878
|
+
active.get(id)?.dispose();
|
|
1604
1879
|
active.delete(id);
|
|
1605
1880
|
styleNodes.get(id)?.remove();
|
|
1606
1881
|
styleNodes.delete(id);
|
|
1607
1882
|
styleEtags.delete(id);
|
|
1608
1883
|
scriptDigests.delete(id);
|
|
1884
|
+
if (managedDefinitionIds.delete(id)) definitions.delete(id);
|
|
1609
1885
|
}
|
|
1610
|
-
|
|
1886
|
+
manifestExtensionIds.clear();
|
|
1887
|
+
for (const id of seen) manifestExtensionIds.add(id);
|
|
1888
|
+
manifestEtag = refreshComplete ? nextManifestEtag : "";
|
|
1889
|
+
return refreshComplete;
|
|
1890
|
+
} catch {
|
|
1891
|
+
return false;
|
|
1892
|
+
}
|
|
1611
1893
|
};
|
|
1612
1894
|
started = true;
|
|
1613
1895
|
for (const definition of definitions.values()) activateDefinition(definition);
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1896
|
+
const remoteOrigin = window.location.hostname.endsWith(".ts.net") || window.location.hostname.includes(".cpolar.");
|
|
1897
|
+
const refreshIntervalMs = remoteOrigin ? 15e3 : 3e3;
|
|
1898
|
+
const refreshTimeoutMs = remoteOrigin ? 2e4 : 8e3;
|
|
1899
|
+
let stopped = false;
|
|
1900
|
+
let refreshTimer;
|
|
1901
|
+
let refreshFailures = 0;
|
|
1902
|
+
let refreshController;
|
|
1903
|
+
const scheduleRefresh = (delayMs) => {
|
|
1904
|
+
if (stopped || document.visibilityState === "hidden" || !navigator.onLine) return;
|
|
1905
|
+
if (refreshTimer !== void 0) clearTimeout(refreshTimer);
|
|
1906
|
+
refreshTimer = window.setTimeout(runRefresh, delayMs);
|
|
1907
|
+
};
|
|
1908
|
+
const runRefresh = () => {
|
|
1909
|
+
if (stopped || refreshController !== void 0) return;
|
|
1910
|
+
refreshController = new AbortController();
|
|
1911
|
+
const controller = refreshController;
|
|
1912
|
+
const timeout = window.setTimeout(() => {
|
|
1913
|
+
controller.abort();
|
|
1914
|
+
}, refreshTimeoutMs);
|
|
1915
|
+
refreshExtensions(controller.signal).then((success) => {
|
|
1916
|
+
refreshFailures = success ? 0 : refreshFailures + 1;
|
|
1917
|
+
}).finally(() => {
|
|
1918
|
+
clearTimeout(timeout);
|
|
1919
|
+
if (refreshController === controller) refreshController = void 0;
|
|
1920
|
+
const backoff = Math.min(6e4, refreshIntervalMs * 2 ** Math.min(refreshFailures, 3));
|
|
1921
|
+
scheduleRefresh(backoff);
|
|
1922
|
+
});
|
|
1923
|
+
};
|
|
1924
|
+
const resumeRefresh = () => {
|
|
1925
|
+
if (document.visibilityState !== "hidden" && navigator.onLine) scheduleRefresh(0);
|
|
1926
|
+
};
|
|
1927
|
+
document.addEventListener("visibilitychange", resumeRefresh);
|
|
1928
|
+
window.addEventListener("online", resumeRefresh);
|
|
1929
|
+
scheduleRefresh(0);
|
|
1622
1930
|
return () => {
|
|
1623
|
-
|
|
1931
|
+
stopped = true;
|
|
1932
|
+
if (refreshTimer !== void 0) clearTimeout(refreshTimer);
|
|
1933
|
+
refreshController?.abort();
|
|
1934
|
+
document.removeEventListener("visibilitychange", resumeRefresh);
|
|
1935
|
+
window.removeEventListener("online", resumeRefresh);
|
|
1624
1936
|
started = false;
|
|
1625
1937
|
legacyDispose?.();
|
|
1626
1938
|
legacyRoot?.remove();
|
|
@@ -1635,7 +1947,7 @@ window.__ModuleLoader__.load({
|
|
|
1635
1947
|
}
|
|
1636
1948
|
let cssEtag = "";
|
|
1637
1949
|
let cssModified = "";
|
|
1638
|
-
async function refreshCssLegacy(style) {
|
|
1950
|
+
async function refreshCssLegacy(style, signal) {
|
|
1639
1951
|
try {
|
|
1640
1952
|
const headers = {};
|
|
1641
1953
|
if (cssEtag !== "") headers["if-none-match"] = cssEtag;
|
|
@@ -1643,33 +1955,44 @@ window.__ModuleLoader__.load({
|
|
|
1643
1955
|
const response = await fetch("/mobile-access/custom.css", {
|
|
1644
1956
|
credentials: "same-origin",
|
|
1645
1957
|
cache: "no-store",
|
|
1646
|
-
headers
|
|
1958
|
+
headers,
|
|
1959
|
+
...signal === void 0 ? {} : { signal }
|
|
1647
1960
|
});
|
|
1648
|
-
if (response.status === 304) return;
|
|
1961
|
+
if (response.status === 304) return true;
|
|
1649
1962
|
if (response.ok) {
|
|
1650
1963
|
cssEtag = response.headers.get("etag") ?? "";
|
|
1651
1964
|
cssModified = response.headers.get("last-modified") ?? "";
|
|
1652
1965
|
style.textContent = await response.text();
|
|
1966
|
+
return true;
|
|
1653
1967
|
}
|
|
1654
|
-
|
|
1968
|
+
return false;
|
|
1969
|
+
} catch {
|
|
1970
|
+
return false;
|
|
1971
|
+
}
|
|
1655
1972
|
}
|
|
1656
1973
|
const CONTROL_STYLES = `
|
|
1657
1974
|
.dsh-mobile-control{position:fixed;z-index:1000;left:16px;bottom:112px;font:14px/1.45 system-ui;color:var(--dsw-alias-label-primary,#16181d)}
|
|
1658
1975
|
.dsh-mobile-control__panel{box-sizing:border-box;width:min(380px,calc(100vw - 32px));max-height:calc(100vh - 140px);overflow-y:auto;padding:16px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:18px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 18px 50px rgb(15 23 42 / 18%)}
|
|
1659
|
-
.dsh-mobile-control__header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.dsh-mobile-control__panel h2{margin:0;font-size:17px;line-height:24px}.dsh-mobile-control__close{display:inline-flex;align-items:center;justify-content:center;width:
|
|
1660
|
-
.dsh-mobile-control__app-download{display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;min-height:38px;margin:0 0 10px;padding:8px 11px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f7f8fa);color:var(--dsw-alias-label-primary,#16181d);font:600 12px/1.3 system-ui;text-decoration:none}.dsh-mobile-control__app-download::after{color:#2563eb;font-size:14px;content:"↗"}.dsh-mobile-control__app-download:hover{border-color:#9fb9e8;background:#f5f8ff;color:#1d4ed8}
|
|
1661
|
-
.dsh-mobile-control__switcher{display:grid;grid-template-columns:1fr
|
|
1976
|
+
.dsh-mobile-control__header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.dsh-mobile-control__panel h2{margin:0;font-size:17px;line-height:24px}.dsh-mobile-control__header-actions{display:flex;align-items:center;gap:2px}.dsh-mobile-control__diagnostic-entry,.dsh-mobile-control__close{display:inline-flex;align-items:center;justify-content:center;min-width:44px;height:44px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;cursor:pointer}.dsh-mobile-control__diagnostic-entry{padding:0 9px;color:#2563eb;font:650 12px/1 system-ui}.dsh-mobile-control__close{font-size:24px;line-height:1}.dsh-mobile-control__diagnostic-entry:hover,.dsh-mobile-control__close:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}
|
|
1977
|
+
.dsh-mobile-control__app-download{display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;min-height:38px;margin:0 0 10px;padding:8px 11px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f7f8fa);color:var(--dsw-alias-label-primary,#16181d);font:600 12px/1.3 system-ui;text-decoration:none}.dsh-mobile-control__app-download[hidden]{display:none}.dsh-mobile-control__app-download::after{color:#2563eb;font-size:14px;content:"↗"}.dsh-mobile-control__app-download:hover{border-color:#9fb9e8;background:#f5f8ff;color:#1d4ed8}
|
|
1978
|
+
.dsh-mobile-control__switcher{display:grid;grid-template-columns:repeat(2,1fr);gap:4px;margin:0 0 14px;padding:4px;border-radius:12px;background:var(--dsw-alias-bg-layer-1,#f3f5f8)}.dsh-mobile-control__switcher[hidden]{display:none}.dsh-mobile-control__tab{min-height:36px;border:0;border-radius:9px;background:transparent;color:var(--dsw-alias-label-secondary,#606873);font:600 13px/1 system-ui;cursor:pointer}.dsh-mobile-control__tab.is-active{background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);box-shadow:0 1px 3px rgb(15 23 42 / 10%)}.dsh-mobile-control__view[hidden]{display:none}.dsh-mobile-control__intro{margin:0 0 12px;color:var(--dsw-alias-label-secondary,#606873);font-size:12px;line-height:1.55}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions button[hidden]{display:none}
|
|
1662
1979
|
.dsh-mobile-control__provider-section{position:relative;margin:0 0 12px}.dsh-mobile-control__section-title{margin:0 0 8px;color:var(--dsw-alias-label-primary,#16181d);font:650 13px/1.4 system-ui}.dsh-mobile-control__provider-section>.dsh-mobile-control__section-title{padding-right:42px}.dsh-mobile-control__provider-choices{display:grid;gap:8px}.dsh-mobile-control__provider{display:flex;flex-direction:column;gap:5px;min-height:68px;padding:11px 12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:#fff;color:inherit;text-align:left;cursor:pointer;transition:border-color 160ms ease,background-color 160ms ease,box-shadow 160ms ease}.dsh-mobile-control__provider:hover{border-color:#9fb9e8;background:#f8fbff}.dsh-mobile-control__provider.is-selected{border-color:#2563eb;background:#f5f8ff;box-shadow:0 0 0 1px #2563eb inset}.dsh-mobile-control__provider:disabled{cursor:wait;opacity:.62}.dsh-mobile-control__provider-top{display:flex;align-items:center;justify-content:space-between;gap:8px}.dsh-mobile-control__provider-top strong{font-size:13px}.dsh-mobile-control__provider-badge{flex:none;padding:3px 7px;border-radius:999px;background:#e8f0ff;color:#1d4ed8;font:650 10px/1.2 system-ui}.dsh-mobile-control__provider-badge.is-cpolar{background:#eaf8f2;color:#087454}.dsh-mobile-control__provider-description{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.45}.dsh-mobile-control__provider-info{position:absolute;z-index:5;top:-13px;right:-8px}.dsh-mobile-control__provider-info-button{display:flex;align-items:center;justify-content:center;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:transparent;color:#475569;cursor:pointer;touch-action:manipulation}.dsh-mobile-control__provider-info-button:hover{background:#f1f5f9;color:#1d4ed8}.dsh-mobile-control__provider-info-glyph{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:18px;height:18px;border:1.5px solid currentColor;border-radius:50%;font:700 12px/1 system-ui}.dsh-mobile-control__provider-info-popover{position:absolute;z-index:6;top:38px;right:4px;box-sizing:border-box;width:min(292px,calc(100vw - 72px));padding:10px 12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 10px 28px rgb(15 23 42 / 16%)}.dsh-mobile-control__provider-info-popover[hidden]{display:none}.dsh-mobile-control__provider-info-popover strong,.dsh-mobile-control__provider-info-popover span{display:block}.dsh-mobile-control__provider-info-popover strong{margin-bottom:3px;font-size:12px}.dsh-mobile-control__provider-info-popover span{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}
|
|
1663
1980
|
.dsh-mobile-control__cpolar-setup{margin:0 0 12px;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:#fff}.dsh-mobile-control__cpolar-setup[hidden],.dsh-mobile-control__cpolar-account[hidden],.dsh-mobile-control__details[hidden],.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions[hidden],.dsh-mobile-control__danger[hidden]{display:none}.dsh-mobile-control__component-status,.dsh-mobile-control__component-note{margin:0 0 10px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__primary{width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:600 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__cpolar-account{margin-top:10px}.dsh-mobile-control__link-row{display:flex;flex-wrap:wrap;gap:6px 12px;margin:0 0 10px}.dsh-mobile-control__text-link{color:#2563eb;font-size:11px;text-decoration:none}.dsh-mobile-control__text-link:hover{text-decoration:underline}.dsh-mobile-control__token-label{display:flex;flex-direction:column;gap:5px;margin:0 0 8px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__token{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:#fff;color:inherit;font:16px/1.4 system-ui}.dsh-mobile-control__cpolar-connect{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:100%;min-height:44px;padding:10px 14px;border-radius:12px;font:650 13px/1.2 system-ui;cursor:pointer;transition:background-color 160ms ease,border-color 160ms ease,opacity 160ms ease}.dsh-mobile-control__cpolar-connect:hover:not(:disabled){border-color:#1d4ed8;background:#1d4ed8}.dsh-mobile-control__cpolar-connect:active:not(:disabled){border-color:#1e40af;background:#1e40af}.dsh-mobile-control__cpolar-connect:disabled{cursor:wait;opacity:.55}.dsh-mobile-control__details{margin:10px 0 0;border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb);padding-top:9px}.dsh-mobile-control__details>summary{min-height:30px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:30px;cursor:pointer}.dsh-mobile-control__details-body{display:flex;flex-wrap:wrap;align-items:center;gap:7px 12px;padding:4px 0}.dsh-mobile-control__details-body p{flex:1 0 100%;margin:0;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__storage{display:block;flex:1 0 100%;max-width:100%;overflow:hidden;padding:7px 8px;border-radius:8px;background:#f3f5f8;color:#475569;font:10px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__danger{flex:1 0 100%;min-height:38px;margin-top:3px;padding:7px 10px;border:1px solid #dc2626;border-radius:9px;background:transparent;color:#b91c1c;font:12px/1.3 system-ui;cursor:pointer}
|
|
1664
1981
|
.dsh-mobile-control__access{display:flex;align-items:baseline;gap:6px;min-width:0;margin:0 0 12px}.dsh-mobile-control__access[hidden]{display:none}.dsh-mobile-control__access-label{flex:none;color:var(--dsw-alias-label-secondary,#606873);white-space:nowrap}.dsh-mobile-control__access-label::after{content:":"}.dsh-mobile-control__access-link{min-width:0;overflow:hidden;color:#2563eb;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__access-link:hover{text-decoration:underline}.dsh-mobile-control__qr{display:flex;justify-content:center;margin:0 0 12px}.dsh-mobile-control__qr[hidden]{display:none}.dsh-mobile-control__qr img{border-radius:12px;background:#fff;padding:8px}
|
|
1665
1982
|
.dsh-mobile-control__status{margin:0 0 14px;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,#606873)}.dsh-mobile-control__status::before{display:inline-block;width:8px;height:8px;margin-right:7px;border-radius:50%;background:#98a1ad;content:""}.dsh-mobile-control__status.is-running::before{background:#16a36a}.dsh-mobile-control__status.is-key{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;word-break:break-all}
|
|
1666
1983
|
.dsh-mobile-control__guide{margin:0 0 14px;padding:12px;border:1px solid #bfdbfe;border-radius:12px;background:#eff6ff}.dsh-mobile-control__guide[hidden]{display:none}.dsh-mobile-control__guide-title{margin:0;color:#172554;font:650 13px/1.45 system-ui}.dsh-mobile-control__guide-summary,.dsh-mobile-control__guide-note{margin:4px 0 0;color:#475569;font-size:12px;line-height:1.5}.dsh-mobile-control__guide-steps{margin:8px 0 0;padding-left:20px;color:#1e293b;font-size:12px;line-height:1.6}.dsh-mobile-control__guide-note{color:#64748b}.dsh-mobile-control__guide-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px}.dsh-mobile-control__guide-actions button{min-width:0;min-height:44px;padding:8px;border-radius:10px;font:12px/1.25 system-ui;cursor:pointer}.dsh-mobile-control__guide-actions button:disabled{cursor:not-allowed;opacity:.45}
|
|
1667
1984
|
.dsh-mobile-control__extensions{margin:0 0 12px;color:var(--dsw-alias-label-secondary,#606873);font-size:12px}
|
|
1985
|
+
.dsh-mobile-control__view.is-diagnostics{--dsh-diagnostic-ok:#087454;--dsh-diagnostic-warning:#a35b00;--dsh-diagnostic-error:#c62828;--dsh-diagnostic-info:#526071}.dsh-mobile-control__diagnostic-summary{box-sizing:border-box;margin:0;padding:13px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:16px;background:var(--dsw-alias-bg-layer-1,#f8fafc)}.dsh-mobile-control__diagnostic-summary-main{display:grid;grid-template-columns:36px minmax(0,1fr);align-items:center;gap:11px}.dsh-mobile-control__diagnostic-summary-icon{position:relative;display:block;width:36px;height:36px;border-radius:50%;background:#e8edf3;color:var(--dsh-diagnostic-info)}.dsh-mobile-control__diagnostic-summary-icon::before,.dsh-mobile-control__diagnostic-summary-icon::after{position:absolute;content:""}.dsh-mobile-control__diagnostic-summary-body{display:flex;min-width:0;flex-direction:column;gap:2px}.dsh-mobile-control__diagnostic-summary-body strong{font-size:13px;line-height:1.35}.dsh-mobile-control__diagnostic-summary-body span{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__diagnostic-summary-meta{display:block;margin-top:11px;padding-top:9px;border-top:1px solid var(--dsw-alias-border-subtle,#dbe1e8);color:var(--dsw-alias-label-secondary,#606873);font-size:10px;line-height:1.45}.dsh-mobile-control__diagnostic-summary.is-ok .dsh-mobile-control__diagnostic-summary-icon{background:#e6f7f0;color:var(--dsh-diagnostic-ok)}.dsh-mobile-control__diagnostic-summary.is-ok .dsh-mobile-control__diagnostic-summary-icon::before{top:10px;left:10px;width:13px;height:7px;border-bottom:2px solid currentColor;border-left:2px solid currentColor;transform:rotate(-45deg)}.dsh-mobile-control__diagnostic-summary.is-attention .dsh-mobile-control__diagnostic-summary-icon{background:#fff4dc;color:var(--dsh-diagnostic-warning)}.dsh-mobile-control__diagnostic-summary.is-error .dsh-mobile-control__diagnostic-summary-icon{background:#fdecec;color:var(--dsh-diagnostic-error)}.dsh-mobile-control__diagnostic-summary.is-attention .dsh-mobile-control__diagnostic-summary-icon::before,.dsh-mobile-control__diagnostic-summary.is-error .dsh-mobile-control__diagnostic-summary-icon::before{top:8px;left:17px;width:2px;height:13px;border-radius:2px;background:currentColor}.dsh-mobile-control__diagnostic-summary.is-attention .dsh-mobile-control__diagnostic-summary-icon::after,.dsh-mobile-control__diagnostic-summary.is-error .dsh-mobile-control__diagnostic-summary-icon::after{bottom:8px;left:17px;width:2px;height:2px;border-radius:50%;background:currentColor}.dsh-mobile-control__diagnostic-summary.is-running .dsh-mobile-control__diagnostic-summary-icon{background:#e8f0ff;color:#2563eb}.dsh-mobile-control__diagnostic-summary.is-running .dsh-mobile-control__diagnostic-summary-icon::before{inset:9px;border:2px solid rgb(37 99 235 / 24%);border-top-color:currentColor;border-radius:50%;animation:dsh-diagnostic-spin .8s linear infinite}
|
|
1986
|
+
.dsh-mobile-control__diagnostic-summary.is-idle .dsh-mobile-control__diagnostic-summary-icon::before{top:8px;left:17px;width:2px;height:2px;border-radius:50%;background:currentColor}.dsh-mobile-control__diagnostic-summary.is-idle .dsh-mobile-control__diagnostic-summary-icon::after{top:13px;left:17px;width:2px;height:11px;border-radius:2px;background:currentColor}
|
|
1987
|
+
.dsh-mobile-control__diagnostic-toolbar{display:grid;grid-template-columns:1fr;gap:8px;margin-top:10px}.dsh-mobile-control__diagnostic-toolbar.has-report{grid-template-columns:1fr 1fr}.dsh-mobile-control__diagnostic-run,.dsh-mobile-control__diagnostic-copy{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border-radius:11px;font:650 12px/1.3 system-ui;cursor:pointer;touch-action:manipulation}.dsh-mobile-control__diagnostic-copy[hidden]{display:none}.dsh-mobile-control__diagnostic-run:disabled{cursor:wait;opacity:.58}.dsh-mobile-control__diagnostic-feedback{margin:8px 0 0;padding:8px 10px;border-radius:9px;background:#eff6ff;color:#1d4ed8;font-size:11px;line-height:1.45}.dsh-mobile-control__diagnostic-feedback[hidden]{display:none}
|
|
1988
|
+
.dsh-mobile-control__diagnostic-checks{display:grid;gap:12px;margin-top:12px;animation:dsh-diagnostic-reveal 160ms ease-out both}.dsh-mobile-control__diagnostic-checks[hidden]{display:none}.dsh-mobile-control__diagnostic-group{overflow:hidden;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__diagnostic-group-header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 11px;border-bottom:1px solid var(--dsw-alias-border-subtle,#e1e5eb);background:var(--dsw-alias-bg-layer-1,#f8fafc)}.dsh-mobile-control__diagnostic-group-header h3{margin:0;font:650 11px/1.4 system-ui}.dsh-mobile-control__diagnostic-group-header span{color:var(--dsw-alias-label-secondary,#606873);font-size:10px}.dsh-mobile-control__diagnostic-list{display:flex;flex-direction:column}.dsh-mobile-control__diagnostic-check{display:grid;grid-template-columns:26px minmax(0,1fr);gap:9px;padding:11px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__diagnostic-check + .dsh-mobile-control__diagnostic-check{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__diagnostic-marker{position:relative;width:26px;height:26px;border-radius:50%;background:#edf1f5;color:var(--dsh-diagnostic-info)}.dsh-mobile-control__diagnostic-marker::before,.dsh-mobile-control__diagnostic-marker::after{position:absolute;content:""}.dsh-mobile-control__diagnostic-check.is-ok .dsh-mobile-control__diagnostic-marker{background:#e6f7f0;color:var(--dsh-diagnostic-ok)}.dsh-mobile-control__diagnostic-check.is-ok .dsh-mobile-control__diagnostic-marker::before{top:7px;left:7px;width:9px;height:5px;border-bottom:1.8px solid currentColor;border-left:1.8px solid currentColor;transform:rotate(-45deg)}.dsh-mobile-control__diagnostic-check.is-warning .dsh-mobile-control__diagnostic-marker{background:#fff4dc;color:var(--dsh-diagnostic-warning)}.dsh-mobile-control__diagnostic-check.is-error .dsh-mobile-control__diagnostic-marker{background:#fdecec;color:var(--dsh-diagnostic-error)}.dsh-mobile-control__diagnostic-check.is-warning .dsh-mobile-control__diagnostic-marker::before,.dsh-mobile-control__diagnostic-check.is-error .dsh-mobile-control__diagnostic-marker::before{top:6px;left:12px;width:2px;height:9px;border-radius:2px;background:currentColor}.dsh-mobile-control__diagnostic-check.is-warning .dsh-mobile-control__diagnostic-marker::after,.dsh-mobile-control__diagnostic-check.is-error .dsh-mobile-control__diagnostic-marker::after{bottom:6px;left:12px;width:2px;height:2px;border-radius:50%;background:currentColor}.dsh-mobile-control__diagnostic-check.is-info .dsh-mobile-control__diagnostic-marker::before{top:6px;left:12px;width:2px;height:2px;border-radius:50%;background:currentColor}.dsh-mobile-control__diagnostic-check.is-info .dsh-mobile-control__diagnostic-marker::after{top:10px;left:12px;width:2px;height:9px;border-radius:2px;background:currentColor}.dsh-mobile-control__diagnostic-check-body{min-width:0}.dsh-mobile-control__diagnostic-check-header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.dsh-mobile-control__diagnostic-check-header strong{min-width:0;font-size:12px;line-height:1.4}.dsh-mobile-control__diagnostic-badge{flex:none;padding:2px 6px;border-radius:999px;background:#edf1f5;color:var(--dsh-diagnostic-info);font:650 10px/1.3 system-ui}.dsh-mobile-control__diagnostic-check.is-ok .dsh-mobile-control__diagnostic-badge{background:#e6f7f0;color:var(--dsh-diagnostic-ok)}.dsh-mobile-control__diagnostic-check.is-warning .dsh-mobile-control__diagnostic-badge{background:#fff4dc;color:var(--dsh-diagnostic-warning)}.dsh-mobile-control__diagnostic-check.is-error .dsh-mobile-control__diagnostic-badge{background:#fdecec;color:var(--dsh-diagnostic-error)}.dsh-mobile-control__diagnostic-check p{margin:4px 0 0;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5;overflow-wrap:anywhere}.dsh-mobile-control__diagnostic-check .dsh-mobile-control__diagnostic-action{margin-top:7px;padding:7px 8px;border-radius:8px;background:var(--dsw-alias-bg-layer-1,#f8fafc);color:var(--dsw-alias-label-primary,#16181d)}.dsh-mobile-control__diagnostic-action span{display:inline-block;margin-right:6px;color:#2563eb;font-weight:700}.dsh-mobile-control__diagnostic-details{margin-top:12px}.dsh-mobile-control__diagnostic-details[hidden]{display:none}.dsh-mobile-control__diagnostic-details>summary{box-sizing:border-box;min-height:44px;line-height:44px}.dsh-mobile-control__diagnostic-report{box-sizing:border-box;max-height:220px;margin:4px 0 0;overflow:auto;padding:10px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:10px;background:var(--dsw-alias-bg-layer-1,#f3f5f8);color:var(--dsw-alias-label-secondary,#606873);font:10px/1.55 ui-monospace,SFMono-Regular,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}
|
|
1989
|
+
.dsh-mobile-control__diagnostic-checks{transition:opacity 150ms ease}.dsh-mobile-control__diagnostic-checks.is-refreshing{opacity:.52}
|
|
1990
|
+
@keyframes dsh-diagnostic-spin{to{transform:rotate(360deg)}}@keyframes dsh-diagnostic-reveal{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}
|
|
1668
1991
|
.dsh-mobile-control__actions{display:flex;flex-wrap:nowrap;gap:6px}.dsh-mobile-control__actions button{flex:1 1 0;min-width:0;min-height:40px;padding:8px 4px;border-radius:10px;font:12px/1.2 system-ui;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dsh-mobile-control__secondary{border:1px solid var(--dsw-alias-border-normal,#cfd5dd);background:transparent;color:inherit}.dsh-mobile-control__primary{border:1px solid #2563eb;background:#2563eb;color:#fff}.dsh-mobile-control__actions button:disabled{cursor:not-allowed;opacity:.45}
|
|
1669
1992
|
.dsh-mobile-control button:focus-visible,.dsh-mobile-control a:focus-visible,.dsh-mobile-control input:focus-visible,.dsh-mobile-control summary:focus-visible{outline:3px solid rgb(37 99 235 / 28%);outline-offset:2px}
|
|
1670
1993
|
.dsh-mobile-control__trigger{box-sizing:border-box;display:flex;align-items:center;gap:8px;width:calc(100% + 8px);height:34px;margin:4px -4px;padding:6px 2px 6px 10px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#16181d);font:14px/22px system-ui;cursor:pointer}.dsh-mobile-control__trigger:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}.dsh-mobile-control__trigger.is-rail{width:36px;height:36px;margin:8px 0 10px;padding:0;justify-content:center;border-radius:50%}.dsh-mobile-control__trigger-icon{position:relative;box-sizing:border-box;flex:none;width:14px;height:19px;border:1.7px solid currentColor;border-radius:3px}.dsh-mobile-control__trigger-icon::after{position:absolute;right:4px;bottom:2px;width:4px;height:1.5px;border-radius:2px;background:currentColor;content:""}.dsh-mobile-control__trigger-label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
|
|
1671
1994
|
.dsh-mobile-control__manage-row{display:flex;justify-content:space-between;gap:8px;margin-top:10px}.dsh-mobile-control__manage{flex:1 1 0;min-width:0;min-height:34px;padding:6px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:transparent;color:inherit;font:12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__devices{margin-top:10px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:10px;padding:8px;max-height:220px;overflow-y:auto}.dsh-mobile-control__device-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px;margin:0}.dsh-mobile-control__device{display:flex;align-items:center;gap:8px;padding:6px 2px}.dsh-mobile-control__device + .dsh-mobile-control__device{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__device-label{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.dsh-mobile-control__device-meta{flex:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;white-space:nowrap}.dsh-mobile-control__device-revoke{flex:none;min-height:28px;padding:4px 8px;border:1px solid #dc2626;border-radius:8px;background:transparent;color:#dc2626;font:12px/1.2 system-ui;cursor:pointer}
|
|
1672
|
-
@media (prefers-reduced-motion:reduce){.dsh-mobile-control__provider,.dsh-mobile-control__cpolar-connect{transition:none}}
|
|
1995
|
+
@media (prefers-reduced-motion:reduce){.dsh-mobile-control__provider,.dsh-mobile-control__cpolar-connect{transition:none}.dsh-mobile-control__diagnostic-summary.is-running .dsh-mobile-control__diagnostic-summary-icon::before,.dsh-mobile-control__diagnostic-checks{animation:none}}
|
|
1673
1996
|
`;
|
|
1674
1997
|
/** Mount the desktop control or mobile feature enhancements. */
|
|
1675
1998
|
function apply(ctx) {
|