ds-harness-remote 0.3.16 → 0.3.18

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.
Files changed (44) hide show
  1. package/README.md +29 -10
  2. package/dist/client-runtime.d.ts +12 -1
  3. package/dist/client-runtime.d.ts.map +1 -1
  4. package/dist/client-runtime.js +119 -9
  5. package/dist/client-runtime.js.map +1 -1
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/client.github.js +231 -9
  8. package/dist/client.js +231 -9
  9. package/dist/client.js.map +1 -1
  10. package/dist/file-viewer-bridge.d.ts +30 -0
  11. package/dist/file-viewer-bridge.d.ts.map +1 -0
  12. package/dist/file-viewer-bridge.js +128 -0
  13. package/dist/file-viewer-bridge.js.map +1 -0
  14. package/dist/file-viewer-contract.d.ts +5 -0
  15. package/dist/file-viewer-contract.d.ts.map +1 -0
  16. package/dist/file-viewer-contract.js +4 -0
  17. package/dist/file-viewer-contract.js.map +1 -0
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +669 -263
  21. package/dist/index.js.map +4 -4
  22. package/dist/remote-file-content-provider.d.ts +36 -0
  23. package/dist/remote-file-content-provider.d.ts.map +1 -0
  24. package/dist/remote-file-content-provider.js +73 -0
  25. package/dist/remote-file-content-provider.js.map +1 -0
  26. package/dist/rpc-router.d.ts +4 -2
  27. package/dist/rpc-router.d.ts.map +1 -1
  28. package/dist/rpc-router.js +11 -2
  29. package/dist/rpc-router.js.map +1 -1
  30. package/dist/server-connection.d.ts +2 -1
  31. package/dist/server-connection.d.ts.map +1 -1
  32. package/dist/server-connection.js +9 -6
  33. package/dist/server-connection.js.map +1 -1
  34. package/dist/service.d.ts +3 -1
  35. package/dist/service.d.ts.map +1 -1
  36. package/dist/service.js +9 -3
  37. package/dist/service.js.map +1 -1
  38. package/dist/typert-gateway-switch.d.ts +6 -1
  39. package/dist/typert-gateway-switch.d.ts.map +1 -1
  40. package/dist/typert-gateway-switch.js +19 -4
  41. package/dist/typert-gateway-switch.js.map +1 -1
  42. package/dist/version.d.ts +1 -1
  43. package/dist/version.js +1 -1
  44. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -1620,7 +1620,64 @@ Minimum version required to store current data is: ` + bestVersion + `.
1620
1620
  });
1621
1621
 
1622
1622
  // src/client.ts
