@wenbin_wb/dsh-bridge 2.5.5 → 2.6.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.
Binary file
package/lib/index.js CHANGED
@@ -108,10 +108,52 @@ class QrCache {
108
108
  }
109
109
 
110
110
  /**
111
- * 非安全上下文(http://LAN-IP:端口)里浏览器没有 crypto.randomUUID,
112
- * DSH 连接层 mint RPC id 时会抛错,注入 polyfill 修复。
111
+ * PWA Web App Manifest 与 App 启动图标
113
112
  */
114
- const RANDOM_UUID_POLYFILL = `<script data-dsh-bridge-polyfill="1">!function(){try{if(self.crypto&&!self.crypto.randomUUID){self.crypto.randomUUID=function(){var b=new Uint8Array(16);self.crypto.getRandomValues(b);b[6]=b[6]&15|64;b[8]=b[8]&63|128;var h="";for(var i=0;i<16;i++){var x=b[i].toString(16);h+=(x.length<2?"0":"")+x;if(i===3||i===5||i===7||i===9)h+="-";}return h;}}}catch(e){}}();</script>`;
113
+ const PWA_MANIFEST = JSON.stringify({
114
+ name: 'DeepSeek Harness',
115
+ short_name: 'DSH',
116
+ description: 'DeepSeek Harness Remote & Mobile Workspace',
117
+ start_url: '/',
118
+ display: 'standalone',
119
+ background_color: '#181825',
120
+ theme_color: '#1e1e2e',
121
+ orientation: 'any',
122
+ icons: [
123
+ {
124
+ src: '/__dsh_bridge__/pwa-icon.svg',
125
+ sizes: 'any',
126
+ type: 'image/svg+xml',
127
+ purpose: 'any maskable'
128
+ }
129
+ ]
130
+ }, null, 2);
131
+
132
+ const PWA_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
133
+ <defs>
134
+ <linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%">
135
+ <stop offset="0%" stop-color="#4f6ef7"/>
136
+ <stop offset="100%" stop-color="#24388a"/>
137
+ </linearGradient>
138
+ </defs>
139
+ <rect width="512" height="512" rx="128" fill="url(#g)"/>
140
+ <path d="M150 170 C150 140, 362 140, 362 170 L362 330 C362 360, 150 360, 150 330 Z" fill="#ffffff" fill-opacity="0.12"/>
141
+ <circle cx="206" cy="220" r="28" fill="#ffffff"/>
142
+ <circle cx="306" cy="220" r="28" fill="#ffffff"/>
143
+ <path d="M200 290 Q256 340 312 290" stroke="#ffffff" stroke-width="24" stroke-linecap="round" fill="none"/>
144
+ <rect x="236" y="90" width="40" height="60" rx="10" fill="#ffffff"/>
145
+ <circle cx="256" cy="80" r="16" fill="#4f6ef7"/>
146
+ </svg>`;
147
+
148
+ const HTML_HEAD_INJECTIONS = `<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
149
+ <meta name="apple-mobile-web-app-capable" content="yes">
150
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
151
+ <meta name="apple-mobile-web-app-title" content="DSH">
152
+ <meta name="theme-color" content="#1e1e2e">
153
+ <link rel="manifest" href="/manifest.webmanifest">
154
+ <link rel="icon" type="image/svg+xml" href="/__dsh_bridge__/pwa-icon.svg">
155
+ <link rel="apple-touch-icon" href="/__dsh_bridge__/pwa-icon.svg">
156
+ <script data-dsh-bridge-polyfill="1">!function(){try{if(self.crypto&&!self.crypto.randomUUID){self.crypto.randomUUID=function(){var b=new Uint8Array(16);self.crypto.getRandomValues(b);b[6]=b[6]&15|64;b[8]=b[8]&63|128;var h="";for(var i=0;i<16;i++){var x=b[i].toString(16);h+=(x.length<2?"0":"")+x;if(i===3||i===5||i===7||i===9)h+="-";}return h;}}}catch(e){}}();</script>`;
115
157
  const INJECT_MARK = 'data-dsh-bridge-polyfill="1"';
116
158
 
117
159
  function isCompressed(headers) {
@@ -150,6 +192,18 @@ class ProxyServer {
150
192
  this.server = createServer((req, res) => {
151
193
  const pathname = (req.url || '/').split('?')[0].replace(/\/+$/, '') || '/';
152
194
 
195
+ // 0. PWA Web App Manifest 与 App 图标支持
196
+ if (pathname === '/manifest.webmanifest' || pathname === '/manifest.json') {
197
+ res.writeHead(200, { 'Content-Type': 'application/manifest+json; charset=utf-8', 'Access-Control-Allow-Origin': '*' });
198
+ res.end(PWA_MANIFEST);
199
+ return;
200
+ }
201
+ if (pathname === '/__dsh_bridge__/pwa-icon.svg' || pathname === '/apple-touch-icon.png') {
202
+ res.writeHead(200, { 'Content-Type': 'image/svg+xml; charset=utf-8', 'Access-Control-Allow-Origin': '*' });
203
+ res.end(PWA_ICON_SVG);
204
+ return;
205
+ }
206
+
153
207
  // 1. 处理登录 API: POST /__dsh_bridge__/login
154
208
  if (pathname === '/__dsh_bridge__/login' && req.method === 'POST') {
155
209
  const chunks = [];
@@ -289,7 +343,7 @@ class ProxyServer {
289
343
  proxyRes.on('end', () => {
290
344
  let html = Buffer.concat(chunks).toString('utf8');
291
345
  if (!html.includes(INJECT_MARK)) {
292
- html = html.replace(/<head[^>]*>/i, (m) => `${m}${RANDOM_UUID_POLYFILL}`);
346
+ html = html.replace(/<head[^>]*>/i, (m) => `${m}${HTML_HEAD_INJECTIONS}`);
293
347
  }
294
348
  const out = Buffer.from(html, 'utf8');
295
349
  const outHeaders = { ...proxyRes.headers };
@@ -584,14 +638,17 @@ class BridgeService {
584
638
  // 检查 npm 上是否有新版本(优先国内高速镜像 npmmirror,降级 npmjs 官方源)
585
639
  async checkVersion() {
586
640
  const fetchRegistry = (url, timeoutMs = 4000) => new Promise((resolve, reject) => {
587
- const req = httpsGet(url, { timeout: timeoutMs }, (res) => {
641
+ const req = httpsGet(url, { timeout: timeoutMs, headers: { 'User-Agent': 'dsh-bridge' } }, (res) => {
588
642
  if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`));
