@linxin666/dsh-remote-web-ui 0.1.16 → 0.1.18
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.i18n.yaml +2 -2
- package/README.md +5 -2
- package/README.zh.md +2 -2
- package/assets/apple-touch-icon.png +0 -0
- package/lib/client.js +48 -58
- package/lib/client.js.map +1 -1
- package/lib/index.js +76 -14
- package/lib/mobile.js +649 -45
- package/lib/mobile.js.map +1 -1
- package/lib/types/client/PluginSettingsCard.d.ts +11 -0
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +11 -5
- package/lib/types/mobile/markdown.d.ts +26 -0
- package/lib/types/mobile/markdown.d.ts.map +1 -0
- package/lib/types/mobile/markdown.js +272 -0
- package/lib/types/mobile/markdown.test.d.ts +2 -0
- package/lib/types/mobile/markdown.test.d.ts.map +1 -0
- package/lib/types/mobile/markdown.test.js +67 -0
- package/lib/types/mobile/messages.d.ts +14 -0
- package/lib/types/mobile/messages.d.ts.map +1 -1
- package/lib/types/mobile/messages.js +54 -2
- package/lib/types/mobile/messages.test.js +99 -0
- package/lib/types/mobile/mobile-styles.d.ts +1 -1
- package/lib/types/mobile/mobile-styles.d.ts.map +1 -1
- package/lib/types/mobile/mobile-styles.js +167 -0
- package/lib/types/mobile/views/ChatView.d.ts.map +1 -1
- package/lib/types/mobile/views/ChatView.js +81 -5
- package/lib/types/mobile/views/ChatView.test.js +105 -0
- package/lib/types/mobile-api.d.ts.map +1 -1
- package/lib/types/mobile-api.js +19 -2
- package/lib/types/mobile-routes.d.ts.map +1 -1
- package/lib/types/mobile-routes.js +32 -0
- package/lib/types/update.d.ts +5 -3
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +22 -6
- package/package.json +2 -1
- package/src/client/PluginSettingsCard.tsx +50 -47
- package/src/client/settings-card.module.css +9 -0
- package/src/mobile/markdown.test.ts +77 -0
- package/src/mobile/markdown.ts +278 -0
- package/src/mobile/messages.test.ts +106 -0
- package/src/mobile/messages.ts +66 -2
- package/src/mobile/mobile-styles.ts +167 -0
- package/src/mobile/views/ChatView.test.tsx +121 -0
- package/src/mobile/views/ChatView.tsx +164 -6
- package/src/mobile-api.ts +19 -2
- package/src/mobile-routes.ts +33 -0
- package/src/update.ts +23 -6
package/lib/index.js
CHANGED
|
@@ -981,6 +981,10 @@ function makeRoutes(deps) {
|
|
|
981
981
|
function mobileBundlePath() {
|
|
982
982
|
return fileURLToPath(new URL("../lib/mobile.js", import.meta.url));
|
|
983
983
|
}
|
|
984
|
+
/** The apple-touch-icon shipped with the package (iOS home-screen icon, 180x180 PNG). */
|
|
985
|
+
function appleTouchIconPath() {
|
|
986
|
+
return fileURLToPath(new URL("../assets/apple-touch-icon.png", import.meta.url));
|
|
987
|
+
}
|
|
984
988
|
/** The mobile page shell: minimal, offline-safe, no external assets. */
|
|
985
989
|
function pageHtml(bundleUrl) {
|
|
986
990
|
return [
|
|
@@ -991,6 +995,7 @@ function pageHtml(bundleUrl) {
|
|
|
991
995
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover\">",
|
|
992
996
|
"<meta name=\"theme-color\" content=\"#f3f5f9\">",
|
|
993
997
|
"<meta name=\"referrer\" content=\"no-referrer\">",
|
|
998
|
+
"<link rel=\"apple-touch-icon\" href=\"/m/apple-touch-icon.png\">",
|
|
994
999
|
"<title>移动端远程控制</title>",
|
|
995
1000
|
"</head>",
|
|
996
1001
|
"<body>",
|
|
@@ -1009,6 +1014,15 @@ function writeStatic(res, status, type, body) {
|
|
|
1009
1014
|
});
|
|
1010
1015
|
res.end(body);
|
|
1011
1016
|
}
|
|
1017
|
+
/** Send the PNG icon as a binary body (unlike text assets, the PNG must not be decoded to utf-8). */
|
|
1018
|
+
function writePng(res, status, body) {
|
|
1019
|
+
res.writeHead(status, {
|
|
1020
|
+
"content-type": "image/png",
|
|
1021
|
+
"cache-control": "public, max-age=31536000, immutable",
|
|
1022
|
+
"referrer-policy": "no-referrer"
|
|
1023
|
+
});
|
|
1024
|
+
res.end(body);
|
|
1025
|
+
}
|
|
1012
1026
|
/**
|
|
1013
1027
|
* Build the mobile page routes.
|
|
1014
1028
|
* @returns the two exact routes to register on webServer.
|
|
@@ -1029,15 +1043,35 @@ function makeMobileRoutes() {
|
|
|
1029
1043
|
writeStatic(res, 500, "text/plain", "failed to read the mobile bundle");
|
|
1030
1044
|
}
|
|
1031
1045
|
};
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
path
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1046
|
+
const handleIcon = async (_req, res) => {
|
|
1047
|
+
const path = appleTouchIconPath();
|
|
1048
|
+
if (!existsSync(path)) {
|
|
1049
|
+
writeStatic(res, 404, "text/plain", "apple-touch-icon not found");
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
try {
|
|
1053
|
+
writePng(res, 200, await readFile(path));
|
|
1054
|
+
} catch {
|
|
1055
|
+
writeStatic(res, 500, "text/plain", "failed to read the apple-touch-icon");
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
return [
|
|
1059
|
+
{
|
|
1060
|
+
kind: "exact",
|
|
1061
|
+
path: "/m",
|
|
1062
|
+
handler: handlePage
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
kind: "exact",
|
|
1066
|
+
path: "/m/mobile.js",
|
|
1067
|
+
handler: handleBundle
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
kind: "exact",
|
|
1071
|
+
path: "/m/apple-touch-icon.png",
|
|
1072
|
+
handler: handleIcon
|
|
1073
|
+
}
|
|
1074
|
+
];
|
|
1041
1075
|
}
|
|
1042
1076
|
//#endregion
|
|
1043
1077
|
//#region src/mobile-api.ts
|
|
@@ -1096,10 +1130,22 @@ const MOBILE_API_METHOD_PREFIX = `${MOBILE_API_PREFIX}/`;
|
|
|
1096
1130
|
function makeMobileApiRoutes(deps) {
|
|
1097
1131
|
const { service, apiProxy, mobileEnterToSend } = deps;
|
|
1098
1132
|
const eventsHeartbeatMs = deps.eventsHeartbeatMs ?? DEFAULT_EVENTS_HEARTBEAT_MS;
|
|
1133
|
+
/**
|
|
1134
|
+
* Refresh the paired device's presence and report whether it is live.
|
|
1135
|
+
* The mobile surface (unlike the desktop Web UI) has no `/api/pair/heartbeat`
|
|
1136
|
+
* sender, so any activity on the mobile channel — a gated RPC, or the live
|
|
1137
|
+
* SSE stream staying open — must count as presence. Without this, an
|
|
1138
|
+
* idle-but-connected phone ages past `offlineAfterMs` and the desktop panel
|
|
1139
|
+
* wrongly reports it as disconnected.
|
|
1140
|
+
*/
|
|
1141
|
+
const touchDeviceFor = (req) => {
|
|
1142
|
+
const deviceId = readCookie(req.headers.cookie, service.config.cookieName);
|
|
1143
|
+
if (deviceId === void 0) return false;
|
|
1144
|
+
return service.touchDevice(deviceId);
|
|
1145
|
+
};
|
|
1099
1146
|
/** The phone gate: a live paired-device cookie, or nothing else proceeds. */
|
|
1100
1147
|
const gateOk = (req) => {
|
|
1101
|
-
|
|
1102
|
-
return deviceId !== void 0 && service.hasDevice(deviceId);
|
|
1148
|
+
return touchDeviceFor(req);
|
|
1103
1149
|
};
|
|
1104
1150
|
const writeJson = (res, status, body) => {
|
|
1105
1151
|
res.writeHead(status, { "content-type": "application/json; charset=utf-8" });
|
|
@@ -1219,6 +1265,7 @@ function makeMobileApiRoutes(deps) {
|
|
|
1219
1265
|
let closed = false;
|
|
1220
1266
|
const heartbeat = setInterval(() => {
|
|
1221
1267
|
if (closed) return;
|
|
1268
|
+
touchDeviceFor(req);
|
|
1222
1269
|
try {
|
|
1223
1270
|
res.write(": ping\n\n");
|
|
1224
1271
|
} catch {}
|
|
@@ -1787,6 +1834,16 @@ const OUTPUT_CAP = 16 * 1024;
|
|
|
1787
1834
|
*/
|
|
1788
1835
|
const WIN_CMD_MISSING_RE = /not recognized as an internal or external command/i;
|
|
1789
1836
|
/**
|
|
1837
|
+
* Bypass for pnpm 11's supply-chain gate: `minimumReleaseAge` (default 24 h)
|
|
1838
|
+
* silently skips same-day releases — `pnpm update --latest` then exits 0
|
|
1839
|
+
* without moving anything and the post-run verification would misreport a
|
|
1840
|
+
* stale no-op. The update here is explicitly user-initiated and the panel
|
|
1841
|
+
* shows exactly which versions are being installed, so the gate only adds a
|
|
1842
|
+
* confusing silent no-op; override it per-invocation instead of asking every
|
|
1843
|
+
* user to edit the profile's pnpm-workspace.yaml.
|
|
1844
|
+
*/
|
|
1845
|
+
const MIN_RELEASE_AGE_OVERRIDE = "--config.minimumReleaseAge=0";
|
|
1846
|
+
/**
|
|
1790
1847
|
* Run the update inside the profile directory. Tries pnpm first, falls back
|
|
1791
1848
|
* to corepack and then npx when the previous command is missing (ENOENT);
|
|
1792
1849
|
* all candidates share one hard timeout and keep accumulating output.
|
|
@@ -1813,6 +1870,7 @@ function runUpdate(deps) {
|
|
|
1813
1870
|
args: [
|
|
1814
1871
|
"update",
|
|
1815
1872
|
"--latest",
|
|
1873
|
+
MIN_RELEASE_AGE_OVERRIDE,
|
|
1816
1874
|
...packages
|
|
1817
1875
|
]
|
|
1818
1876
|
},
|
|
@@ -1822,6 +1880,7 @@ function runUpdate(deps) {
|
|
|
1822
1880
|
"pnpm",
|
|
1823
1881
|
"update",
|
|
1824
1882
|
"--latest",
|
|
1883
|
+
MIN_RELEASE_AGE_OVERRIDE,
|
|
1825
1884
|
...packages
|
|
1826
1885
|
]
|
|
1827
1886
|
},
|
|
@@ -1832,6 +1891,7 @@ function runUpdate(deps) {
|
|
|
1832
1891
|
"pnpm",
|
|
1833
1892
|
"update",
|
|
1834
1893
|
"--latest",
|
|
1894
|
+
MIN_RELEASE_AGE_OVERRIDE,
|
|
1835
1895
|
...packages
|
|
1836
1896
|
]
|
|
1837
1897
|
}
|
|
@@ -1930,9 +1990,11 @@ function runUpdate(deps) {
|
|
|
1930
1990
|
}
|
|
1931
1991
|
/**
|
|
1932
1992
|
* Run the update, then verify the installed versions actually moved. pnpm
|
|
1933
|
-
* exits 0 even when it silently kept the installed versions —
|
|
1934
|
-
* `minimumReleaseAge` gate
|
|
1935
|
-
*
|
|
1993
|
+
* exits 0 even when it silently kept the installed versions — runUpdate
|
|
1994
|
+
* overrides pnpm 11's `minimumReleaseAge` gate (default 24 h) with
|
|
1995
|
+
* `--config.minimumReleaseAge=0`, but an older pnpm without the override or
|
|
1996
|
+
* another silent no-op can still keep versions in place — so a green exit
|
|
1997
|
+
* alone must not report a misleading "update complete". Re-read the
|
|
1936
1998
|
* installed versions afterwards and surface a `stale` failure (with the
|
|
1937
1999
|
* captured pnpm output) when nothing moved, so the panel can tell the user
|
|
1938
2000
|
* how to unblock the gate instead of claiming success.
|