dsh-bridge-gateway 0.1.2 → 0.1.4
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 +10 -0
- package/client/client.js +41 -4
- package/client/index.js +40 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
本项目 `dsh-bridge-gateway` 是基于 [dsh-bridge](https://github.com/wenbin-wb/dsh-bridge) 的移植增强分支,在保留原版能力之外,重点新增「公网直连网关」。
|
|
4
4
|
|
|
5
|
+
## [0.1.4] - 待发布
|
|
6
|
+
|
|
7
|
+
### 修复
|
|
8
|
+
- 修复「远程访问」面板在宿主连接未建立时无限卡在「加载中」的问题:为状态拉取增加兜底超时(15s),超时后释放 in-flight 锁并给出可用的「🔄 重试」按钮,避免面板永远无法自行恢复。
|
|
9
|
+
|
|
10
|
+
## [0.1.3] - 待发布
|
|
11
|
+
|
|
12
|
+
### 修复
|
|
13
|
+
- 修复移动端对话时底部输入框横向超出屏幕右缘的问题:约束输入卡片与编辑器最大宽度不超视口,长内容自动折行。
|
|
14
|
+
|
|
5
15
|
## [0.1.2] - 待发布
|
|
6
16
|
|
|
7
17
|
### 新增
|
package/client/client.js
CHANGED
|
@@ -2920,18 +2920,29 @@ function BridgePanel({ rpcCall }) {
|
|
|
2920
2920
|
}, [rpcCall, adminToken]);
|
|
2921
2921
|
const loadInFlightRef = React.useRef(false);
|
|
2922
2922
|
const loadSeqRef = React.useRef(0);
|
|
2923
|
+
const LOAD_TIMEOUT_MS = 15e3;
|
|
2923
2924
|
const load = React.useCallback(async (quiet = false) => {
|
|
2924
2925
|
if (loadInFlightRef.current) return;
|
|
2925
2926
|
loadInFlightRef.current = true;
|
|
2926
2927
|
const currentSeq = ++loadSeqRef.current;
|
|
2928
|
+
const timedOut = { done: false };
|
|
2927
2929
|
try {
|
|
2928
|
-
const
|
|
2930
|
+
const result = await Promise.race([
|
|
2931
|
+
authRpcCall(BRIDGE_ENDPOINTS.getStatus, {}),
|
|
2932
|
+
new Promise((resolve) => {
|
|
2933
|
+
setTimeout(() => {
|
|
2934
|
+
timedOut.done = true;
|
|
2935
|
+
resolve(null);
|
|
2936
|
+
}, LOAD_TIMEOUT_MS);
|
|
2937
|
+
})
|
|
2938
|
+
]);
|
|
2939
|
+
if (timedOut.done) throw new Error("\u52A0\u8F7D\u8D85\u65F6\uFF08\u5BBF\u4E3B\u8FDE\u63A5\u53EF\u80FD\u5728\u5207\u6362\u6216\u672A\u5EFA\u7ACB\uFF09\u3002\u8BF7\u70B9\u51FB\u300C\u{1F504} \u91CD\u8BD5\u300D\u5237\u65B0\u3002");
|
|
2929
2940
|
if (currentSeq !== loadSeqRef.current) return;
|
|
2930
|
-
if (!
|
|
2931
|
-
setStatus(
|
|
2941
|
+
if (!result?.ok) throw new Error(result?.error?.message ?? "RPC failed");
|
|
2942
|
+
setStatus(result.value);
|
|
2932
2943
|
if (!quiet) setErr(null);
|
|
2933
2944
|
} catch (e) {
|
|
2934
|
-
if (currentSeq === loadSeqRef.current) setErr(e.message);
|
|
2945
|
+
if (currentSeq === loadSeqRef.current) setErr(e.message || "\u52A0\u8F7D\u5931\u8D25");
|
|
2935
2946
|
} finally {
|
|
2936
2947
|
loadInFlightRef.current = false;
|
|
2937
2948
|
}
|
|
@@ -3345,6 +3356,11 @@ function BridgePanel({ rpcCall }) {
|
|
|
3345
3356
|
}
|
|
3346
3357
|
},
|
|
3347
3358
|
React.createElement("span", { style: { flex: "1 1 auto" } }, err),
|
|
3359
|
+
!isInterceptionErr && React.createElement("button", {
|
|
3360
|
+
type: "button",
|
|
3361
|
+
style: { ...s.btnGhost, height: 26, fontSize: 12, padding: "0 10px", flexShrink: 0 },
|
|
3362
|
+
onClick: () => load()
|
|
3363
|
+
}, "\u{1F504} \u91CD\u8BD5"),
|
|
3348
3364
|
isInterceptionErr && React.createElement("button", {
|
|
3349
3365
|
type: "button",
|
|
3350
3366
|
style: { ...s.btnPri, background: "#dc2626", color: "#ffffff", height: 26, fontSize: 12, padding: "0 10px", flexShrink: 0 },
|
|
@@ -3902,6 +3918,27 @@ function injectMobileStyles() {
|
|
|
3902
3918
|
background: var(--dsw-alias-bg-layer-2, #f4f4f7) !important;
|
|
3903
3919
|
}
|
|
3904
3920
|
|
|
3921
|
+
/* \u8F93\u5165\u6846\u6A2A\u5411\u4E0D\u6EA2\u51FA\uFF1A\u5361\u7247\u53CA\u5176\u7F29\u5BB9\u5668\u6700\u5927\u5BBD\u5EA6\u4E0D\u8D85\u8FC7\u89C6\u53E3\uFF0C\u5185\u90E8\u7F16\u8F91\u5668\u53EF\u6536\u7F29\u3001\u957F\u5185\u5BB9\u81EA\u52A8\u6298\u884C */
|
|
3922
|
+
div[class*="uV2eYG_scrollBody"] {
|
|
3923
|
+
max-width: 100vw !important;
|
|
3924
|
+
overflow-x: hidden !important;
|
|
3925
|
+
}
|
|
3926
|
+
div[class*="uV2eYG_card"] {
|
|
3927
|
+
width: 100% !important;
|
|
3928
|
+
max-width: 100% !important;
|
|
3929
|
+
min-width: 0 !important;
|
|
3930
|
+
box-sizing: border-box !important;
|
|
3931
|
+
}
|
|
3932
|
+
div[class*="uV2eYG_card"] div,
|
|
3933
|
+
div[class*="uV2eYG_card"] textarea,
|
|
3934
|
+
div[class*="uV2eYG_card"] [contenteditable="true"] {
|
|
3935
|
+
max-width: 100% !important;
|
|
3936
|
+
min-width: 0 !important;
|
|
3937
|
+
overflow-wrap: anywhere !important;
|
|
3938
|
+
word-break: break-word !important;
|
|
3939
|
+
box-sizing: border-box !important;
|
|
3940
|
+
}
|
|
3941
|
+
|
|
3905
3942
|
/* \u8F93\u5165\u6846\u5E95\u90E8\u5DE5\u5177\u680F\uFF1A\u5F39\u6027\u81EA\u9002\u5E94\uFF0C\u5F7B\u5E95\u675C\u7EDD\u6743\u9650\u9009\u62E9\u5668(Full access)\u4E0E\u6A21\u578B\u9009\u62E9\u5668\u91CD\u53E0\u78B0\u649E */
|
|
3906
3943
|
div[class*="uV2eYG_row"] {
|
|
3907
3944
|
display: flex !important;
|
package/client/index.js
CHANGED
|
@@ -2597,18 +2597,28 @@ function BridgePanel({ rpcCall }) {
|
|
|
2597
2597
|
|
|
2598
2598
|
const loadInFlightRef = React.useRef(false);
|
|
2599
2599
|
const loadSeqRef = React.useRef(0);
|
|
2600
|
+
// 兜底超时:RPC 若一直不返回(连接打不开/宿主未响应),强制结束「加载中」,
|
|
2601
|
+
// 释放 in-flight 锁并提示重试,避免面板无限卡在加载态
|
|
2602
|
+
const LOAD_TIMEOUT_MS = 15000;
|
|
2600
2603
|
const load = React.useCallback(async (quiet = false) => {
|
|
2601
2604
|
if (loadInFlightRef.current) return;
|
|
2602
2605
|
loadInFlightRef.current = true;
|
|
2603
2606
|
const currentSeq = ++loadSeqRef.current;
|
|
2607
|
+
const timedOut = { done: false };
|
|
2604
2608
|
try {
|
|
2605
|
-
const
|
|
2609
|
+
const result = await Promise.race([
|
|
2610
|
+
authRpcCall(BRIDGE_ENDPOINTS.getStatus, {}),
|
|
2611
|
+
new Promise((resolve) => {
|
|
2612
|
+
setTimeout(() => { timedOut.done = true; resolve(null); }, LOAD_TIMEOUT_MS);
|
|
2613
|
+
}),
|
|
2614
|
+
]);
|
|
2615
|
+
if (timedOut.done) throw new Error('加载超时(宿主连接可能在切换或未建立)。请点击「🔄 重试」刷新。');
|
|
2606
2616
|
if (currentSeq !== loadSeqRef.current) return;
|
|
2607
|
-
if (!
|
|
2608
|
-
setStatus(
|
|
2617
|
+
if (!result?.ok) throw new Error(result?.error?.message ?? 'RPC failed');
|
|
2618
|
+
setStatus(result.value);
|
|
2609
2619
|
if (!quiet) setErr(null);
|
|
2610
2620
|
} catch (e) {
|
|
2611
|
-
if (currentSeq === loadSeqRef.current) setErr(e.message);
|
|
2621
|
+
if (currentSeq === loadSeqRef.current) setErr(e.message || '加载失败');
|
|
2612
2622
|
} finally {
|
|
2613
2623
|
loadInFlightRef.current = false;
|
|
2614
2624
|
}
|
|
@@ -2977,6 +2987,11 @@ function BridgePanel({ rpcCall }) {
|
|
|
2977
2987
|
},
|
|
2978
2988
|
},
|
|
2979
2989
|
React.createElement('span', { style: { flex: '1 1 auto' } }, err),
|
|
2990
|
+
!isInterceptionErr && React.createElement('button', {
|
|
2991
|
+
type: 'button',
|
|
2992
|
+
style: { ...s.btnGhost, height: 26, fontSize: 12, padding: '0 10px', flexShrink: 0 },
|
|
2993
|
+
onClick: () => load(),
|
|
2994
|
+
}, '🔄 重试'),
|
|
2980
2995
|
isInterceptionErr && React.createElement('button', {
|
|
2981
2996
|
type: 'button',
|
|
2982
2997
|
style: { ...s.btnPri, background: '#dc2626', color: '#ffffff', height: 26, fontSize: 12, padding: '0 10px', flexShrink: 0 },
|
|
@@ -3500,6 +3515,27 @@ function injectMobileStyles() {
|
|
|
3500
3515
|
background: var(--dsw-alias-bg-layer-2, #f4f4f7) !important;
|
|
3501
3516
|
}
|
|
3502
3517
|
|
|
3518
|
+
/* 输入框横向不溢出:卡片及其缩容器最大宽度不超过视口,内部编辑器可收缩、长内容自动折行 */
|
|
3519
|
+
div[class*="uV2eYG_scrollBody"] {
|
|
3520
|
+
max-width: 100vw !important;
|
|
3521
|
+
overflow-x: hidden !important;
|
|
3522
|
+
}
|
|
3523
|
+
div[class*="uV2eYG_card"] {
|
|
3524
|
+
width: 100% !important;
|
|
3525
|
+
max-width: 100% !important;
|
|
3526
|
+
min-width: 0 !important;
|
|
3527
|
+
box-sizing: border-box !important;
|
|
3528
|
+
}
|
|
3529
|
+
div[class*="uV2eYG_card"] div,
|
|
3530
|
+
div[class*="uV2eYG_card"] textarea,
|
|
3531
|
+
div[class*="uV2eYG_card"] [contenteditable="true"] {
|
|
3532
|
+
max-width: 100% !important;
|
|
3533
|
+
min-width: 0 !important;
|
|
3534
|
+
overflow-wrap: anywhere !important;
|
|
3535
|
+
word-break: break-word !important;
|
|
3536
|
+
box-sizing: border-box !important;
|
|
3537
|
+
}
|
|
3538
|
+
|
|
3503
3539
|
/* 输入框底部工具栏:弹性自适应,彻底杜绝权限选择器(Full access)与模型选择器重叠碰撞 */
|
|
3504
3540
|
div[class*="uV2eYG_row"] {
|
|
3505
3541
|
display: flex !important;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-bridge-gateway",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "以 dsh-bridge 为根基、融合 remote-gateway 能力的 DSH 远程访问网关:局域网 / Cloudflare 隧道 / 自建隧道之外,新增「公网直连网关」(0.0.0.0 监听 + 自带 HTTPS 自签证书 + 强制登录门禁),解决移动端外网直连操控电脑。",
|
|
5
5
|
"releaseNotes": "【dsh-bridge-gateway】以 dsh-bridge 为根基、融合 remote-gateway 能力的 DSH 远程访问网关\n• ➕ 公网访问区:隧道 / 直连网关 二选一,网关全部配置项可在界面配置\n• ➕ 直连网关:0.0.0.0:<端口> 自带 HTTPS(自签证书) + 强制 public_only 门禁,复用 AuthManager,链路打通到 DSH loopback\n• 📱 修复移动端选择模型时界面溢出屏幕的问题\n• 默认不启用,安装后原有局域网/隧道/IM 行为完全不变",
|
|
6
6
|
"type": "module",
|