@qzsy/dsh-bridge 3.2.0 → 3.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # 更新日志
2
2
 
3
+ ## [v3.2.1] - 2026-11-02
4
+
5
+ ### 🐛 修复
6
+
7
+ - **网关发布不再掉线**:收到网关 `drain`(滚动重启)后不再停在「已断开」,在途请求结束后自动重连;此前每次网关发布都要人工点「连接」,长连接会一直停在离线。
8
+ - **npm 仓库地址**:`repository.url` 补 `git+` 前缀,符合 npm 规范写法。
9
+
10
+ ### ✨ 调整
11
+
12
+ - **网关卡片精简**:在线时只显示一行「网关:地址 + 新窗口打开」;掉线 / 连接中才展开状态徽标、可编辑地址与保存。
13
+
3
14
  ## [v3.2.0] - 2026-11-02
4
15
 
5
16
  ### ✨ 新增
package/client/client.js CHANGED
@@ -58,6 +58,8 @@ var zh = {
58
58
  title: "\u8FDC\u7A0B\u8BBF\u95EE",
59
59
  subtitle: "DSH \u8FDC\u7A0B\u96A7\u9053\u4E91 \xB7 \u5B98\u65B9\u5BA2\u6237\u7AEF",
60
60
  gateway: "SaaS \u7F51\u5173\u5730\u5740",
61
+ gatewayLabel: "\u7F51\u5173",
62
+ openInNewWindow: "\u65B0\u7A97\u53E3\u6253\u5F00",
61
63
  save: "\u4FDD\u5B58\u7F51\u5173",
62
64
  saved: "\u5DF2\u4FDD\u5B58",
63
65
  device: "\u8BBE\u5907",
@@ -123,6 +125,8 @@ var en = {
123
125
  title: "Remote Access",
124
126
  subtitle: "DSH Remote Tunnel Cloud \xB7 Official Client",
125
127
  gateway: "SaaS gateway URL",
128
+ gatewayLabel: "Gateway",
129
+ openInNewWindow: "Open in new window",
126
130
  save: "Save gateway",
127
131
  saved: "Saved",
128
132
  device: "Device",
@@ -543,6 +547,18 @@ function BridgePanel() {
543
547
  const openUrl = status?.openUrl ?? "";
544
548
  const passwordSet = Boolean(status?.access?.passwordSet);
545
549
  const stateText = connected ? t("ready") : phase === "connecting" || phase === "reconnecting" ? t("connecting") : t("offline");
550
+ const gatewayWebUrl = React.useMemo(() => {
551
+ const raw = String(status?.gatewayUrl || gatewayDraft || "").trim();
552
+ if (!raw) return "";
553
+ try {
554
+ const url = new URL(raw);
555
+ if (url.protocol === "wss:") url.protocol = "https:";
556
+ else if (url.protocol === "ws:") url.protocol = "http:";
557
+ return url.origin;
558
+ } catch {
559
+ return raw.replace(/\/+$/, "");
560
+ }
561
+ }, [status?.gatewayUrl, gatewayDraft]);
546
562
  return h(
547
563
  "div",
548
564
  { style: styles.wrap },
@@ -559,35 +575,55 @@ function BridgePanel() {
559
575
  onRefresh: () => setProfileTick((value) => value + 1),
560
576
  t
561
577
  }) : null,
578
+ // 网关卡片:在线时只留一行「网关:地址 + 新窗口打开」;掉线/连接中才展开
579
+ // 状态徽标与可编辑地址,避免正常状态下一屏塞满诊断信息。
562
580
  h(
563
581
  "div",
564
582
  { style: styles.card },
565
- h(
583
+ connected ? h(
566
584
  "div",
567
585
  { style: styles.row },
568
- h("span", { style: styles.badge }, `${t("status")}: ${stateText}`),
569
- h("span", { style: styles.badge }, bound ? `${t("device")}: ${status?.device?.idMasked ?? ""}` : t("notBound")),
570
- status?.protocol ? h("span", { style: styles.badge }, `protocol v${status.protocol}`) : null
571
- ),
572
- h(
573
- "div",
574
- { style: { marginTop: 10 } },
575
- h("span", { style: styles.label }, t("gateway")),
586
+ h("span", { style: { ...styles.muted, whiteSpace: "nowrap" } }, `${t("gatewayLabel")}\uFF1A`),
587
+ h("a", {
588
+ href: gatewayWebUrl,
589
+ target: "_blank",
590
+ rel: "noopener noreferrer",
591
+ style: { flex: 1, minWidth: 180, fontSize: 13, lineHeight: 1.6, wordBreak: "break-all", color: "inherit" }
592
+ }, gatewayWebUrl),
593
+ h("a", {
594
+ href: gatewayWebUrl,
595
+ target: "_blank",
596
+ rel: "noopener noreferrer",
597
+ style: { ...styles.btn, textDecoration: "none", whiteSpace: "nowrap" }
598
+ }, t("openInNewWindow"))
599
+ ) : [
576
600
  h(
577
601
  "div",
578
602
  { style: styles.row },
579
- h("input", {
580
- style: styles.input,
581
- value: gatewayDraft,
582
- placeholder: "wss://dsh.b.nps.qzsyzn.com/_gw/connect",
583
- onChange: (e) => setGatewayDraft(e.target.value)
584
- }),
585
- h("button", { style: styles.btnPrimary, disabled: busy === "gateway" || !gatewayDraft, onClick: saveGateway }, t("save"))
586
- )
587
- ),
588
- !adminToken ? h("div", { style: { ...styles.muted, marginTop: 8 } }, t("adminLocalOnly")) : null,
589
- error ? h("div", { style: { ...styles.error, marginTop: 10 } }, `${t("lastError")}: ${error}`) : null,
590
- notice ? h("div", { style: { ...styles.muted, marginTop: 8 } }, notice) : null
603
+ h("span", { style: styles.badge }, `${t("status")}: ${stateText}`),
604
+ h("span", { style: styles.badge }, bound ? `${t("device")}: ${status?.device?.idMasked ?? ""}` : t("notBound")),
605
+ status?.protocol ? h("span", { style: styles.badge }, `protocol v${status.protocol}`) : null
606
+ ),
607
+ h(
608
+ "div",
609
+ { style: { marginTop: 10 } },
610
+ h("span", { style: styles.label }, t("gateway")),
611
+ h(
612
+ "div",
613
+ { style: styles.row },
614
+ h("input", {
615
+ style: styles.input,
616
+ value: gatewayDraft,
617
+ placeholder: "wss://dsh.b.nps.qzsyzn.com/_gw/connect",
618
+ onChange: (e) => setGatewayDraft(e.target.value)
619
+ }),
620
+ h("button", { style: styles.btnPrimary, disabled: busy === "gateway" || !gatewayDraft, onClick: saveGateway }, t("save"))
621
+ )
622
+ ),
623
+ !adminToken ? h("div", { style: { ...styles.muted, marginTop: 8 } }, t("adminLocalOnly")) : null,
624
+ error ? h("div", { style: { ...styles.error, marginTop: 10 } }, `${t("lastError")}: ${error}`) : null,
625
+ notice ? h("div", { style: { ...styles.muted, marginTop: 8 } }, notice) : null
626
+ ]
591
627
  ),
592
628
  h(
593
629
  "div",
package/client/index.js CHANGED
@@ -305,6 +305,19 @@ function BridgePanel() {
305
305
  const openUrl = status?.openUrl ?? '';
306
306
  const passwordSet = Boolean(status?.access?.passwordSet);
307
307
  const stateText = connected ? t('ready') : (phase === 'connecting' || phase === 'reconnecting' ? t('connecting') : t('offline'));
308
+ // 在线态只展示一行「网关:地址」:把 wss://host/_gw/connect 归一成可点开的 web 地址。
309
+ const gatewayWebUrl = React.useMemo(() => {
310
+ const raw = String(status?.gatewayUrl || gatewayDraft || '').trim();
311
+ if (!raw) return '';
312
+ try {
313
+ const url = new URL(raw);
314
+ if (url.protocol === 'wss:') url.protocol = 'https:';
315
+ else if (url.protocol === 'ws:') url.protocol = 'http:';
316
+ return url.origin;
317
+ } catch {
318
+ return raw.replace(/\/+$/, '');
319
+ }
320
+ }, [status?.gatewayUrl, gatewayDraft]);
308
321
 
309
322
  return h('div', { style: styles.wrap },
310
323
  h('div', { style: { marginBottom: 12 } },
@@ -320,27 +333,47 @@ function BridgePanel() {
320
333
  t,
321
334
  }) : null,
322
335
 
336
+ // 网关卡片:在线时只留一行「网关:地址 + 新窗口打开」;掉线/连接中才展开
337
+ // 状态徽标与可编辑地址,避免正常状态下一屏塞满诊断信息。
323
338
  h('div', { style: styles.card },
324
- h('div', { style: styles.row },
325
- h('span', { style: styles.badge }, `${t('status')}: ${stateText}`),
326
- h('span', { style: styles.badge }, bound ? `${t('device')}: ${status?.device?.idMasked ?? ''}` : t('notBound')),
327
- status?.protocol ? h('span', { style: styles.badge }, `protocol v${status.protocol}`) : null,
328
- ),
329
- h('div', { style: { marginTop: 10 } },
330
- h('span', { style: styles.label }, t('gateway')),
331
- h('div', { style: styles.row },
332
- h('input', {
333
- style: styles.input,
334
- value: gatewayDraft,
335
- placeholder: 'wss://dsh.b.nps.qzsyzn.com/_gw/connect',
336
- onChange: (e) => setGatewayDraft(e.target.value),
337
- }),
338
- h('button', { style: styles.btnPrimary, disabled: busy === 'gateway' || !gatewayDraft, onClick: saveGateway }, t('save')),
339
- ),
340
- ),
341
- !adminToken ? h('div', { style: { ...styles.muted, marginTop: 8 } }, t('adminLocalOnly')) : null,
342
- error ? h('div', { style: { ...styles.error, marginTop: 10 } }, `${t('lastError')}: ${error}`) : null,
343
- notice ? h('div', { style: { ...styles.muted, marginTop: 8 } }, notice) : null,
339
+ connected
340
+ ? h('div', { style: styles.row },
341
+ h('span', { style: { ...styles.muted, whiteSpace: 'nowrap' } }, `${t('gatewayLabel')}:`),
342
+ h('a', {
343
+ href: gatewayWebUrl,
344
+ target: '_blank',
345
+ rel: 'noopener noreferrer',
346
+ style: { flex: 1, minWidth: 180, fontSize: 13, lineHeight: 1.6, wordBreak: 'break-all', color: 'inherit' },
347
+ }, gatewayWebUrl),
348
+ h('a', {
349
+ href: gatewayWebUrl,
350
+ target: '_blank',
351
+ rel: 'noopener noreferrer',
352
+ style: { ...styles.btn, textDecoration: 'none', whiteSpace: 'nowrap' },
353
+ }, t('openInNewWindow')),
354
+ )
355
+ : [
356
+ h('div', { style: styles.row },
357
+ h('span', { style: styles.badge }, `${t('status')}: ${stateText}`),
358
+ h('span', { style: styles.badge }, bound ? `${t('device')}: ${status?.device?.idMasked ?? ''}` : t('notBound')),
359
+ status?.protocol ? h('span', { style: styles.badge }, `protocol v${status.protocol}`) : null,
360
+ ),
361
+ h('div', { style: { marginTop: 10 } },
362
+ h('span', { style: styles.label }, t('gateway')),
363
+ h('div', { style: styles.row },
364
+ h('input', {
365
+ style: styles.input,
366
+ value: gatewayDraft,
367
+ placeholder: 'wss://dsh.b.nps.qzsyzn.com/_gw/connect',
368
+ onChange: (e) => setGatewayDraft(e.target.value),
369
+ }),
370
+ h('button', { style: styles.btnPrimary, disabled: busy === 'gateway' || !gatewayDraft, onClick: saveGateway }, t('save')),
371
+ ),
372
+ ),
373
+ !adminToken ? h('div', { style: { ...styles.muted, marginTop: 8 } }, t('adminLocalOnly')) : null,
374
+ error ? h('div', { style: { ...styles.error, marginTop: 10 } }, `${t('lastError')}: ${error}`) : null,
375
+ notice ? h('div', { style: { ...styles.muted, marginTop: 8 } }, notice) : null,
376
+ ],
344
377
  ),
345
378
 
346
379
  h('div', { style: styles.card },
@@ -3,6 +3,8 @@ export const zh = {
3
3
  title: '远程访问',
4
4
  subtitle: 'DSH 远程隧道云 · 官方客户端',
5
5
  gateway: 'SaaS 网关地址',
6
+ gatewayLabel: '网关',
7
+ openInNewWindow: '新窗口打开',
6
8
  save: '保存网关',
7
9
  saved: '已保存',
8
10
  device: '设备',
@@ -69,6 +71,8 @@ export const en = {
69
71
  title: 'Remote Access',
70
72
  subtitle: 'DSH Remote Tunnel Cloud · Official Client',
71
73
  gateway: 'SaaS gateway URL',
74
+ gatewayLabel: 'Gateway',
75
+ openInNewWindow: 'Open in new window',
72
76
  save: 'Save gateway',
73
77
  saved: 'Saved',
74
78
  device: 'Device',