589
643
  const chunks = [];
590
644
  res.on('data', (c) => chunks.push(c));
591
645
  res.on('end', () => {
592
646
  try {
593
647
  const data = JSON.parse(Buffer.concat(chunks).toString());
594
- resolve(data.version ?? null);
648
+ resolve({
649
+ version: data.version ?? null,
650
+ releaseNotes: data.releaseNotes ?? data.description ?? null,
651
+ });
595
652
  } catch (e) {
596
653
  reject(e);
597
654
  }
@@ -602,9 +659,13 @@ class BridgeService {
602
659
  });
603
660
 
604
661
  try {
605
- const latest = await fetchRegistry('https://registry.npmmirror.com/@wenbin_wb/dsh-bridge/latest', 3500)
662
+ const latestData = await fetchRegistry('https://registry.npmmirror.com/@wenbin_wb/dsh-bridge/latest', 3500)
606
663
  .catch(() => fetchRegistry('https://registry.npmjs.org/@wenbin_wb/dsh-bridge/latest', 5000));
607
- return { current: VERSION, latest: latest ?? null };
664
+ return {
665
+ current: VERSION,
666
+ latest: latestData?.version ?? null,
667
+ releaseNotes: latestData?.releaseNotes ?? null,
668
+ };
608
669
  } catch (e) {
609
670
  return { current: VERSION, latest: null, error: e.message ?? '检查失败' };
610
671
  }
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@wenbin_wb/dsh-bridge",
3
- "version": "2.5.5",
3
+ "version": "2.6.0",
4
4
  "description": "手机扫码即可在移动端/公网继续用 DeepSeek Harness,人不在电脑前也能接着干。一键局域网二维码、Cloudflare 公网隧道、自建隧道与微信 / QQ / 飞书 / Telegram Bot(多工作区/会话持久化/媒体/卡片审批/流式输出),无需自己搭公网服务器。",
5
+ "releaseNotes": "【v2.6.0 移动端交互重构与长按菜单】\n• 📱 深度重构移动端触控交互,极简通透顶栏与大圆角输入胶囊\n• 🖐️ 侧边栏支持长按(Long Press)呼出操作菜单(重命名/分叉/归档),边缘滑动开闭抽屉\n• 🛠️ 彻底修复「运行中」等状态药丸徽标在手机屏幕下的换行问题\n• ⚡ 优化版本检查与升级提示,直观展示新版本更新内容亮点",
5
6
  "type": "module",
6
7
  "main": "lib/index.js",
7
8
  "exports": {