1623
- var import_qrcode = __toESM(require_browser(), 1), clientModuleId = "ds-harness-remote", localeNamespace = "dsh-remote", en = {
1623
+ var import_qrcode = __toESM(require_browser(), 1);
1624
+
1625
+ // src/remote-file-content-provider.ts
1626
+ function shouldUseRemoteFileViewer(status) {
1627
+ return status.mode === "remote" && status.remoteFeatures?.fileViewer === !0;
1628
+ }
1629
+ function createRemoteFileContentProvider(call) {
1630
+ return {
1631
+ id: "dsh-remote-files",
1632
+ priority: 1e4,
1633
+ supports: () => !0,
1634
+ async stat(locator, signal) {
1635
+ let value = await call("fileviewer.stat", { path: locator }, signal);
1636
+ if (value.exists)
1637
+ return {
1638
+ name: value.name,
1639
+ size: value.isDirectory ? 0 : value.size,
1640
+ mime: value.mime,
1641
+ mtimeMs: value.mtimeMs,
1642
+ isDirectory: value.isDirectory
1643
+ };
1644
+ },
1645
+ async read(locator, request) {
1646
+ if (!Number.isInteger(request.offset) || request.offset < 0) throw new Error("A non-negative integer offset is required.");
1647
+ if (!Number.isInteger(request.length) || request.length <= 0) throw new Error("A positive integer length is required.");
1648
+ let chunks = [], received = 0;
1649
+ for (; received < request.length; ) {
1650
+ request.signal.throwIfAborted();
1651
+ let length = Math.min(524288, request.length - received), offset = request.offset + received, range = await call("fileviewer.readRange", { path: locator, offset, length }, request.signal);
1652
+ if (range.offset !== offset) throw new Error("The Remote Host returned a mismatched file range.");
1653
+ let bytes = decodeBase64(range.data);
1654
+ if (bytes.byteLength > length) throw new Error("The Remote Host returned more file bytes than requested.");
1655
+ if (chunks.push(bytes), received += bytes.byteLength, range.eof || bytes.byteLength === 0) break;
1656
+ }
1657
+ let merged = new Uint8Array(received), cursor = 0;
1658
+ for (let chunk of chunks)
1659
+ merged.set(chunk, cursor), cursor += chunk.byteLength;
1660
+ return merged;
1661
+ },
1662
+ async list(locator, signal) {
1663
+ return (await call("fileviewer.list", { path: locator }, signal)).entries.map((entry) => ({
1664
+ locator: entry.path,
1665
+ name: entry.name,
1666
+ size: entry.isDirectory ? 0 : entry.size ?? 0,
1667
+ mtimeMs: entry.mtimeMs,
1668
+ isDirectory: entry.isDirectory
1669
+ }));
1670
+ }
1671
+ };
1672
+ }
1673
+ function decodeBase64(value) {
1674
+ let binary = atob(value), bytes = new Uint8Array(binary.length);
1675
+ for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
1676
+ return bytes;
1677
+ }
1678
+
1679
+ // src/client.ts
1680
+ var clientModuleId = "ds-harness-remote", localeNamespace = "dsh-remote", en = {
1624
1681
  pluginTitle: "DeepSeek Remote",
1625
1682
  pluginDescription: "Connect once. Available anytime.",
1626
1683
  expandSettings: "Show settings: {name}",
@@ -1740,7 +1797,39 @@ Minimum version required to store current data is: ` + bestVersion + `.
1740
1797
  connectionRouteTurn: "TURN relay service",
1741
1798
  connectionRouteRelay: "Remote Server",
1742
1799
  connectionRouteHost: "Work computer running Harness",
1800
+ connectionRouteLanDetail: "Direct transfer over the local network",
1801
+ connectionRouteP2pDetail: "Direct transfer over the internet",
1802
+ connectionRouteTurnDetail: "Encrypted transfer through the TURN service",
1803
+ connectionRouteRelayDetail: "Encrypted transfer through the Remote Server",
1743
1804
  connectionRouteEncrypted: "Application data remains end-to-end encrypted along this route.",
1805
+ connectionDetailsConnection: "Connection",
1806
+ connectionDetailsWebRtc: "Network details \xB7 WebRTC / ICE",
1807
+ connectionId: "Connection ID",
1808
+ connectedAt: "Established",
1809
+ preferredTransports: "Attempt order",
1810
+ controlChannel: "Control channel",
1811
+ controlAddress: "Control address",
1812
+ controlStateConnecting: "Connecting",
1813
+ controlStateOpen: "Connected",
1814
+ controlStateClosing: "Closing",
1815
+ controlStateClosed: "Closed",
1816
+ peerState: "Peer connection",
1817
+ dataChannel: "DataChannel",
1818
+ localCandidate: "Local candidate",
1819
+ remoteCandidate: "Remote candidate",
1820
+ localAddress: "Local address",
1821
+ remoteAddress: "Remote address",
1822
+ networkProtocol: "Network protocol",
1823
+ relayProtocol: "TURN protocol",
1824
+ roundTripTime: "Round-trip time",
1825
+ availableBitrate: "Available outgoing bitrate",
1826
+ bytesSent: "WebRTC bytes sent",
1827
+ bytesReceived: "WebRTC bytes received",
1828
+ notProvided: "Not provided",
1829
+ candidateHost: "Local address \xB7 host",
1830
+ candidateSrflx: "Public address \xB7 srflx",
1831
+ candidatePrflx: "Peer address \xB7 prflx",
1832
+ candidateRelay: "TURN address \xB7 relay",
1744
1833
  openLocalWorkspaces: "Open local workspaces",
1745
1834
  clientSignInHint: "Sign in to this Server to list your remote Hosts.",
1746
1835
  signInClient: "DeepSeek Harness Remote",
@@ -1874,7 +1963,39 @@ Minimum version required to store current data is: ` + bestVersion + `.
1874
1963
  connectionRouteTurn: "TURN \u4E2D\u7EE7\u670D\u52A1",
1875
1964
  connectionRouteRelay: "Remote Server",
1876
1965
  connectionRouteHost: "\u8FD0\u884C Harness \u7684\u5DE5\u4F5C\u7535\u8111",
1966
+ connectionRouteLanDetail: "\u5728\u672C\u5730\u7F51\u7EDC\u4E2D\u76F4\u63A5\u4F20\u8F93",
1967
+ connectionRouteP2pDetail: "\u901A\u8FC7\u4E92\u8054\u7F51\u76F4\u63A5\u4F20\u8F93",
1968
+ connectionRouteTurnDetail: "\u901A\u8FC7 TURN \u670D\u52A1\u8F6C\u53D1\u52A0\u5BC6\u6570\u636E",
1969
+ connectionRouteRelayDetail: "\u901A\u8FC7 Remote Server \u8F6C\u53D1\u52A0\u5BC6\u6570\u636E",
1877
1970
  connectionRouteEncrypted: "\u7EBF\u8DEF\u4E0A\u7684\u4E1A\u52A1\u6570\u636E\u4FDD\u6301\u7AEF\u5230\u7AEF\u52A0\u5BC6\u3002",
1971
+ connectionDetailsConnection: "\u8FDE\u63A5",
1972
+ connectionDetailsWebRtc: "\u7F51\u7EDC\u8BE6\u60C5 \xB7 WebRTC / ICE",
1973
+ connectionId: "\u8FDE\u63A5\u7F16\u53F7",
1974
+ connectedAt: "\u5EFA\u7ACB\u65F6\u95F4",
1975
+ preferredTransports: "\u5C1D\u8BD5\u987A\u5E8F",
1976
+ controlChannel: "\u63A7\u5236\u901A\u9053",
1977
+ controlAddress: "\u63A7\u5236\u5730\u5740",
1978
+ controlStateConnecting: "\u8FDE\u63A5\u4E2D",
1979
+ controlStateOpen: "\u5DF2\u8FDE\u63A5",
1980
+ controlStateClosing: "\u6B63\u5728\u5173\u95ED",
1981
+ controlStateClosed: "\u5DF2\u5173\u95ED",
1982
+ peerState: "\u8FDE\u63A5\u72B6\u6001",
1983
+ dataChannel: "DataChannel",
1984
+ localCandidate: "\u672C\u5730\u5019\u9009",
1985
+ remoteCandidate: "\u8FDC\u7AEF\u5019\u9009",
1986
+ localAddress: "\u672C\u5730\u5730\u5740",
1987
+ remoteAddress: "\u8FDC\u7AEF\u5730\u5740",
1988
+ networkProtocol: "\u4F20\u8F93\u534F\u8BAE",
1989
+ relayProtocol: "TURN \u534F\u8BAE",
1990
+ roundTripTime: "\u5F80\u8FD4\u65F6\u5EF6",
1991
+ availableBitrate: "\u53EF\u7528\u4E0A\u884C\u5E26\u5BBD",
1992
+ bytesSent: "WebRTC \u5DF2\u53D1\u9001",
1993
+ bytesReceived: "WebRTC \u5DF2\u63A5\u6536",
1994
+ notProvided: "\u672A\u63D0\u4F9B",
1995
+ candidateHost: "\u672C\u5730\u5730\u5740 \xB7 host",
1996
+ candidateSrflx: "\u516C\u7F51\u5730\u5740 \xB7 srflx",
1997
+ candidatePrflx: "\u5BF9\u7AEF\u5730\u5740 \xB7 prflx",
1998
+ candidateRelay: "TURN \u5730\u5740 \xB7 relay",
1878
1999
  openLocalWorkspaces: "\u6253\u5F00\u672C\u5730\u5DE5\u4F5C\u533A",
1879
2000
  clientSignInHint: "\u767B\u5F55 Server \u540E\u5373\u53EF\u67E5\u770B\u81EA\u5DF1\u7684\u8FDC\u7AEF\u4E3B\u673A\u3002",
1880
2001
  signInClient: "DeepSeek Harness Remote",
@@ -1893,6 +2014,22 @@ Minimum version required to store current data is: ` + bestVersion + `.
1893
2014
  let date = new Date(value);
1894
2015
  return Number.isNaN(date.getTime()) ? "\u2014" : date.toLocaleString();
1895
2016
  }
2017
+ function formatByteSize(value) {
2018
+ if (value < 1024) return `${value.toLocaleString()} B`;
2019
+ let units = ["KiB", "MiB", "GiB"], amount = value, unit = "B";
2020
+ for (let nextUnit of units)
2021
+ if (amount /= 1024, unit = nextUnit, amount < 1024) break;
2022
+ return `${amount.toLocaleString(void 0, { maximumFractionDigits: 1 })} ${unit}`;
2023
+ }
2024
+ function formatBitrate(value) {
2025
+ let units = ["bit/s", "Kbit/s", "Mbit/s", "Gbit/s"], amount = value, unitIndex = 0;
2026
+ for (; amount >= 1e3 && unitIndex < units.length - 1; )
2027
+ amount /= 1e3, unitIndex += 1;
2028
+ return `${amount.toLocaleString(void 0, { maximumFractionDigits: 1 })} ${units[unitIndex]}`;
2029
+ }
2030
+ function shortDeviceId(value) {
2031
+ return value.length <= 14 ? value : `${value.slice(0, 8)}\u2026${value.slice(-4)}`;
2032
+ }
1896
2033
  function connectionErrorMessage(code, t) {
1897
2034
  return t(code === "ACCOUNT_AUTH_REQUIRED" || code === "AUTH_INVALID" || code === "TOKEN_EXPIRED" ? "connectionAuthorizationExpired" : code === "DEVICE_REVOKED" ? "connectionDeviceRevoked" : code === "DEVICE_OWNERSHIP_REQUIRED" ? "connectionOwnershipRequired" : code === "RATE_LIMITED" ? "connectionRateLimited" : code === "UNSUPPORTED_VERSION" ? "connectionVersionMismatch" : code === "INVALID_MESSAGE" ? "connectionInvalidResponse" : code === "CONNECTION_FAILED" || code === "SERVER_NOT_CONFIGURED" ? "connectionReachability" : "connectionUnexpected");
1898
2035
  }
@@ -2734,7 +2871,13 @@ Minimum version required to store current data is: ` + bestVersion + `.
2734
2871
  }, []), React.useEffect(() => {
2735
2872
  if (status?.mode === "remote")
2736
2873
  return hideLocalSessionActions();
2737
- }, [status?.mode]), status?.mode !== "remote") return null;
2874
+ }, [status?.mode]), React.useEffect(() => {
2875
+ if (!routeOpen) return;
2876
+ let closeOnEscape = (event) => {
2877
+ event.key === "Escape" && setRouteOpen(!1);
2878
+ };
2879
+ return document.addEventListener("keydown", closeOnEscape), () => document.removeEventListener("keydown", closeOnEscape);
2880
+ }, [routeOpen]), status?.mode !== "remote") return null;
2738
2881
  let exit = async () => {
2739
2882
  setBusy(!0);
2740
2883
  try {
@@ -2742,7 +2885,12 @@ Minimum version required to store current data is: ` + bestVersion + `.
2742
2885
  } finally {
2743
2886
  setBusy(!1);
2744
2887
  }
2745
- }, transport = status.transport ?? "Disconnected", networkLabel = t(transport === "P2P" ? "remoteNetworkP2p" : transport === "TURN" ? "remoteNetworkTurn" : transport === "Relay" ? "remoteNetworkRelay" : transport === "LAN" ? "remoteNetworkLan" : "remoteNetworkOffline"), networkOnline = status.connected === !0 && transport !== "Disconnected", routeVia = t(transport === "P2P" ? "connectionRouteP2p" : transport === "TURN" ? "connectionRouteTurn" : transport === "Relay" ? "connectionRouteRelay" : "connectionRouteLan");
2888
+ }, transport = status.transport ?? "Disconnected", networkLabel = t(transport === "P2P" ? "remoteNetworkP2p" : transport === "TURN" ? "remoteNetworkTurn" : transport === "Relay" ? "remoteNetworkRelay" : transport === "LAN" ? "remoteNetworkLan" : "remoteNetworkOffline"), networkOnline = status.connected === !0 && transport !== "Disconnected", routeVia = t(transport === "P2P" ? "connectionRouteP2p" : transport === "TURN" ? "connectionRouteTurn" : transport === "Relay" ? "connectionRouteRelay" : "connectionRouteLan"), routeViaDetail = t(transport === "P2P" ? "connectionRouteP2pDetail" : transport === "TURN" ? "connectionRouteTurnDetail" : transport === "Relay" ? "connectionRouteRelayDetail" : "connectionRouteLanDetail"), network = status.network, webRtc = network?.webRtc, controlStateLabel = network?.controlChannelState === "connecting" ? t("controlStateConnecting") : network?.controlChannelState === "open" ? t("controlStateOpen") : network?.controlChannelState === "closing" ? t("controlStateClosing") : t("controlStateClosed"), detailValue = (value) => value === void 0 || value === "" ? t("notProvided") : String(value), candidateLabel = (value) => value === "host" ? t("candidateHost") : value === "srflx" ? t("candidateSrflx") : value === "prflx" ? t("candidatePrflx") : value === "relay" ? t("candidateRelay") : detailValue(value), fact = (label, value, mono = !1) => React.createElement(
2889
+ "div",
2890
+ null,
2891
+ React.createElement("dt", null, label),
2892
+ React.createElement("dd", { className: mono ? "isMono" : void 0, title: mono ? value : void 0 }, value)
2893
+ );
2746
2894
  return React.createElement(
2747
2895
  "div",
2748
2896
  { className: "dshRemoteSessionHeader", role: "status" },
@@ -2778,7 +2926,6 @@ Minimum version required to store current data is: ` + bestVersion + `.
2778
2926
  {
2779
2927
  className: "dshRemoteRoutePanel",
2780
2928
  role: "dialog",
2781
- "aria-modal": !0,
2782
2929
  "aria-label": t("connectionRouteTitle")
2783
2930
  },
2784
2931
  React.createElement(
@@ -2790,9 +2937,62 @@ Minimum version required to store current data is: ` + bestVersion + `.
2790
2937
  React.createElement(
2791
2938
  "ol",
2792
2939
  null,
2793
- React.createElement("li", null, React.createElement("small", null, t("connectionRouteFrom")), React.createElement("strong", null, t("connectionRouteCurrentDevice"))),
2794
- React.createElement("li", null, React.createElement("small", null, t("connectionRouteVia")), React.createElement("strong", null, routeVia)),
2795
- React.createElement("li", null, React.createElement("small", null, t("connectionRouteTo")), React.createElement("strong", null, status.target?.name ?? t("host")), React.createElement("span", null, t("connectionRouteHost")))
2940
+ React.createElement(
2941
+ "li",
2942
+ null,
2943
+ React.createElement("small", null, t("connectionRouteFrom")),
2944
+ React.createElement("strong", null, network?.local.name ?? t("connectionRouteCurrentDevice")),
2945
+ network === void 0 ? null : React.createElement("span", null, `${network.local.platform} \xB7 ${shortDeviceId(network.local.deviceId)}`)
2946
+ ),
2947
+ React.createElement(
2948
+ "li",
2949
+ null,
2950
+ React.createElement("small", null, t("connectionRouteVia")),
2951
+ React.createElement("strong", null, routeVia),
2952
+ React.createElement("span", null, routeViaDetail)
2953
+ ),
2954
+ React.createElement(
2955
+ "li",
2956
+ null,
2957
+ React.createElement("small", null, t("connectionRouteTo")),
2958
+ React.createElement("strong", null, network?.remote.name ?? status.target?.name ?? t("host")),
2959
+ React.createElement("span", null, network === void 0 ? t("connectionRouteHost") : `${network.remote.platform} \xB7 ${shortDeviceId(network.remote.deviceId)}`)
2960
+ )
2961
+ ),
2962
+ network === void 0 ? null : React.createElement(
2963
+ "section",
2964
+ { className: "dshRemoteRouteSection" },
2965
+ React.createElement("h3", null, t("connectionDetailsConnection")),
2966
+ React.createElement(
2967
+ "dl",
2968
+ null,
2969
+ fact(t("connectionId"), detailValue(network.connectionId), !0),
2970
+ fact(t("connectedAt"), network.connectedAt === void 0 ? t("notProvided") : formatLocalTime(network.connectedAt)),
2971
+ fact(t("preferredTransports"), network.preferredTransports.map((value) => value.toUpperCase()).join(" \u2192 ")),
2972
+ fact(t("controlChannel"), `WebSocket \xB7 ${controlStateLabel}`),
2973
+ fact(t("controlAddress"), network.controlChannelUrl, !0)
2974
+ )
2975
+ ),
2976
+ webRtc === void 0 ? null : React.createElement(
2977
+ "section",
2978
+ { className: "dshRemoteRouteSection" },
2979
+ React.createElement("h3", null, t("connectionDetailsWebRtc")),
2980
+ React.createElement(
2981
+ "dl",
2982
+ null,
2983
+ fact(t("peerState"), `${webRtc.connectionState} \xB7 ICE ${webRtc.iceConnectionState}`),
2984
+ fact(t("dataChannel"), detailValue(webRtc.dataChannelState)),
2985
+ fact(t("localCandidate"), candidateLabel(webRtc.localCandidateType)),
2986
+ fact(t("remoteCandidate"), candidateLabel(webRtc.remoteCandidateType)),
2987
+ fact(t("localAddress"), detailValue(webRtc.localAddress), !0),
2988
+ fact(t("remoteAddress"), detailValue(webRtc.remoteAddress), !0),
2989
+ fact(t("networkProtocol"), detailValue(webRtc.protocol?.toUpperCase())),
2990
+ fact(t("relayProtocol"), detailValue(webRtc.relayProtocol?.toUpperCase())),
2991
+ fact(t("roundTripTime"), webRtc.currentRoundTripTimeMs === void 0 ? t("notProvided") : `${webRtc.currentRoundTripTimeMs.toLocaleString()} ms`),
2992
+ fact(t("availableBitrate"), webRtc.availableOutgoingBitrate === void 0 ? t("notProvided") : formatBitrate(webRtc.availableOutgoingBitrate)),
2993
+ fact(t("bytesSent"), webRtc.bytesSent === void 0 ? t("notProvided") : formatByteSize(webRtc.bytesSent)),
2994
+ fact(t("bytesReceived"), webRtc.bytesReceived === void 0 ? t("notProvided") : formatByteSize(webRtc.bytesReceived))
2995
+ )
2796
2996
  ),
2797
2997
  React.createElement("p", null, t("connectionRouteEncrypted"))
2798
2998
  )) : null
