dsh-mobile 0.8.0 → 0.8.1

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/lib/client.js CHANGED
@@ -803,7 +803,22 @@ window.__ModuleLoader__.load({
803
803
  lanSetupConfiguring: "Creating private certificates and local network rules…",
804
804
  lanSetupRequired: "Local network setup has not been completed. Choose a network above to continue.",
805
805
  lanSetupRestart: "Setup complete for {origin}. Restart DSH once to start local network access.",
806
- lanSetupFailed: "Setup was not completed. Confirm the network selection and approve the Windows prompt, then try again."
806
+ lanSetupFailed: "Setup was not completed. Confirm the network selection and approve the Windows prompt, then try again.",
807
+ lanChangeTitle: "Change network",
808
+ lanChangeIntro: "Move local network access to another interface. The private CA and paired devices are kept; connected phones reconnect with the new address.",
809
+ lanChangeSelect: "New network",
810
+ lanChangeRefresh: "Scan again",
811
+ lanChangeConfirm: "Change network",
812
+ lanChangeBusy: "Changing network…",
813
+ lanChangeOk: "Network saved. If local access is stopped, enable it before connecting to the new address.",
814
+ lanChangeOkDisconnected: "Network changed and the listener restarted. Connected phones were disconnected; generate a new pairing QR to reconnect.",
815
+ lanChangeCurrent: "current",
816
+ lanChangeUnchanged: "That is already the current network.",
817
+ lanChangeUnavailable: "That network is no longer available. Scan again.",
818
+ lanChangeUnsupported: "This setup uses a fixed address, so it cannot change networks here.",
819
+ lanChangeFailed: "The change did not complete. Refresh the status before retrying; the previous configuration may have been restored.",
820
+ lanChangeRefreshFailed: "Could not refresh network status. A submitted change may have completed; check the current status before retrying.",
821
+ lanChangeRecoveryRequired: "The previous network could not be restored. Check local network configuration before enabling access again."
807
822
  });
