dsh-cherry-bridge 0.1.11 → 0.2.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/README.en.md +11 -4
- package/README.md +10 -4
- package/dist/index.d.mts +31 -3
- package/dist/index.mjs +906 -144
- package/docs/e2e-checklist.md +2 -2
- package/lib/client.js +47 -0
- package/package.json +4 -3
- package/src/AGENTS.md +860 -0
- package/src/connection.ts +114 -10
- package/src/deviceStore.ts +204 -5
- package/src/diagnostics.ts +30 -0
- package/src/httpApi.ts +129 -8
- package/src/index.ts +190 -8
- package/src/pairing.ts +504 -112
- package/src/rpc/jsonRpcClient.ts +19 -1
- package/src/subscriptions.ts +10 -2
- package/src/text.ts +158 -0
- package/src/tools.ts +181 -14
- package/ui/AGENTS.md +23 -0
- package/ui/src/DeviceCard.tsx +35 -0
- package/ui/src/i18n.ts +10 -0
- package/ui/src/types.ts +9 -1
- package/src/urlHost.ts +0 -15
package/docs/e2e-checklist.md
CHANGED
|
@@ -269,8 +269,8 @@ http://127.0.0.1:23023/cherry-remote/api/scope`(宿主换过端口就换端口
|
|
|
269
269
|
- [ ] 该端点同样受信任 fence 约束:非回环 Host、非同源 Origin、`sec-fetch-site: cross-site`
|
|
270
270
|
一律 403;无 Origin 的非浏览器客户端放行。
|
|
271
271
|
- [ ] 全流程日志不含 token / invitationSecret / accessToken / 消息文本 / part 文本。
|
|
272
|
-
- [ ] **上游版本核验**(桌面端为 2.1.4–2.1.
|
|
273
|
-
|
|
272
|
+
- [ ] **上游版本核验**(桌面端为 2.1.4–2.1.8 或已比对过的更新版本;依据见
|
|
273
|
+
src/AGENTS.md「Protocol basis」):
|
|
274
274
|
- [ ] 桌面端**升级后无需重新配对**:设备档案直接连上,`desktopIdentity` 未变。
|
|
275
275
|
- [ ] 桌面端为 2.1.5+ 且会话里有**来自手机上传的附件**时:该 part 为 `kind:"file"`
|
|
276
276
|
并带 `name`/`mediaType`/`byteLength`,`content` 为空,且**没有**任何
|
package/lib/client.js
CHANGED
|
@@ -36,6 +36,10 @@ window.__ModuleLoader__.load({
|
|
|
36
36
|
"device.field.name": "设备名称",
|
|
37
37
|
"device.field.hosts": "主机地址",
|
|
38
38
|
"device.hosts.hint": "多个候选地址用逗号分隔(整体替换)",
|
|
39
|
+
"device.field.ports": "每地址端口",
|
|
40
|
+
"device.ports.hint": "部分候选地址的端口与上方的端口不同;在「地址维护」里改动端口会把所有候选地址改为同一端口。",
|
|
41
|
+
"device.ports.current": "当前端口映射:",
|
|
42
|
+
"device.port.hint": "保持当前值会保留各地址自己的端口;改成新值会把所有候选地址重指到该端口。",
|
|
39
43
|
"device.save.name": "保存名称",
|
|
40
44
|
"device.save.addresses": "保存地址",
|
|
41
45
|
"device.remove.confirm": "确认移除",
|
|
@@ -136,6 +140,10 @@ window.__ModuleLoader__.load({
|
|
|
136
140
|
"device.field.name": "Device name",
|
|
137
141
|
"device.field.hosts": "Host addresses",
|
|
138
142
|
"device.hosts.hint": "Separate candidate addresses with commas (the whole list is replaced)",
|
|
143
|
+
"device.field.ports": "Ports per address",
|
|
144
|
+
"device.ports.hint": "Some candidate addresses dial a different port than the one above; changing the port in address maintenance moves every candidate address to that one port.",
|
|
145
|
+
"device.ports.current": "Current port map:",
|
|
146
|
+
"device.port.hint": "Keeping the current value preserves each address’s own port; a new value re-points every candidate address.",
|
|
139
147
|
"device.save.name": "Save name",
|
|
140
148
|
"device.save.addresses": "Save addresses",
|
|
141
149
|
"device.remove.confirm": "Confirm removal",
|
|
@@ -516,6 +524,20 @@ window.__ModuleLoader__.load({
|
|
|
516
524
|
function parseHosts(raw) {
|
|
517
525
|
return raw.split(",").map((entry) => entry.trim()).filter((entry) => entry !== "");
|
|
518
526
|
}
|
|
527
|
+
/** The dial port for one host: its own stored port, else the record-level one. */
|
|
528
|
+
function dialPort(device, host) {
|
|
529
|
+
return device.ports?.[host] ?? device.port;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* `host:port` as one readable address.
|
|
533
|
+
*
|
|
534
|
+
* An IPv6 literal contains colons, so `fe80::1:4343` reads as an ambiguous
|
|
535
|
+
* host; stored hosts are bare (`normalizeHost` strips the brackets), so the
|
|
536
|
+
* brackets are added here, for display only.
|
|
537
|
+
*/
|
|
538
|
+
function formatAddress(host, port) {
|
|
539
|
+
return host.includes(":") ? `[${host}]:${port}` : `${host}:${port}`;
|
|
540
|
+
}
|
|
519
541
|
function DeviceCard({ device, state, onSaved, onRemoved }) {
|
|
520
542
|
const t = useT();
|
|
521
543
|
const [editor, setEditor] = (0, react.useState)("none");
|
|
@@ -615,6 +637,8 @@ window.__ModuleLoader__.load({
|
|
|
615
637
|
onRemoved(device.deviceId);
|
|
616
638
|
});
|
|
617
639
|
};
|
|
640
|
+
const mixedPorts = device.hosts.some((host) => dialPort(device, host) !== device.port);
|
|
641
|
+
const addressList = device.hosts.map((host) => formatAddress(host, dialPort(device, host))).join(", ");
|
|
618
642
|
const label = state === void 0 ? t("device.state.unknown") : t(STATE_KEYS[state] ?? state);
|
|
619
643
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
620
644
|
className: "cherry-card",
|
|
@@ -681,6 +705,10 @@ window.__ModuleLoader__.load({
|
|
|
681
705
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: device.hosts.join(", ") }),
|
|
682
706
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("device.field.port") }),
|
|
683
707
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: device.port }),
|
|
708
|
+
mixedPorts && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("device.field.ports") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
709
|
+
className: "cherry-mono",
|
|
710
|
+
children: addressList
|
|
711
|
+
})] }),
|
|
684
712
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("device.field.id") }),
|
|
685
713
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
686
714
|
className: "cherry-mono",
|
|
@@ -688,6 +716,10 @@ window.__ModuleLoader__.load({
|
|
|
688
716
|
})
|
|
689
717
|
]
|
|
690
718
|
}),
|
|
719
|
+
mixedPorts && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
720
|
+
className: "cherry-hint",
|
|
721
|
+
children: t("device.ports.hint")
|
|
722
|
+
}),
|
|
691
723
|
editor === "rename" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
692
724
|
className: "cherry-inline-form",
|
|
693
725
|
onSubmit: saveName,
|
|
@@ -725,6 +757,17 @@ window.__ModuleLoader__.load({
|
|
|
725
757
|
className: "cherry-hint",
|
|
726
758
|
children: t("device.hosts.hint")
|
|
727
759
|
}),
|
|
760
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
761
|
+
className: "cherry-hint",
|
|
762
|
+
children: [
|
|
763
|
+
t("device.ports.current"),
|
|
764
|
+
" ",
|
|
765
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
766
|
+
className: "cherry-mono",
|
|
767
|
+
children: addressList
|
|
768
|
+
})
|
|
769
|
+
]
|
|
770
|
+
}),
|
|
728
771
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
729
772
|
htmlFor: `port-${device.deviceId}`,
|
|
730
773
|
children: t("device.field.port")
|
|
@@ -735,6 +778,10 @@ window.__ModuleLoader__.load({
|
|
|
735
778
|
value: portText,
|
|
736
779
|
onChange: (event) => setPortText(event.target.value)
|
|
737
780
|
}),
|
|
781
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
782
|
+
className: "cherry-hint",
|
|
783
|
+
children: t("device.port.hint")
|
|
784
|
+
}),
|
|
738
785
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
739
786
|
type: "submit",
|
|
740
787
|
disabled: busy,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-cherry-bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"packageManager": "npm@10.9.9",
|
|
@@ -65,8 +65,9 @@
|
|
|
65
65
|
"prepublishOnly": "npm run typecheck && npm test && npm run build && npm run build:client && npm pack --dry-run"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@cherrystudio/remote-protocol": "0.
|
|
69
|
-
"@cherrystudio/remote-transport": "0.2.
|
|
68
|
+
"@cherrystudio/remote-protocol": "0.7.0",
|
|
69
|
+
"@cherrystudio/remote-transport": "0.2.5",
|
|
70
|
+
"@libp2p/peer-id": "6.0.15",
|
|
70
71
|
"ws": "8.22.0",
|
|
71
72
|
"zod": "4.3.4"
|
|
72
73
|
},
|