dsh-pocket 1.0.10 → 1.0.11
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/api.js +1 -0
- package/client/client.js +25 -6
- package/client/index.jsx +20 -3
- package/lib/index.js +2 -0
- package/lib/restart.js +45 -0
- package/lib/web-rpc.js +6 -1
- package/package.json +1 -1
package/client/api.js
CHANGED
package/client/client.js
CHANGED
|
@@ -44,7 +44,8 @@ var POCKET_ENDPOINTS = Object.freeze({
|
|
|
44
44
|
pushStatus: "push.status",
|
|
45
45
|
pushSetEnabled: "push.setEnabled",
|
|
46
46
|
version: "pocket.version",
|
|
47
|
-
update: "pocket.update"
|
|
47
|
+
update: "pocket.update",
|
|
48
|
+
restart: "pocket.restart"
|
|
48
49
|
});
|
|
49
50
|
function compareVersions(a, b) {
|
|
50
51
|
const pa = String(a).replace(/^v/, "").split(".");
|
|
@@ -1346,6 +1347,14 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1346
1347
|
alive = false;
|
|
1347
1348
|
};
|
|
1348
1349
|
}, []);
|
|
1350
|
+
const restartPocket = async () => {
|
|
1351
|
+
setUpdateInfo((u) => ({ ...u, restarting: true }));
|
|
1352
|
+
try {
|
|
1353
|
+
await call(POCKET_ENDPOINTS.restart, {});
|
|
1354
|
+
} catch (err) {
|
|
1355
|
+
setUpdateInfo((u) => ({ ...u, restarting: false, result: "fail", output: err.message }));
|
|
1356
|
+
}
|
|
1357
|
+
};
|
|
1349
1358
|
const runUpdate = async () => {
|
|
1350
1359
|
setUpdateInfo((u) => ({ ...u, updating: true, result: null }));
|
|
1351
1360
|
try {
|
|
@@ -1414,9 +1423,9 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1414
1423
|
(0, import_react2.createElement)("div", { style: styles.muted }, "\u624B\u673A\u626B\u7801\u6253\u5F00\u7684\u5C31\u662F\u7535\u8111\u4E0A\u7684\u8FD9\u4E2A\u754C\u9762\uFF0C\u5B9E\u65F6\u540C\u6B65 | the phone shows this exact screen, live")
|
|
1415
1424
|
),
|
|
1416
1425
|
(0, import_react2.createElement)(
|
|
1417
|
-
"
|
|
1418
|
-
{
|
|
1419
|
-
"\u5F00\u53D1\u8005\uFF1A\u7A0B\u5E8F\u5458\u5C11\u5317\u6668
|
|
1426
|
+
"div",
|
|
1427
|
+
{ style: { fontSize: 12, color: "var(--dsw-alias-label-tertiary,#8b93a1)", whiteSpace: "nowrap" } },
|
|
1428
|
+
"\u5F00\u53D1\u8005\uFF1A\u7A0B\u5E8F\u5458\u5C11\u5317\u6668"
|
|
1420
1429
|
)
|
|
1421
1430
|
),
|
|
1422
1431
|
// 更新提示
|
|
@@ -1427,7 +1436,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1427
1436
|
"div",
|
|
1428
1437
|
{ style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 } },
|
|
1429
1438
|
(0, import_react2.createElement)("div", { style: { fontWeight: 600, fontSize: 13 } }, `\u{1F4E6} \u65B0\u7248\u672C v${updateInfo.latest} | Update available`),
|
|
1430
|
-
updateInfo.result !== "ok" ? (0, import_react2.createElement)("button", { style: styles.primary, onClick: runUpdate, disabled: updateInfo.updating }, updateInfo.updating ? "\u66F4\u65B0\u4E2D\u2026" : `\u66F4\u65B0\u5230 v${updateInfo.latest} | Update`) : (0, import_react2.createElement)("button", { style: styles.
|
|
1439
|
+
updateInfo.result !== "ok" ? (0, import_react2.createElement)("button", { style: styles.primary, onClick: runUpdate, disabled: updateInfo.updating }, updateInfo.updating ? "\u66F4\u65B0\u4E2D\u2026" : `\u66F4\u65B0\u5230 v${updateInfo.latest} | Update`) : (0, import_react2.createElement)("button", { style: styles.primary, onClick: restartPocket, disabled: updateInfo.restarting }, updateInfo.restarting ? "\u91CD\u542F\u4E2D\u2026" : "\u{1F504} \u91CD\u542F dsh web \u751F\u6548 | Restart now")
|
|
1431
1440
|
),
|
|
1432
1441
|
(0, import_react2.createElement)(
|
|
1433
1442
|
"div",
|
|
@@ -1487,7 +1496,17 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1487
1496
|
!pushEnabled ? "\u5DF2\u5173\u95ED\uFF1Aagent \u8DD1\u5B8C\u4E0D\u4F1A\u63A8\u9001 | off: no notifications" : pushState === "on" ? "\u5DF2\u5F00\u542F\uFF1Aagent \u8DD1\u5B8C/\u51FA\u9519\u65F6\u624B\u673A\u6536\u5230\u901A\u77E5 | on: notified when tasks finish or fail" : pushState === "unsupported" ? "\u5DF2\u5F00\u542F\uFF08\u4F46\u5F53\u524D\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u63A8\u9001\uFF09| on, but this browser does not support push" : pushState === "insecure" ? "\u5DF2\u5F00\u542F\uFF0C\u4F46\u5F53\u524D\u8DEF\u5F84\u4E0D\u662F HTTPS\u2014\u2014\u63A8\u9001\u9700\u8981\u516C\u7F51\u96A7\u9053\u6216 localhost | on, but push needs HTTPS (public tunnel) or localhost" : pushState === "checking" ? "\u68C0\u67E5\u4E2D\u2026 | checking\u2026" : "\u63A8\u9001\u672A\u751F\u6548 | push not active"
|
|
1488
1497
|
)
|
|
1489
1498
|
),
|
|
1490
|
-
error ? (0, import_react2.createElement)("div", { style: { color: "var(--dsw-alias-state-error-primary,#dc2626)", fontSize: 12, marginTop: 8 } }, `\u274C ${error}`) : null
|
|
1499
|
+
error ? (0, import_react2.createElement)("div", { style: { color: "var(--dsw-alias-state-error-primary,#dc2626)", fontSize: 12, marginTop: 8 } }, `\u274C ${error}`) : null,
|
|
1500
|
+
// 页面最底部:反馈入口
|
|
1501
|
+
(0, import_react2.createElement)(
|
|
1502
|
+
"div",
|
|
1503
|
+
{ style: { ...styles.block, textAlign: "center" } },
|
|
1504
|
+
(0, import_react2.createElement)(
|
|
1505
|
+
"a",
|
|
1506
|
+
{ href: "https://github.com/shaobeichen/dsh-pocket/issues", target: "_blank", rel: "noreferrer", style: { fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)", textDecoration: "none" } },
|
|
1507
|
+
"\u6709\u95EE\u9898\uFF1F\u6B22\u8FCE\u5230 GitHub Issues \u53CD\u9988 \u{1F64F} | Questions? Open an issue on GitHub"
|
|
1508
|
+
)
|
|
1509
|
+
)
|
|
1491
1510
|
);
|
|
1492
1511
|
}
|
|
1493
1512
|
function apply(ctx) {
|
package/client/index.jsx
CHANGED
|
@@ -105,6 +105,17 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
105
105
|
return () => { alive = false; };
|
|
106
106
|
}, []);
|
|
107
107
|
|
|
108
|
+
// 重启宿主(更新生效必需:刷新页面不会重载服务端代码)
|
|
109
|
+
const restartPocket = async () => {
|
|
110
|
+
setUpdateInfo((u) => ({ ...u, restarting: true }));
|
|
111
|
+
try {
|
|
112
|
+
await call(POCKET_ENDPOINTS.restart, {});
|
|
113
|
+
// 宿主即将退出重启,无需更多处理
|
|
114
|
+
} catch (err) {
|
|
115
|
+
setUpdateInfo((u) => ({ ...u, restarting: false, result: 'fail', output: err.message }));
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
108
119
|
// 一键更新:调宿主 dsh plugin update
|
|
109
120
|
const runUpdate = async () => {
|
|
110
121
|
setUpdateInfo((u) => ({ ...u, updating: true, result: null }));
|
|
@@ -171,8 +182,8 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
171
182
|
h('strong', null, '📱 手机访问 | Phone access'),
|
|
172
183
|
h('div', { style: styles.muted }, '手机扫码打开的就是电脑上的这个界面,实时同步 | the phone shows this exact screen, live'),
|
|
173
184
|
),
|
|
174
|
-
h('
|
|
175
|
-
'开发者:程序员少北晨
|
|
185
|
+
h('div', { style: { fontSize: 12, color: 'var(--dsw-alias-label-tertiary,#8b93a1)', whiteSpace: 'nowrap' } },
|
|
186
|
+
'开发者:程序员少北晨'),
|
|
176
187
|
),
|
|
177
188
|
|
|
178
189
|
// 更新提示
|
|
@@ -181,7 +192,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
181
192
|
h('div', { style: { fontWeight: 600, fontSize: 13 } }, `📦 新版本 v${updateInfo.latest} | Update available`),
|
|
182
193
|
updateInfo.result !== 'ok'
|
|
183
194
|
? h('button', { style: styles.primary, onClick: runUpdate, disabled: updateInfo.updating }, updateInfo.updating ? '更新中…' : `更新到 v${updateInfo.latest} | Update`)
|
|
184
|
-
: h('button', { style: styles.
|
|
195
|
+
: h('button', { style: styles.primary, onClick: restartPocket, disabled: updateInfo.restarting }, updateInfo.restarting ? '重启中…' : '🔄 重启 dsh web 生效 | Restart now'),
|
|
185
196
|
),
|
|
186
197
|
h('div', { style: styles.muted, marginTop: 4 },
|
|
187
198
|
updateInfo.result === 'ok' ? '✅ 已更新,重启 dsh web 生效 | updated — restart dsh web'
|
|
@@ -238,6 +249,12 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
238
249
|
),
|
|
239
250
|
|
|
240
251
|
error ? h('div', { style: { color: 'var(--dsw-alias-state-error-primary,#dc2626)', fontSize: 12, marginTop: 8 } }, `❌ ${error}`) : null,
|
|
252
|
+
|
|
253
|
+
// 页面最底部:反馈入口
|
|
254
|
+
h('div', { style: { ...styles.block, textAlign: 'center' } },
|
|
255
|
+
h('a', { href: 'https://github.com/shaobeichen/dsh-pocket/issues', target: '_blank', rel: 'noreferrer', style: { fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)', textDecoration: 'none' } },
|
|
256
|
+
'有问题?欢迎到 GitHub Issues 反馈 🙏 | Questions? Open an issue on GitHub'),
|
|
257
|
+
),
|
|
241
258
|
);
|
|
242
259
|
}
|
|
243
260
|
|
package/lib/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { createRequire } from 'node:module';
|
|
|
15
15
|
import { createPocketService } from './service.mjs';
|
|
16
16
|
import { installPocketRpc } from './web-rpc.js';
|
|
17
17
|
import { createPushService } from './push.mjs';
|
|
18
|
+
import { restartHost } from './restart.js';
|
|
18
19
|
|
|
19
20
|
const name = 'dsh-pocket';
|
|
20
21
|
const inject = ['connection', 'webServer'];
|
|
@@ -83,6 +84,7 @@ export function apply(ctx, config = {}, internals = {}) {
|
|
|
83
84
|
service,
|
|
84
85
|
push: internals.push ?? { vapidPublicKey: () => '', count: () => 0, subscribe: async () => false, unsubscribe: async () => false, isEnabled: () => true, setEnabled: async () => true },
|
|
85
86
|
runUpdate: internals.runUpdate ?? { currentVersion, perform: performUpdate },
|
|
87
|
+
restart: internals.restart ?? (() => restartHost({ internals })),
|
|
86
88
|
log: logger,
|
|
87
89
|
});
|
|
88
90
|
disposers.push(disposeRpc);
|
package/lib/restart.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// dsh-pocket 自重启:重新拉起启动本宿主的确切 dsh 调用(脱离父进程),
|
|
2
|
+
// 让更新后的插件代码生效——用户无需离开界面手动重启(借鉴 dshmarket 的
|
|
3
|
+
// self-restart 方案,见 https://github.com/dsh-market/dsh-market lib/restart.js)。
|
|
4
|
+
//
|
|
5
|
+
// 原理:本插件运行在 dsh web 进程内,process.argv 即 dsh CLI 的启动参数
|
|
6
|
+
// (如 node <bin.js> web [flags])。用相同参数 detached 拉起新进程,
|
|
7
|
+
// 短暂等待后旧进程退出,新进程接管端口。
|
|
8
|
+
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 重建启动调用(与当前宿主相同的命令)。
|
|
13
|
+
* @returns {{file:string, args:string[]}}
|
|
14
|
+
*/
|
|
15
|
+
export function restartLaunch() {
|
|
16
|
+
return {
|
|
17
|
+
file: process.argv[0], // node
|
|
18
|
+
args: [process.argv[1], ...process.argv.slice(2)], // <bin.js> + web [flags]
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 拉起替代宿主(detached),随后退出当前进程。
|
|
24
|
+
* @param {object} opts
|
|
25
|
+
* @param {number} [opts.exitDelayMs] 等待新进程接管后再退出(默认 800ms)
|
|
26
|
+
* @param {object} [opts.internals] 测试注入:spawnFn / exitFn
|
|
27
|
+
* @returns {{spawned:boolean, file:string}}
|
|
28
|
+
*/
|
|
29
|
+
export function restartHost({ exitDelayMs = 800, internals = {} } = {}) {
|
|
30
|
+
const spawnFn = internals.spawn ?? spawn;
|
|
31
|
+
const exitFn = internals.exit ?? ((code) => process.exit(code));
|
|
32
|
+
const { file, args } = restartLaunch();
|
|
33
|
+
try {
|
|
34
|
+
const child = spawnFn(file, args, {
|
|
35
|
+
detached: true,
|
|
36
|
+
stdio: 'ignore',
|
|
37
|
+
env: process.env,
|
|
38
|
+
});
|
|
39
|
+
child.unref?.();
|
|
40
|
+
setTimeout(() => exitFn(0), exitDelayMs);
|
|
41
|
+
return { spawned: true, file };
|
|
42
|
+
} catch (err) {
|
|
43
|
+
return { spawned: false, error: err?.message ?? String(err) };
|
|
44
|
+
}
|
|
45
|
+
}
|
package/lib/web-rpc.js
CHANGED
|
@@ -17,7 +17,7 @@ function fail(code, message) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/** 注册 /dsh-pocket 逻辑通道(仅本机 loopback 可调)。 */
|
|
20
|
-
export function installPocketRpc(ctx, { service, push, log = console, runUpdate = null }) {
|
|
20
|
+
export function installPocketRpc(ctx, { service, push, log = console, runUpdate = null, restart = null }) {
|
|
21
21
|
if (!ctx?.connection?.rpc?.handle) {
|
|
22
22
|
log.warn?.('dsh-pocket: DSH Host Connection RPC unavailable — settings tab disabled | 无 Connection RPC,设置页不可用');
|
|
23
23
|
return () => {};
|
|
@@ -63,6 +63,11 @@ export function installPocketRpc(ctx, { service, push, log = console, runUpdate
|
|
|
63
63
|
const result = await runUpdate.perform(payload?.profile ?? 'web');
|
|
64
64
|
return ok(result);
|
|
65
65
|
}
|
|
66
|
+
if (endpoint === POCKET_ENDPOINTS.restart) {
|
|
67
|
+
if (!restart) return fail('bad-request', '重启不可用 | restart unavailable');
|
|
68
|
+
const result = restart();
|
|
69
|
+
return ok(result);
|
|
70
|
+
}
|
|
66
71
|
return fail('bad-request', `Unknown endpoint: ${endpoint}`);
|
|
67
72
|
} catch (err) {
|
|
68
73
|
log.error?.('dsh-pocket: rpc %s failed | RPC 失败: %s', endpoint, err?.message ?? err);
|
package/package.json
CHANGED