808
823
  Object.assign(MOBILE_CONTROL_MESSAGES.it, {
809
824
  lanSetupTitle: "Completa la configurazione della rete locale",
@@ -818,7 +833,22 @@ window.__ModuleLoader__.load({
818
833
  lanSetupConfiguring: "Creazione dei certificati privati e delle regole di rete locale…",
819
834
  lanSetupRequired: "La configurazione della rete locale non è completa. Scegli una rete qui sopra per continuare.",
820
835
  lanSetupRestart: "Configurazione completata per {origin}. Riavvia DSH una volta per attivare l’accesso locale.",
821
- lanSetupFailed: "Configurazione non completata. Controlla la rete e approva la richiesta di Windows, quindi riprova."
836
+ lanSetupFailed: "Configurazione non completata. Controlla la rete e approva la richiesta di Windows, quindi riprova.",
837
+ lanChangeTitle: "Cambia rete",
838
+ lanChangeIntro: "Sposta l’accesso alla rete locale su un’altra interfaccia. La CA privata e i dispositivi abbinati restano; i telefoni collegati si riconnettono con il nuovo indirizzo.",
839
+ lanChangeSelect: "Nuova rete",
840
+ lanChangeRefresh: "Cerca di nuovo",
841
+ lanChangeConfirm: "Cambia rete",
842
+ lanChangeBusy: "Cambio della rete…",
843
+ lanChangeOk: "Rete salvata. Se l’accesso locale è disattivato, attivalo prima di collegarti al nuovo indirizzo.",
844
+ lanChangeOkDisconnected: "Rete cambiata e listener riavviato. I telefoni collegati sono stati disconnessi; genera un nuovo QR di abbinamento per riconnetterti.",
845
+ lanChangeCurrent: "attuale",
846
+ lanChangeUnchanged: "Questa è già la rete attuale.",
847
+ lanChangeUnavailable: "La rete non è più disponibile. Cerca di nuovo.",
848
+ lanChangeUnsupported: "Questa configurazione usa un indirizzo fisso: non può cambiare rete qui.",
849
+ lanChangeFailed: "Cambio non completato. Aggiorna lo stato prima di riprovare; la configurazione precedente potrebbe essere stata ripristinata.",
850
+ lanChangeRefreshFailed: "Impossibile aggiornare lo stato. Una modifica inviata potrebbe essere stata completata; verifica prima di riprovare.",
851
+ lanChangeRecoveryRequired: "Impossibile ripristinare la rete precedente. Controlla la configurazione locale prima di riattivare l’accesso."
822
852
  });
823
853
  Object.assign(MOBILE_CONTROL_MESSAGES.zh, {
824
854
  lanSetupTitle: "完成局域网配置",
@@ -833,7 +863,22 @@ window.__ModuleLoader__.load({
833
863
  lanSetupConfiguring: "正在生成私有证书并配置局域网规则…",
834
864
  lanSetupRequired: "尚未完成局域网配置,请选择上方网络继续。",
835
865
  lanSetupRestart: "已为 {origin} 完成配置。请重启一次 DSH,局域网访问会自动开启。",
836
- lanSetupFailed: "配置未完成。请确认网卡选择并允许 Windows 授权提示,然后重试。"
866
+ lanSetupFailed: "配置未完成。请确认网卡选择并允许 Windows 授权提示,然后重试。",
867
+ lanChangeTitle: "更换网络",
868
+ lanChangeIntro: "把局域网访问切换到另一块网卡。私有 CA 与已配对设备都会保留,已连接的手机需要用新地址重新连接。",
869
+ lanChangeSelect: "新网络",
870
+ lanChangeRefresh: "重新扫描",
871
+ lanChangeConfirm: "更换网络",
872
+ lanChangeBusy: "正在更换网络…",
873
+ lanChangeOk: "网络配置已保存。若局域网访问已关闭,请开启后再用新地址连接。",
874
+ lanChangeOkDisconnected: "网络已更换并重启监听,已连接的手机已断开;请生成新的配对二维码重新连接。",
875
+ lanChangeCurrent: "当前",
876
+ lanChangeUnchanged: "这已经是当前网络。",
877
+ lanChangeUnavailable: "该网络已不可用,请重新扫描。",
878
+ lanChangeUnsupported: "当前配置使用固定地址,无法在这里更换网络。",
879
+ lanChangeFailed: "更换未完成。请先刷新状态再决定是否重试;先前配置可能已恢复。",
880
+ lanChangeRefreshFailed: "无法刷新网络状态,已提交的更换可能已完成;请先确认当前状态,不要重复提交。",
881
+ lanChangeRecoveryRequired: "无法恢复先前网络,请先检查局域网配置,再决定是否重新开启访问。"
837
882
  });
838
883
  Object.assign(MOBILE_CONTROL_MESSAGES.en, {
839
884
  selfHostedConnections: "Self-hosted connection",
@@ -3933,7 +3978,7 @@ window.__ModuleLoader__.load({
3933
3978
  [data-dsh-mobile-details] { position:fixed !important; z-index:250 !important; inset:0 0 0 auto !important; width:min(94vw,460px) !important; max-width:none !important; transform:translateX(100%); transition:transform var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); background:var(--dsw-alias-bg-layer-1, #fff); box-shadow:-18px 0 46px rgb(15 23 42 / 18%); }
3934
3979
  [data-dsh-mobile-details][data-open="true"] { transform:translateX(0); }
3935
3980
  [data-dsh-mobile-handle] { display:none !important; }
3936
- [data-dsh-mobile-settings] { flex-direction:column !important; width:100vw !important; height:100dvh !important; max-width:none !important; border-radius:0 !important; animation:dsh-mobile-panel-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }
3981
+ [data-dsh-mobile-settings="true"] { flex-direction:column !important; width:100vw !important; height:100dvh !important; max-width:none !important; border-radius:0 !important; animation:dsh-mobile-panel-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }
3937
3982
  [data-dsh-mobile-settings-nav] { flex:none !important; width:100% !important; padding:max(14px,env(safe-area-inset-top)) 12px 8px !important; gap:10px !important; border-bottom:1px solid var(--dsw-alias-border-l2,#e8ebef); }
3938
3983
  [data-dsh-mobile-settings-nav] [class*="_navTitle"] { padding:0 8px !important; font-size:18px !important; line-height:28px !important; }
3939
3984
  [data-dsh-mobile-settings-list] { flex-direction:row !important; gap:4px !important; overflow-x:auto !important; scrollbar-width:none; }
@@ -4150,7 +4195,17 @@ window.__ModuleLoader__.load({
4150
4195
  const children = Array.from(dialog.children);
4151
4196
  const nav = children.find((child) => classToken(child, "_nav"));
4152
4197
  const content = children.find((child) => classToken(child, "_content"));
4153
- if (nav === void 0 || content === void 0) continue;
4198
+ if (nav === void 0) continue;
4199
+ if (content === void 0) {
4200
+ const header = children.find((child) => classToken(child, "_header"));
4201
+ const options = children.find((child) => classToken(child, "_options"));
4202
+ const title = children.find((child) => classToken(child, "_navTitle"));
4203
+ if (dialog.getAttribute("data-shortcut-modal") !== "settings" || header === void 0 || options === void 0 || title === void 0) continue;
4204
+ dialog.dataset.dshMobileSettings = "grid";
4205
+ header.setAttribute("data-dsh-mobile-settings-header", "true");
4206
+ marked += 1;
4207
+ continue;
4208
+ }
4154
4209
  dialog.dataset.dshMobileSettings = "true";
4155
4210
  nav.dataset.dshMobileSettingsNav = "true";
4156
4211
  content.dataset.dshMobileSettingsContent = "true";
@@ -11395,6 +11450,31 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
11395
11450
  const lanSetupStatus = element("p", "dsh-mobile-control__status");
11396
11451
  lanSetupStatus.setAttribute("role", "status");
11397
11452
  lanSetupStatus.setAttribute("aria-live", "polite");
11453
+ const lanChange = element("section", "dsh-mobile-control__lan-setup");
11454
+ lanChange.hidden = true;
11455
+ const lanChangeTitle = element("h3", "dsh-mobile-control__section-title");
11456
+ lanChangeTitle.textContent = t("lanChangeTitle");
11457
+ const lanChangeIntro = element("p", "dsh-mobile-control__intro");
11458
+ lanChangeIntro.textContent = t("lanChangeIntro");
11459
+ const lanChangeForm = element("div", "dsh-mobile-control__lan-setup-form");
11460
+ const lanChangeLabel = element("label", "dsh-mobile-control__field");
11461
+ lanChangeLabel.textContent = t("lanChangeSelect");
11462
+ const lanChangeSelect = element("select");
11463
+ lanChangeSelect.setAttribute("aria-label", t("lanChangeSelect"));
11464
+ lanChangeLabel.append(lanChangeSelect);
11465
+ const lanChangeActions = element("div", "dsh-mobile-control__lan-setup-actions");
11466
+ const lanChangeRefresh = element("button", "dsh-mobile-control__secondary");
11467
+ lanChangeRefresh.type = "button";
11468
+ lanChangeRefresh.textContent = t("lanChangeRefresh");
11469
+ const lanChangeConfirm = element("button", "dsh-mobile-control__primary");
11470
+ lanChangeConfirm.type = "button";
11471
+ lanChangeConfirm.textContent = t("lanChangeConfirm");
11472
+ lanChangeActions.append(lanChangeRefresh, lanChangeConfirm);
11473
+ const lanChangeStatus = element("p", "dsh-mobile-control__status");
11474
+ lanChangeStatus.setAttribute("role", "status");
11475
+ lanChangeStatus.setAttribute("aria-live", "polite");
11476
+ lanChangeForm.append(lanChangeLabel, lanChangeActions);
11477
+ lanChange.append(lanChangeTitle, lanChangeIntro, lanChangeForm, lanChangeStatus);
11398
11478
  const trustedNetworks = element("details", "dsh-mobile-control__details");
11399
11479
  const trustedNetworksSummary = element("summary");
11400
11480
  trustedNetworksSummary.textContent = t("trustedNetworksTitle");
@@ -12730,7 +12810,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
12730
12810
  diagnosticsDetails.append(diagnosticsDetailsSummary, diagnosticsReport);
12731
12811
  header.append(title, headerActions);
12732
12812
  actions.append(toggle, pair, linkPair);
12733
- lanView.append(lanSetup, access, qrBox, lanPairingValidity, status, extensionStatus, actions, trustedNetworks);
12813
+ lanView.append(lanSetup, lanChange, access, qrBox, lanPairingValidity, status, extensionStatus, actions, trustedNetworks);
12734
12814
  const channelPane = element("div", "dsh-mobile-control__channel-pane");
12735
12815
  channelPane.append(lanView, remoteWorkspace);
12736
12816
  const remoteColumns = element("div", "dsh-mobile-control__remote-columns");
@@ -12745,6 +12825,9 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
12745
12825
  let lanConfigured = true;
12746
12826
  let lanRestartRequired = false;
12747
12827
  let lanSetupLoaded = false;
12828
+ let lanChangeLoaded = false;
12829
+ let lanChangeBusy = false;
12830
+ let lanChangeRequest;
12748
12831
  let remoteRunning = false;
12749
12832
  let remoteReady = false;
12750
12833
  let remoteProvider = "tailscale";
@@ -12961,6 +13044,8 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
12961
13044
  lanChoiceBadge.textContent = running ? t("lanBadgeOn") : t("lanBadgeOff");
12962
13045
  origin = running && typeof data.origin === "string" ? data.origin : "";
12963
13046
  lanSetup.hidden = lanConfigured && !lanRestartRequired;
13047
+ lanChange.hidden = !lanConfigured || lanRestartRequired || data.rebindSupported !== true;
13048
+ if (!lanChange.hidden && !lanChangeLoaded) loadLanChange();
12964
13049
  lanSetupForm.hidden = lanRestartRequired;
12965
13050
  lanSetupIntro.hidden = lanRestartRequired;
12966
13051
  status.hidden = !lanConfigured || lanRestartRequired;
@@ -12974,7 +13059,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
12974
13059
  accessLink.textContent = origin;
12975
13060
  accessLink.title = origin;
12976
13061
  status.classList.toggle("is-running", running);
12977
- status.textContent = !lanConfigured ? t("lanSetupRequired") : lanRestartRequired ? t("lanSetupRestart", { origin: typeof data.pendingOrigin === "string" ? data.pendingOrigin : "" }) : running ? t("lanOn") : t("lanOff");
13062
+ status.textContent = data.recoveryRequired === true ? t("lanChangeRecoveryRequired") : !lanConfigured ? t("lanSetupRequired") : lanRestartRequired ? t("lanSetupRestart", { origin: typeof data.pendingOrigin === "string" ? data.pendingOrigin : "" }) : running ? t("lanOn") : t("lanOff");
12978
13063
  const extensionData = data.extensions;
12979
13064
  if (extensionData !== null && typeof extensionData === "object") {
12980
13065
  const loaded = typeof extensionData.loaded === "number" ? extensionData.loaded : 0;
@@ -13065,6 +13150,80 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
13065
13150
  lanSetupConfigure.disabled = lanRestartRequired || lanSetupSelect.options.length === 0;
13066
13151
  });
13067
13152
  });
13153
+ const syncLanChange = () => {
13154
+ const waiting = lanChangeBusy || lanChangeRequest !== void 0;
13155
+ lanChangeSelect.disabled = waiting;
13156
+ lanChangeRefresh.disabled = waiting;
13157
+ lanChangeConfirm.disabled = waiting || lanChangeSelect.options.length === 0;
13158
+ };
13159
+ const renderLanChange = (data) => {
13160
+ const networks = Array.isArray(data.networks) ? data.networks.filter((entry) => typeof entry === "object" && entry !== null) : [];
13161
+ lanChangeSelect.replaceChildren();
13162
+ for (const network of networks) {
13163
+ const name = typeof network.name === "string" ? network.name : "";
13164
+ const address = typeof network.address === "string" ? network.address : "";
13165
+ if (name === "") continue;
13166
+ const option = element("option");
13167
+ option.value = name;
13168
+ option.textContent = `${name} · ${address}${network.current === true ? ` · ${t("lanChangeCurrent")}` : ""}`;
13169
+ if (network.current === true) option.selected = true;
13170
+ lanChangeSelect.append(option);
13171
+ }
13172
+ syncLanChange();
13173
+ };
13174
+ const loadLanChange = () => {
13175
+ if (lanChangeRequest !== void 0) return lanChangeRequest;
13176
+ lanChangeLoaded = true;
13177
+ lanChangeRequest = Promise.all([controlRequestJson("/api/mobile-access/lan/networks"), controlRequestJson("/api/mobile-access/lan/control")]).then(([data, control]) => {
13178
+ if (!lifecycle.signal.aborted) {
13179
+ renderLanChange(data);
13180
+ render(control);
13181
+ }
13182
+ }, () => {
13183
+ if (!lifecycle.signal.aborted) lanChangeStatus.textContent = t("lanChangeRefreshFailed");
13184
+ }).finally(() => {
13185
+ lanChangeRequest = void 0;
13186
+ if (!lifecycle.signal.aborted) syncLanChange();
13187
+ });
13188
+ syncLanChange();
13189
+ return lanChangeRequest;
13190
+ };
13191
+ lanChangeRefresh.addEventListener("click", () => {
13192
+ loadLanChange();
13193
+ });
13194
+ lanChangeSelect.addEventListener("change", syncLanChange);
13195
+ lanChangeConfirm.addEventListener("click", () => {
13196
+ if (lanChangeSelect.value === "" || lanChangeBusy || lanChangeRequest !== void 0) return;
13197
+ lanChangeBusy = true;
13198
+ syncLanChange();
13199
+ lanChangeConfirm.textContent = t("lanChangeBusy");
13200
+ lanChangeStatus.textContent = t("lanChangeBusy");
13201
+ controlRequestJson("/api/mobile-access/lan/rebind", {
13202
+ method: "POST",
13203
+ body: JSON.stringify({ networkInterface: lanChangeSelect.value })
13204
+ }, LONG_CONTROL_REQUEST_TIMEOUT_MS).then(async (data) => {
13205
+ if (lifecycle.signal.aborted) return;
13206
+ lanChangeStatus.textContent = data.disconnected === true && data.ready === true ? t("lanChangeOkDisconnected") : t("lanChangeOk");
13207
+ try {
13208
+ const control = await controlRequestJson("/api/mobile-access/lan/control");
13209
+ if (lifecycle.signal.aborted) return;
13210
+ render(control);
13211
+ await loadLanChange();
13212
+ if (!lifecycle.signal.aborted && data.ready === true) openPairing("key");
13213
+ } catch {
13214
+ if (!lifecycle.signal.aborted) lanChangeStatus.textContent = t("lanChangeRefreshFailed");
13215
+ }
13216
+ }, (error) => {
13217
+ if (lifecycle.signal.aborted) return;
13218
+ const text = String(error);
13219
+ lanChangeStatus.textContent = text.includes("lan_rebind_unchanged") ? t("lanChangeUnchanged") : text.includes("lan_rebind_network_unavailable") ? t("lanChangeUnavailable") : text.includes("lan_rebind_unsupported") ? t("lanChangeUnsupported") : text.includes("lan_rebind_recovery_required") ? t("lanChangeRecoveryRequired") : t("lanChangeFailed");
13220
+ }).finally(() => {
13221
+ lanChangeBusy = false;
13222
+ if (lifecycle.signal.aborted) return;
13223
+ lanChangeConfirm.textContent = t("lanChangeConfirm");
13224
+ syncLanChange();
13225
+ });
13226
+ });
13068
13227
  const clearQrTarget = (target) => {
13069
13228
  if (typeof target.replaceChildren === "function") {
13070
13229
  target.replaceChildren();