@@ -2838,7 +3038,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2838
3038
  ".dshRemoteModeButton:is(button):hover{background:var(--dsw-alias-interactive-bg-hover)}",
2839
3039
  ".dshRemoteSidebarEntry{box-sizing:border-box;position:relative;min-width:0;display:block;overflow:hidden}.dshRemoteSidebarEntry .dshRemoteModeButton{box-sizing:border-box;width:100%;min-width:0}.dshRemoteSidebarEntry.isWide{width:calc(100% + 8px);height:34px;margin:4px -4px}.dshRemoteSidebarEntry.isWide .dshRemoteModeButton{height:34px;min-height:34px;padding:6px 48px 6px 10px;border-radius:12px}.dshRemoteSidebarEntry.isRail{width:36px;height:54px}.dshRemoteSidebarEntry.isRail .dshRemoteModeButton{width:36px;height:36px;min-height:36px;justify-content:center;gap:0;margin:8px 0 10px;padding:0;border-radius:50%}.dshRemoteSidebarEntry.isActive .dshRemoteModeButton{color:var(--dsw-alias-label-secondary);background:transparent}.dshRemoteSidebarLabel{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteExitLink{position:absolute;top:50%;right:10px;transform:translateY(-50%);white-space:nowrap;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:0;font:inherit;font-size:12px;line-height:20px;cursor:pointer}.dshRemoteExitLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteExitLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:2px}.dshRemoteExitLink:disabled{opacity:.45;cursor:default;text-decoration:none}",
