dsh-pocket 1.2.0 → 1.3.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.
- package/client/client.js +20 -12
- package/client/index.jsx +32 -13
- package/package.json +1 -1
package/client/client.js
CHANGED
|
@@ -1282,14 +1282,16 @@ function mobileApply(ctx) {
|
|
|
1282
1282
|
var name = "dsh-pocket";
|
|
1283
1283
|
var inject = ["slots", "connection", "layout", "locale", "sessionLogDownload"];
|
|
1284
1284
|
var styles = {
|
|
1285
|
-
card: { background: "var(--dsw-alias-bg-layer-1,#fff)", border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", borderRadius: 12, padding: "
|
|
1286
|
-
block: { borderTop: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", marginTop:
|
|
1287
|
-
muted: { color: "var(--dsw-alias-label-tertiary,#8b93a1)", fontSize: 12 },
|
|
1288
|
-
code: { fontFamily: "ui-monospace,Menlo,monospace", fontSize: 12, wordBreak: "break-all", margin: "
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1285
|
+
card: { background: "var(--dsw-alias-bg-layer-1,#fff)", border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", borderRadius: 12, padding: "16px 20px", maxWidth: 480 },
|
|
1286
|
+
block: { borderTop: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", marginTop: 16, paddingTop: 16 },
|
|
1287
|
+
muted: { color: "var(--dsw-alias-label-tertiary,#8b93a1)", fontSize: 12, lineHeight: 1.5 },
|
|
1288
|
+
code: { fontFamily: "ui-monospace,Menlo,monospace", fontSize: 12, wordBreak: "break-all", margin: "6px 0 10px", color: "var(--dsw-alias-label-primary,inherit)" },
|
|
1289
|
+
// 主按钮:官方 md 胶囊形(36px)
|
|
1290
|
+
primary: { font: "inherit", cursor: "pointer", border: "none", background: "var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))", color: "#fff", height: 36, padding: "0 16px", borderRadius: 999, fontSize: 13, fontWeight: 500, display: "inline-flex", alignItems: "center", justifyContent: "center" },
|
|
1291
|
+
// 次级按钮:官方 outline/ghost 胶囊形
|
|
1292
|
+
btn: { font: "inherit", cursor: "pointer", border: "1px solid var(--dsw-alias-button-ghost-active-border, var(--dsw-alias-border-l2,#d1d5db))", background: "var(--dsw-alias-bg-layer-1,#fff)", color: "var(--dsw-alias-label-primary,inherit)", height: 36, padding: "0 16px", borderRadius: 999, fontSize: 13, display: "inline-flex", alignItems: "center", justifyContent: "center" },
|
|
1293
|
+
qr: { width: 220, height: 220, borderRadius: 10, border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", margin: "8px 0" },
|
|
1294
|
+
warn: { color: "var(--dsw-alias-state-warn-primary,#b45309)", fontSize: 12, lineHeight: 1.5 }
|
|
1293
1295
|
};
|
|
1294
1296
|
function PocketSettingsTab({ rpcCall }) {
|
|
1295
1297
|
const [status, setStatus] = (0, import_react2.useState)(null);
|
|
@@ -1298,6 +1300,12 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1298
1300
|
const [tunnelState, setTunnelState] = (0, import_react2.useState)(null);
|
|
1299
1301
|
const [restartNotice, setRestartNotice] = (0, import_react2.useState)(false);
|
|
1300
1302
|
const [updateInfo, setUpdateInfo] = (0, import_react2.useState)(null);
|
|
1303
|
+
const [now, setNow] = (0, import_react2.useState)(Date.now());
|
|
1304
|
+
(0, import_react2.useEffect)(() => {
|
|
1305
|
+
const t = setInterval(() => setNow(Date.now()), 1e3);
|
|
1306
|
+
return () => clearInterval(t);
|
|
1307
|
+
}, []);
|
|
1308
|
+
const elapsed = (startedAt) => startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)) : 0;
|
|
1301
1309
|
const call = async (endpoint, payload) => {
|
|
1302
1310
|
const res = await rpcCall(endpoint, payload);
|
|
1303
1311
|
if (!res?.ok) throw new Error(res?.error?.message ?? "RPC failed");
|
|
@@ -1356,7 +1364,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1356
1364
|
};
|
|
1357
1365
|
}, []);
|
|
1358
1366
|
const restartPocket = async () => {
|
|
1359
|
-
setUpdateInfo((u) => ({ ...u, restarting: true }));
|
|
1367
|
+
setUpdateInfo((u) => ({ ...u, restarting: true, startedAt: Date.now() }));
|
|
1360
1368
|
try {
|
|
1361
1369
|
await Promise.race([
|
|
1362
1370
|
call(POCKET_ENDPOINTS.restart, {}),
|
|
@@ -1373,7 +1381,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1373
1381
|
}
|
|
1374
1382
|
};
|
|
1375
1383
|
const runUpdate = async () => {
|
|
1376
|
-
setUpdateInfo((u) => ({ ...u, updating: true, result: null }));
|
|
1384
|
+
setUpdateInfo((u) => ({ ...u, updating: true, result: null, startedAt: Date.now() }));
|
|
1377
1385
|
try {
|
|
1378
1386
|
const r = await call(POCKET_ENDPOINTS.update, {});
|
|
1379
1387
|
setUpdateInfo((u) => ({
|
|
@@ -1458,7 +1466,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1458
1466
|
(0, import_react2.createElement)(
|
|
1459
1467
|
"div",
|
|
1460
1468
|
{ style: styles.muted, marginTop: 4 },
|
|
1461
|
-
updateInfo.result === "ok" ? updateInfo.autoRestart ? "\u2705 \u5DF2\u66F4\u65B0\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u542F\u751F\u6548\uFF0C\u8BF7\u7A0D\u5019\u5237\u65B0 | updated \u2014 restarting automatically, refresh shortly" : "\u2705 \u5DF2\u66F4\u65B0\uFF0C\u91CD\u542F dsh web \u751F\u6548 | updated \u2014 restart dsh web" : updateInfo.result === "fail" ? `\u274C \u5931\u8D25\uFF1A${updateInfo.output || "\u672A\u77E5"}\uFF08\u624B\u52A8\u66F4\u65B0\uFF1Adsh plugin --profile web update dsh-pocket --latest -w\uFF09` : `\u5F53\u524D v${updateInfo.current} \u2192 \u6700\u65B0 v${updateInfo.latest}`
|
|
1469
|
+
updateInfo.updating ? `\u23F3 \u66F4\u65B0\u4E2D\uFF08\u901A\u5E38 1-2 \u5206\u949F\uFF09\xB7 \u5DF2\u7B49\u5F85 ${elapsed(updateInfo.startedAt)} \u79D2 | updating (usually 1-2 min) \xB7 ${elapsed(updateInfo.startedAt)}s` : updateInfo.restarting ? `\u23F3 \u6B63\u5728\u91CD\u542F\u751F\u6548\uFF08\u901A\u5E38 10-30 \u79D2\uFF09\xB7 \u5DF2\u7B49\u5F85 ${elapsed(updateInfo.startedAt)} \u79D2 | restarting (usually 10-30s) \xB7 ${elapsed(updateInfo.startedAt)}s` : updateInfo.result === "ok" ? updateInfo.autoRestart ? "\u2705 \u5DF2\u66F4\u65B0\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u542F\u751F\u6548\uFF0C\u8BF7\u7A0D\u5019\u5237\u65B0 | updated \u2014 restarting automatically, refresh shortly" : "\u2705 \u5DF2\u66F4\u65B0\uFF0C\u91CD\u542F dsh web \u751F\u6548 | updated \u2014 restart dsh web" : updateInfo.result === "fail" ? `\u274C \u5931\u8D25\uFF1A${updateInfo.output || "\u672A\u77E5"}\uFF08\u624B\u52A8\u66F4\u65B0\uFF1Adsh plugin --profile web update dsh-pocket --latest -w\uFF09` : `\u5F53\u524D v${updateInfo.current} \u2192 \u6700\u65B0 v${updateInfo.latest}`
|
|
1462
1470
|
)
|
|
1463
1471
|
) : null,
|
|
1464
1472
|
// 局域网
|
|
@@ -1494,7 +1502,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1494
1502
|
tunnelStarting ? (0, import_react2.createElement)(
|
|
1495
1503
|
"div",
|
|
1496
1504
|
{ style: { marginTop: 8, fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)" } },
|
|
1497
|
-
`\u23F3
|
|
1505
|
+
tunnelPhase === "downloading" ? `\u23F3 \u4E0B\u8F7D cloudflared\uFF08\u9996\u6B21\u7EA6 20-50MB\uFF0C\u901A\u5E38 1-2 \u5206\u949F\uFF1B\u4E4B\u540E\u79D2\u5F00\uFF09\xB7 \u5DF2\u7B49\u5F85 ${elapsed(tunnelStateStarted)} \u79D2` : `\u23F3 \u8FDE\u63A5 Cloudflare \u8FB9\u7F18\uFF08\u901A\u5E38 5-30 \u79D2\uFF09\xB7 \u5DF2\u7B49\u5F85 ${elapsed(tunnelStateStarted)} \u79D2${elapsed(tunnelStateStarted) > 30 ? " \u2014 \u6709\u70B9\u4E45\uFF1F\u68C0\u67E5\u662F\u5426\u5F00\u7740\u4EE3\u7406/VPN\uFF08Clash TUN \u7B49\uFF09" : ""}`
|
|
1498
1506
|
) : tunnelPhase === "error" ? (0, import_react2.createElement)(
|
|
1499
1507
|
"div",
|
|
1500
1508
|
{ style: { marginTop: 8, fontSize: 12, color: "var(--dsw-alias-state-error-primary,#dc2626)" } },
|
package/client/index.jsx
CHANGED
|
@@ -15,15 +15,20 @@ import { mobileApply } from './mobile/mobile-apply.tsx';
|
|
|
15
15
|
const name = 'dsh-pocket';
|
|
16
16
|
const inject = ['slots', 'connection', 'layout', 'locale', 'sessionLogDownload'];
|
|
17
17
|
|
|
18
|
+
// 官方 DeepSeek Harness 设计系统(dsh-client-ui-theme design-platform.css):
|
|
19
|
+
// 按钮 md=36px 胶囊形 / sm=28px;品牌色 --dsw-alias-brand-primary;
|
|
20
|
+
// hover 走 --dsw-alias-button-*-hover;间距 4px 栅格;正文 13px。
|
|
18
21
|
const styles = {
|
|
19
|
-
card: { background: 'var(--dsw-alias-bg-layer-1,#fff)', border: '1px solid var(--dsw-alias-border-l2,#e5e7eb)', borderRadius: 12, padding: '
|
|
20
|
-
block: { borderTop: '1px solid var(--dsw-alias-border-l2,#e5e7eb)', marginTop:
|
|
21
|
-
muted: { color: 'var(--dsw-alias-label-tertiary,#8b93a1)', fontSize: 12 },
|
|
22
|
-
code: { fontFamily: 'ui-monospace,Menlo,monospace', fontSize: 12, wordBreak: 'break-all', margin: '
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
card: { background: 'var(--dsw-alias-bg-layer-1,#fff)', border: '1px solid var(--dsw-alias-border-l2,#e5e7eb)', borderRadius: 12, padding: '16px 20px', maxWidth: 480 },
|
|
23
|
+
block: { borderTop: '1px solid var(--dsw-alias-border-l2,#e5e7eb)', marginTop: 16, paddingTop: 16 },
|
|
24
|
+
muted: { color: 'var(--dsw-alias-label-tertiary,#8b93a1)', fontSize: 12, lineHeight: 1.5 },
|
|
25
|
+
code: { fontFamily: 'ui-monospace,Menlo,monospace', fontSize: 12, wordBreak: 'break-all', margin: '6px 0 10px', color: 'var(--dsw-alias-label-primary,inherit)' },
|
|
26
|
+
// 主按钮:官方 md 胶囊形(36px)
|
|
27
|
+
primary: { font: 'inherit', cursor: 'pointer', border: 'none', background: 'var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))', color: '#fff', height: 36, padding: '0 16px', borderRadius: 999, fontSize: 13, fontWeight: 500, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' },
|
|
28
|
+
// 次级按钮:官方 outline/ghost 胶囊形
|
|
29
|
+
btn: { font: 'inherit', cursor: 'pointer', border: '1px solid var(--dsw-alias-button-ghost-active-border, var(--dsw-alias-border-l2,#d1d5db))', background: 'var(--dsw-alias-bg-layer-1,#fff)', color: 'var(--dsw-alias-label-primary,inherit)', height: 36, padding: '0 16px', borderRadius: 999, fontSize: 13, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' },
|
|
30
|
+
qr: { width: 220, height: 220, borderRadius: 10, border: '1px solid var(--dsw-alias-border-l2,#e5e7eb)', margin: '8px 0' },
|
|
31
|
+
warn: { color: 'var(--dsw-alias-state-warn-primary,#b45309)', fontSize: 12, lineHeight: 1.5 },
|
|
27
32
|
};
|
|
28
33
|
|
|
29
34
|
function PocketSettingsTab({ rpcCall }) {
|
|
@@ -32,7 +37,15 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
32
37
|
const [error, setError] = useState(null);
|
|
33
38
|
const [tunnelState, setTunnelState] = useState(null); // 隧道进度 {phase, detail, startedAt}
|
|
34
39
|
const [restartNotice, setRestartNotice] = useState(false); // 重启后提示
|
|
35
|
-
const [updateInfo, setUpdateInfo] = useState(null); // { current, latest, updating, result } | null
|
|
40
|
+
const [updateInfo, setUpdateInfo] = useState(null); // { current, latest, updating, result, startedAt } | null
|
|
41
|
+
const [now, setNow] = useState(Date.now()); // 每秒 tick,驱动倒计时
|
|
42
|
+
|
|
43
|
+
// 进行中操作的「已等待 X 秒」倒计时
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const t = setInterval(() => setNow(Date.now()), 1000);
|
|
46
|
+
return () => clearInterval(t);
|
|
47
|
+
}, []);
|
|
48
|
+
const elapsed = (startedAt) => (startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1000)) : 0);
|
|
36
49
|
|
|
37
50
|
const call = async (endpoint, payload) => {
|
|
38
51
|
const res = await rpcCall(endpoint, payload);
|
|
@@ -92,7 +105,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
92
105
|
|
|
93
106
|
// 重启宿主(更新生效必需:刷新页面不会重载服务端代码)
|
|
94
107
|
const restartPocket = async () => {
|
|
95
|
-
setUpdateInfo((u) => ({ ...u, restarting: true }));
|
|
108
|
+
setUpdateInfo((u) => ({ ...u, restarting: true, startedAt: Date.now() }));
|
|
96
109
|
try {
|
|
97
110
|
// 宿主 500ms 后自杀,RPC 响应可能来不及送达 → 3 秒超时兜底,别让按钮永远卡「重启中…」
|
|
98
111
|
await Promise.race([
|
|
@@ -113,7 +126,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
113
126
|
|
|
114
127
|
// 一键更新:调宿主 dsh plugin update(成功后宿主自动重启生效,用户只点一次)
|
|
115
128
|
const runUpdate = async () => {
|
|
116
|
-
setUpdateInfo((u) => ({ ...u, updating: true, result: null }));
|
|
129
|
+
setUpdateInfo((u) => ({ ...u, updating: true, result: null, startedAt: Date.now() }));
|
|
117
130
|
try {
|
|
118
131
|
const r = await call(POCKET_ENDPOINTS.update, {});
|
|
119
132
|
setUpdateInfo((u) => ({
|
|
@@ -187,7 +200,11 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
187
200
|
: h('button', { style: styles.primary, onClick: restartPocket, disabled: updateInfo.restarting }, updateInfo.restarting ? '重启中…' : '🔄 重启 dsh web 生效 | Restart now'),
|
|
188
201
|
),
|
|
189
202
|
h('div', { style: styles.muted, marginTop: 4 },
|
|
190
|
-
updateInfo.
|
|
203
|
+
updateInfo.updating
|
|
204
|
+
? `⏳ 更新中(通常 1-2 分钟)· 已等待 ${elapsed(updateInfo.startedAt)} 秒 | updating (usually 1-2 min) · ${elapsed(updateInfo.startedAt)}s`
|
|
205
|
+
: updateInfo.restarting
|
|
206
|
+
? `⏳ 正在重启生效(通常 10-30 秒)· 已等待 ${elapsed(updateInfo.startedAt)} 秒 | restarting (usually 10-30s) · ${elapsed(updateInfo.startedAt)}s`
|
|
207
|
+
: updateInfo.result === 'ok'
|
|
191
208
|
? (updateInfo.autoRestart ? '✅ 已更新,正在自动重启生效,请稍候刷新 | updated — restarting automatically, refresh shortly'
|
|
192
209
|
: '✅ 已更新,重启 dsh web 生效 | updated — restart dsh web')
|
|
193
210
|
: updateInfo.result === 'fail' ? `❌ 失败:${updateInfo.output || '未知'}(手动更新:dsh plugin --profile web update dsh-pocket --latest -w)`
|
|
@@ -221,7 +238,9 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
221
238
|
h('button', { style: styles.primary, onClick: startTunnel, disabled: busy || tunnelStarting }, busy ? '开启中…' : '开启公网访问 | Enable anywhere'),
|
|
222
239
|
tunnelStarting
|
|
223
240
|
? h('div', { style: { marginTop: 8, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)' } },
|
|
224
|
-
|
|
241
|
+
tunnelPhase === 'downloading'
|
|
242
|
+
? `⏳ 下载 cloudflared(首次约 20-50MB,通常 1-2 分钟;之后秒开)· 已等待 ${elapsed(tunnelStateStarted)} 秒`
|
|
243
|
+
: `⏳ 连接 Cloudflare 边缘(通常 5-30 秒)· 已等待 ${elapsed(tunnelStateStarted)} 秒${elapsed(tunnelStateStarted) > 30 ? ' — 有点久?检查是否开着代理/VPN(Clash TUN 等)' : ''}`)
|
|
225
244
|
: tunnelPhase === 'error'
|
|
226
245
|
? h('div', { style: { marginTop: 8, fontSize: 12, color: 'var(--dsw-alias-state-error-primary,#dc2626)' } },
|
|
227
246
|
`❌ 开启失败:${tunnelStateDetail || '未知错误 | failed'}(可重试;若是代理/VPN 问题见 README 排障)`)
|
package/package.json
CHANGED