2840
3040
  ".dshRemoteComputerIcon{box-sizing:border-box;width:18px;height:18px;flex:0 0 18px;color:var(--dsw-alias-label-secondary)}",
2841
- '.dshRemoteSessionHeader{position:fixed;z-index:25;top:12px;left:50%;transform:translateX(-50%);max-width:calc(100vw - 360px);height:28px;display:inline-flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;white-space:nowrap}.dshRemoteSessionHeader>svg{width:15px;height:15px;flex:0 0 auto}.dshRemoteSessionTarget{min-width:0;max-width:260px;overflow:hidden;text-overflow:ellipsis}.dshRemoteNetwork{flex:0 0 auto;border:0;background:transparent;color:inherit;font:inherit;padding:3px 2px;display:inline-flex;align-items:center;gap:5px;cursor:pointer}.dshRemoteNetwork:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteNetwork:disabled{cursor:default}.dshRemoteNetwork>i{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork.isOnline>i{background:var(--dsw-alias-state-success-primary)}.dshRemoteNetwork.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemoteNetwork.isOffline>i{background:currentColor}.dshRemoteEncrypted{flex:0 0 auto;color:var(--dsw-alias-label-tertiary)}.dshRemoteHeaderExitLink{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:3px 2px;font:inherit;text-decoration:none;cursor:pointer}.dshRemoteHeaderExitLink:hover{text-decoration:underline;color:var(--dsw-alias-label-primary)}.dshRemoteHeaderExitLink:disabled{opacity:.45;cursor:default;text-decoration:none}.dshRemoteRouteBackdrop{position:fixed;inset:0;z-index:26}.dshRemoteRoutePanel{position:absolute;top:48px;right:28px;width:min(460px,calc(100vw - 32px));color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;box-shadow:var(--dsw-shadow-lv2);padding:16px;white-space:normal}.dshRemoteRoutePanel>header{display:flex;align-items:center;justify-content:space-between}.dshRemoteRoutePanel>header strong{font-size:14px}.dshRemoteRoutePanel>header button{width:28px;height:28px;border:0;border-radius:7px;background:transparent;color:inherit;font-size:20px;cursor:pointer}.dshRemoteRoutePanel>header button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteRoutePanel ol{display:flex;align-items:stretch;margin:16px 0;padding:0;list-style:none}.dshRemoteRoutePanel li{position:relative;min-width:0;flex:1;display:flex;flex-direction:column;gap:4px;padding-right:20px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2192";position:absolute;right:7px;top:21px;color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li small{color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li strong,.dshRemoteRoutePanel li span{overflow:hidden;text-overflow:ellipsis}.dshRemoteRoutePanel li strong{font-size:13px}.dshRemoteRoutePanel li span{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteRoutePanel>p{margin:14px 0 0;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}@media(max-width:620px){.dshRemoteSessionHeader{top:8px;max-width:calc(100vw - 112px)}.dshRemoteSessionHeader>svg{display:none}.dshRemoteSessionTarget{max-width:130px}.dshRemoteEncrypted{display:none}.dshRemoteRoutePanel{top:42px;right:12px}.dshRemoteRoutePanel ol{flex-direction:column;gap:18px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2193";top:auto;right:auto;bottom:-16px;left:3px}}',
3041
+ '.dshRemoteSessionHeader{position:fixed;z-index:25;top:12px;left:50%;transform:translateX(-50%);max-width:calc(100vw - 360px);height:28px;display:inline-flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;white-space:nowrap}.dshRemoteSessionHeader>svg{width:15px;height:15px;flex:0 0 auto}.dshRemoteSessionTarget{min-width:0;max-width:260px;overflow:hidden;text-overflow:ellipsis}.dshRemoteNetwork{flex:0 0 auto;border:0;background:transparent;color:inherit;font:inherit;padding:3px 2px;display:inline-flex;align-items:center;gap:5px;cursor:pointer}.dshRemoteNetwork:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteNetwork:disabled{cursor:default}.dshRemoteNetwork>i{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork.isOnline>i{background:var(--dsw-alias-state-success-primary)}.dshRemoteNetwork.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemoteNetwork.isOffline>i{background:currentColor}.dshRemoteEncrypted{flex:0 0 auto;color:var(--dsw-alias-label-tertiary)}.dshRemoteHeaderExitLink{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:3px 2px;font:inherit;text-decoration:none;cursor:pointer}.dshRemoteHeaderExitLink:hover{text-decoration:underline;color:var(--dsw-alias-label-primary)}.dshRemoteHeaderExitLink:disabled{opacity:.45;cursor:default;text-decoration:none}.dshRemoteNetwork:focus-visible,.dshRemoteHeaderExitLink:focus-visible,.dshRemoteRoutePanel>header button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteRouteBackdrop{position:fixed;inset:0;z-index:26}.dshRemoteRoutePanel{box-sizing:border-box;position:absolute;top:48px;right:28px;width:min(680px,calc(100vw - 32px));max-height:calc(100vh - 72px);overflow:auto;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;padding:16px;white-space:normal}.dshRemoteRoutePanel>header{position:sticky;top:-16px;z-index:1;display:flex;align-items:center;justify-content:space-between;margin:-16px -16px 0;padding:16px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteRoutePanel>header strong{font-size:14px}.dshRemoteRoutePanel>header button{width:28px;height:28px;border:0;border-radius:7px;background:transparent;color:inherit;font-size:20px;cursor:pointer}.dshRemoteRoutePanel>header button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteRoutePanel ol{display:flex;align-items:stretch;margin:12px 0 0;padding:0 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2);list-style:none}.dshRemoteRoutePanel li{position:relative;min-width:0;flex:1;display:flex;flex-direction:column;gap:4px;padding-right:20px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2192";position:absolute;right:7px;top:21px;color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li small{color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li strong,.dshRemoteRoutePanel li span{overflow:hidden;text-overflow:ellipsis}.dshRemoteRoutePanel li strong{font-size:13px}.dshRemoteRoutePanel li span{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteRouteSection{padding-top:16px}.dshRemoteRouteSection h3{margin:0 0 10px;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary)}.dshRemoteRouteSection dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 24px;margin:0}.dshRemoteRouteSection dl>div{min-width:0;display:grid;grid-template-columns:minmax(104px,auto) minmax(0,1fr);gap:10px;padding:7px 0;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:12px;line-height:1.45}.dshRemoteRouteSection dt{color:var(--dsw-alias-label-tertiary)}.dshRemoteRouteSection dd{min-width:0;margin:0;text-align:right;overflow-wrap:anywhere}.dshRemoteRouteSection dd.isMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}.dshRemoteRoutePanel>p{margin:16px 0 0;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}@media(max-width:620px){.dshRemoteSessionHeader{top:8px;max-width:calc(100vw - 112px)}.dshRemoteSessionHeader>svg{display:none}.dshRemoteSessionTarget{max-width:130px}.dshRemoteEncrypted{display:none}.dshRemoteRoutePanel{top:42px;right:12px;max-height:calc(100vh - 56px)}.dshRemoteRoutePanel ol{flex-direction:column;gap:18px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2193";top:auto;right:auto;bottom:-16px;left:3px}.dshRemoteRouteSection dl{grid-template-columns:1fr}}',
2842
3042
  ".dshRemoteSessionHeader{left:auto;right:148px;transform:none;max-width:calc(100vw - 420px)}@media(max-width:760px){.dshRemoteSessionHeader{left:auto;right:104px;transform:none;max-width:calc(100vw - 124px)}}",
2843
3043
  ".dshRemoteModeButton:focus-visible,.dshRemotePage button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}",
2844
3044
  ".dshRemotePage{width:min(720px,100%);max-height:min(760px,calc(100vh - 40px));display:flex;flex-direction:column;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:14px;overflow:hidden;animation:dshRemotePageIn .18s cubic-bezier(.25,1,.5,1)}",
@@ -2898,7 +3098,29 @@ Minimum version required to store current data is: ` + bestVersion + `.
2898
3098
  if (!result.ok) throw new Error(result.error?.message ?? t("remoteRequestFailed"));
2899
3099
  return result.value;
2900
3100
  };
2901
- ctx.effect(() => ctx.locale.register(localeNamespace, { zh, en }), "dsh-remote: dictionaries"), ctx.effect(installStyle, "dsh-remote: client styles"), ctx.slots.inject("shell.overlay", () => ctx.slots.register({
3101
+ ctx.inject(["fileViewer"], (fileViewerContext) => {
3102
+ let viewer = fileViewerContext.get("fileViewer");
3103
+ viewer !== void 0 && fileViewerContext.effect(() => {
3104
+ let active = !0, unregister, sync = async () => {
3105
+ try {
3106
+ let status = await control("status");
3107
+ if (!active) return;
3108
+ let supported = shouldUseRemoteFileViewer(status);
3109
+ supported && unregister === void 0 ? unregister = viewer.registerContentProvider(createRemoteFileContentProvider(
3110
+ (endpoint, payload) => control(endpoint, payload)
3111
+ )) : !supported && unregister !== void 0 && (unregister(), unregister = void 0);
3112
+ } catch {
3113
+ }
3114
+ };
3115
+ sync();
3116
+ let timer = window.setInterval(() => {
3117
+ sync();
3118
+ }, 1500);
3119
+ return () => {
3120
+ active = !1, window.clearInterval(timer), unregister?.();
3121
+ };
3122
+ }, "dsh-remote: remote file viewer provider");
3123
+ }), ctx.effect(() => ctx.locale.register(localeNamespace, { zh, en }), "dsh-remote: dictionaries"), ctx.effect(installStyle, "dsh-remote: client styles"), ctx.slots.inject("shell.overlay", () => ctx.slots.register({
2902
3124
  name: "shell.overlay",
2903
3125
  id: "dsh-remote-global-context",
2904
3126
  order: 20,