@linxin666/dsh-remote-web-ui 0.1.15 → 0.1.17
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 +9 -5
- package/README.zh.md +1 -1
- package/assets/apple-touch-icon.png +0 -0
- package/lib/client.js +58 -10
- package/lib/client.js.map +1 -1
- package/lib/index.js +183 -22
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +3 -1
- package/lib/types/client/UpdatePanel.js +2 -0
- package/lib/types/client/locales.d.ts +4 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +4 -0
- package/lib/types/client/settings-form.d.ts +62 -0
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +61 -12
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +36 -10
- 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 +46 -4
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +134 -8
- package/package.json +2 -1
- package/src/client/PluginSettingsCard.tsx +7 -1
- package/src/client/UpdatePanel.tsx +2 -0
- package/src/client/locales.ts +4 -0
- package/src/client/settings-card.module.css +3 -0
- package/src/client/settings-form.ts +114 -12
- package/src/index.ts +34 -10
- package/src/mobile-api.ts +19 -2
- package/src/mobile-routes.ts +33 -0
- package/src/update.ts +145 -9
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 {}
|
|
@@ -1633,13 +1680,16 @@ function isLinkedSpec(spec) {
|
|
|
1633
1680
|
}
|
|
1634
1681
|
/**
|
|
1635
1682
|
* Resolve the anchor package's manifest path. The aggregate package is the
|
|
1636
|
-
* canonical entry point; this plugin's own package is the fallback.
|
|
1683
|
+
* canonical entry point; this plugin's own package is the fallback. Both a
|
|
1684
|
+
* throwing resolve and an undefined return mean "not installed" and move on
|
|
1685
|
+
* to the next candidate.
|
|
1637
1686
|
* @param resolve - a Node resolve implementation scoped to the host process.
|
|
1638
1687
|
* @returns the absolute manifest path, or undefined when neither is installed.
|
|
1639
1688
|
*/
|
|
1640
1689
|
function resolveAnchorManifest(resolve) {
|
|
1641
1690
|
for (const name of [AGGREGATE_PACKAGE, SELF_PACKAGE]) try {
|
|
1642
|
-
|
|
1691
|
+
const path = resolve(name + "/package.json");
|
|
1692
|
+
if (path !== void 0) return path;
|
|
1643
1693
|
} catch {}
|
|
1644
1694
|
}
|
|
1645
1695
|
/**
|
|
@@ -1701,14 +1751,21 @@ async function fetchLatestVersion(name, fetchImpl, timeoutMs = 1e4) {
|
|
|
1701
1751
|
return;
|
|
1702
1752
|
}
|
|
1703
1753
|
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Sentinel for an installed version that could not be read (missing manifest
|
|
1756
|
+
* or resolve failure). It is a real-looking version so `checkUpdates` can
|
|
1757
|
+
* render the affected row, but the verified-update comparison must never
|
|
1758
|
+
* treat it as evidence — a read failure is not a version that "moved".
|
|
1759
|
+
*/
|
|
1760
|
+
const VERSION_UNKNOWN = "0.0.0";
|
|
1704
1761
|
/** The resolved current version of one family package (probe failure tolerated). */
|
|
1705
1762
|
function readInstalledVersion(resolve, name) {
|
|
1706
1763
|
try {
|
|
1707
1764
|
const path = resolve(name + "/package.json");
|
|
1708
1765
|
const version = path === void 0 ? void 0 : readManifest(path)?.version;
|
|
1709
|
-
return typeof version === "string" ? version :
|
|
1766
|
+
return typeof version === "string" ? version : VERSION_UNKNOWN;
|
|
1710
1767
|
} catch {
|
|
1711
|
-
return
|
|
1768
|
+
return VERSION_UNKNOWN;
|
|
1712
1769
|
}
|
|
1713
1770
|
}
|
|
1714
1771
|
/**
|
|
@@ -1777,6 +1834,16 @@ const OUTPUT_CAP = 16 * 1024;
|
|
|
1777
1834
|
*/
|
|
1778
1835
|
const WIN_CMD_MISSING_RE = /not recognized as an internal or external command/i;
|
|
1779
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
|
+
/**
|
|
1780
1847
|
* Run the update inside the profile directory. Tries pnpm first, falls back
|
|
1781
1848
|
* to corepack and then npx when the previous command is missing (ENOENT);
|
|
1782
1849
|
* all candidates share one hard timeout and keep accumulating output.
|
|
@@ -1800,13 +1867,20 @@ function runUpdate(deps) {
|
|
|
1800
1867
|
const candidates = [
|
|
1801
1868
|
{
|
|
1802
1869
|
command: "pnpm",
|
|
1803
|
-
args: [
|
|
1870
|
+
args: [
|
|
1871
|
+
"update",
|
|
1872
|
+
"--latest",
|
|
1873
|
+
MIN_RELEASE_AGE_OVERRIDE,
|
|
1874
|
+
...packages
|
|
1875
|
+
]
|
|
1804
1876
|
},
|
|
1805
1877
|
{
|
|
1806
1878
|
command: "corepack",
|
|
1807
1879
|
args: [
|
|
1808
1880
|
"pnpm",
|
|
1809
1881
|
"update",
|
|
1882
|
+
"--latest",
|
|
1883
|
+
MIN_RELEASE_AGE_OVERRIDE,
|
|
1810
1884
|
...packages
|
|
1811
1885
|
]
|
|
1812
1886
|
},
|
|
@@ -1816,6 +1890,8 @@ function runUpdate(deps) {
|
|
|
1816
1890
|
"--yes",
|
|
1817
1891
|
"pnpm",
|
|
1818
1892
|
"update",
|
|
1893
|
+
"--latest",
|
|
1894
|
+
MIN_RELEASE_AGE_OVERRIDE,
|
|
1819
1895
|
...packages
|
|
1820
1896
|
]
|
|
1821
1897
|
}
|
|
@@ -1912,6 +1988,72 @@ function runUpdate(deps) {
|
|
|
1912
1988
|
runCandidate(0);
|
|
1913
1989
|
});
|
|
1914
1990
|
}
|
|
1991
|
+
/**
|
|
1992
|
+
* Run the update, then verify the installed versions actually moved. pnpm
|
|
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
|
|
1998
|
+
* installed versions afterwards and surface a `stale` failure (with the
|
|
1999
|
+
* captured pnpm output) when nothing moved, so the panel can tell the user
|
|
2000
|
+
* how to unblock the gate instead of claiming success.
|
|
2001
|
+
*
|
|
2002
|
+
* The stale decision anchors on the pre-run installed versions, not on the
|
|
2003
|
+
* registry latest: under a lenient gate pnpm may move 0.1.12 -> 0.1.13 while
|
|
2004
|
+
* latest stays 0.1.15 — that is a real update, not stale. The post-run anchor
|
|
2005
|
+
* path is re-resolved rather than reused from boot time: pnpm removes the old
|
|
2006
|
+
* version's .pnpm directory on update, so a boot-time captured path would
|
|
2007
|
+
* fail to read and collapse a successful update into a bogus 'missing'.
|
|
2008
|
+
*
|
|
2009
|
+
* A green exit whose verification has nothing to compare (registry probe
|
|
2010
|
+
* outage, missing anchor, non-npm mode) is reported as `verify-failed` — it
|
|
2011
|
+
* must never read as success. A green exit where no package moved but the
|
|
2012
|
+
* post-run check could not prove the install is fully current (a partial
|
|
2013
|
+
* probe failure hides whether a gate kept something back) is also
|
|
2014
|
+
* `verify-failed`: it must not collapse into a success either.
|
|
2015
|
+
* @param deps - the run and check seams.
|
|
2016
|
+
* @returns the run result; `stale` when exit 0 left every version in place,
|
|
2017
|
+
* `verify-failed` when the post-run check could not verify anything.
|
|
2018
|
+
*/
|
|
2019
|
+
async function runUpdateVerified(deps) {
|
|
2020
|
+
const before = /* @__PURE__ */ new Map();
|
|
2021
|
+
for (const name of deps.run.packages) {
|
|
2022
|
+
const version = readInstalledVersion(deps.check.resolve, name);
|
|
2023
|
+
if (version !== VERSION_UNKNOWN) before.set(name, version);
|
|
2024
|
+
}
|
|
2025
|
+
const result = await runUpdate(deps.run);
|
|
2026
|
+
if (!result.ok) return result;
|
|
2027
|
+
const anchorManifestPath = resolveAnchorManifest(deps.check.resolve) ?? deps.check.anchorManifestPath;
|
|
2028
|
+
const status = await checkUpdates({
|
|
2029
|
+
...deps.check,
|
|
2030
|
+
anchorManifestPath
|
|
2031
|
+
});
|
|
2032
|
+
if (status.error !== void 0 || status.mode !== "npm") return {
|
|
2033
|
+
...result,
|
|
2034
|
+
ok: false,
|
|
2035
|
+
errorCode: "verify-failed",
|
|
2036
|
+
error: "pnpm exited 0 but the post-run version check could not verify the install"
|
|
2037
|
+
};
|
|
2038
|
+
if (status.packages.some((packageStatus) => {
|
|
2039
|
+
const beforeVersion = before.get(packageStatus.name);
|
|
2040
|
+
if (beforeVersion === void 0 || packageStatus.current === VERSION_UNKNOWN) return false;
|
|
2041
|
+
return packageStatus.current !== beforeVersion;
|
|
2042
|
+
})) return result;
|
|
2043
|
+
if (status.outdated) return {
|
|
2044
|
+
...result,
|
|
2045
|
+
ok: false,
|
|
2046
|
+
errorCode: "stale",
|
|
2047
|
+
error: "pnpm exited 0 but the installed versions did not change"
|
|
2048
|
+
};
|
|
2049
|
+
if (status.packages.some((packageStatus) => packageStatus.latest === void 0)) return {
|
|
2050
|
+
...result,
|
|
2051
|
+
ok: false,
|
|
2052
|
+
errorCode: "verify-failed",
|
|
2053
|
+
error: "pnpm exited 0 but the post-run version check could not verify the install"
|
|
2054
|
+
};
|
|
2055
|
+
return result;
|
|
2056
|
+
}
|
|
1915
2057
|
//#endregion
|
|
1916
2058
|
//#region src/update-routes.ts
|
|
1917
2059
|
/** Route paths (exact matches under /api). */
|
|
@@ -2093,11 +2235,17 @@ function apply(ctx, config) {
|
|
|
2093
2235
|
const apiProxy = ctx.get("apiProxy");
|
|
2094
2236
|
if (apiProxy === void 0) console.warn("remote-web-ui: apiProxy service unavailable — the mobile data channel is disabled");
|
|
2095
2237
|
const requireFromHost = createRequire(import.meta.url);
|
|
2096
|
-
const
|
|
2238
|
+
const resolveAnchorPath = () => resolveAnchorManifest((specifier) => {
|
|
2239
|
+
try {
|
|
2240
|
+
return requireFromHost.resolve(specifier);
|
|
2241
|
+
} catch {
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
});
|
|
2097
2245
|
const updateRoutes = makeUpdateRoutes({
|
|
2098
2246
|
fence: (request) => isTrustedApiRequest(request, []),
|
|
2099
2247
|
check: () => checkUpdates({
|
|
2100
|
-
anchorManifestPath,
|
|
2248
|
+
anchorManifestPath: resolveAnchorPath(),
|
|
2101
2249
|
resolve: (specifier) => {
|
|
2102
2250
|
try {
|
|
2103
2251
|
return requireFromHost.resolve(specifier);
|
|
@@ -2108,7 +2256,7 @@ function apply(ctx, config) {
|
|
|
2108
2256
|
fetchLatest: (name) => fetchLatestVersion(name, fetch)
|
|
2109
2257
|
}),
|
|
2110
2258
|
run: async () => {
|
|
2111
|
-
const target = resolveUpdateTarget({ anchorManifestPath });
|
|
2259
|
+
const target = resolveUpdateTarget({ anchorManifestPath: resolveAnchorPath() });
|
|
2112
2260
|
if ("error" in target) {
|
|
2113
2261
|
const code = target.error;
|
|
2114
2262
|
return {
|
|
@@ -2119,9 +2267,22 @@ function apply(ctx, config) {
|
|
|
2119
2267
|
errorCode: code
|
|
2120
2268
|
};
|
|
2121
2269
|
}
|
|
2122
|
-
return
|
|
2123
|
-
|
|
2124
|
-
|
|
2270
|
+
return runUpdateVerified({
|
|
2271
|
+
run: {
|
|
2272
|
+
profileDir: target.profileDir,
|
|
2273
|
+
packages: target.packages
|
|
2274
|
+
},
|
|
2275
|
+
check: {
|
|
2276
|
+
anchorManifestPath: resolveAnchorPath(),
|
|
2277
|
+
resolve: (specifier) => {
|
|
2278
|
+
try {
|
|
2279
|
+
return requireFromHost.resolve(specifier);
|
|
2280
|
+
} catch {
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
2283
|
+
},
|
|
2284
|
+
fetchLatest: (name) => fetchLatestVersion(name, fetch)
|
|
2285
|
+
}
|
|
2125
2286
|
});
|
|
2126
2287
|
}
|
|
2127
2288
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAGnD,oGAAoG;AACpG,eAAO,MAAM,cAAc,kMAUjB,CAAA;AAEV,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzD,oEAAoE;AACpE,MAAM,MAAM,eAAe,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI,IAAI,GAAG,WAAW,CAAA;AAE9E,wDAAwD;AACxD,MAAM,WAAW,uBAAuB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACnE,0CAA0C;IAC1C,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAA;IACnF,uCAAuC;IACvC,QAAQ,EAAE,IAAI,CAAA;IACd,4EAA4E;IAC5E,cAAc,EAAE,IAAI,CAAA;IACpB,kFAAkF;IAClF,KAAK,EAAE,SAAS,CAAA;IAChB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,6BAA6B;IAC7B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,uBAAuB,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAGnD,oGAAoG;AACpG,eAAO,MAAM,cAAc,kMAUjB,CAAA;AAEV,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzD,oEAAoE;AACpE,MAAM,MAAM,eAAe,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI,IAAI,GAAG,WAAW,CAAA;AAE9E,wDAAwD;AACxD,MAAM,WAAW,uBAAuB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACnE,0CAA0C;IAC1C,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAA;IACnF,uCAAuC;IACvC,QAAQ,EAAE,IAAI,CAAA;IACd,4EAA4E;IAC5E,cAAc,EAAE,IAAI,CAAA;IACpB,kFAAkF;IAClF,KAAK,EAAE,SAAS,CAAA;IAChB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,6BAA6B;IAC7B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,uBAAuB,CAAC,IAAI,CAAC,sCAiHpG;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAA;IACV,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,sEAAsE;IACtE,UAAU,EAAE,OAAO,CAAA;IACnB,6DAA6D;IAC7D,OAAO,EAAE,OAAO,CAAA;IAChB,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAA;IACvB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAA;IACpB,gFAAgF;IAChF,QAAQ,EAAE,OAAO,CAAA;IACjB,wBAAwB;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,oEAAoE;IACpE,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,kHAAkH;AAClH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG;IAC7C,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,+BAqCA;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG;IAC/C,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;CACjB,+BAmCA;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG;IAC9C,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAA;IACpB,mEAAmE;IACnE,OAAO,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACzD,+BAsCA"}
|
|
@@ -46,7 +46,9 @@ export function PluginSettingsCard(props) {
|
|
|
46
46
|
: null] }));
|
|
47
47
|
}
|
|
48
48
|
return (_jsxs("li", { className: cardClass, children: [_jsxs("button", { type: "button", className: css.header, "aria-expanded": open, "aria-label": `${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`, onClick: () => { setOpen(!open); }, children: [_jsxs("span", { className: css.headText, children: [_jsx("span", { className: css.name, title: title, children: title }), _jsx("span", { className: css.description, title: description, children: description })] }), state.dirty ? _jsx("span", { className: css.pending, title: props.t('settings.unsaved'), children: props.t('settings.unsaved') }) : null, _jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: open ? `${css.chevron} ${css.chevronOpen}` : css.chevron, children: _jsx("path", { d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z", fill: "currentColor" }) })] }), open
|
|
49
|
-
? (_jsxs("div", { className: css.body, children: [!state.writable ? _jsx("p", { className: css.readOnly, role: "status", children: props.t('settings.readOnly') }) : null, props.children, _jsxs("div", { className: css.footer, children: [state.failed
|
|
49
|
+
? (_jsxs("div", { className: css.body, children: [!state.writable ? _jsx("p", { className: css.readOnly, role: "status", children: props.t('settings.readOnly') }) : null, props.children, _jsxs("div", { className: css.footer, children: [state.failed
|
|
50
|
+
? (_jsxs("p", { className: css.failed, role: "status", children: [props.t('settings.saveFailed'), state.failedReason ? ' - ' + state.failedReason : ''] }))
|
|
51
|
+
: null, _jsx("button", { type: "button", className: css.discard, disabled: !state.dirty || state.saving, onClick: props.onDiscard, children: props.t('settings.discard') }), _jsx("button", { type: "button", className: css.save, disabled: blocked, onClick: props.onSave, children: props.t(!state.saving ? 'settings.save' : 'settings.saving') })] })] }))
|
|
50
52
|
: null] }));
|
|
51
53
|
}
|
|
52
54
|
/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */
|
|
@@ -77,6 +77,8 @@ function errorMessageOf(t, result) {
|
|
|
77
77
|
case "not-found": return t("update.error.notFound");
|
|
78
78
|
case "link": return t("update.error.link");
|
|
79
79
|
case "pnpm-failed": return t("update.error.pnpmFailed", { code: String(result.exitCode ?? "?") });
|
|
80
|
+
case "stale": return t("update.error.stale");
|
|
81
|
+
case "verify-failed": return t("update.error.verifyFailed");
|
|
80
82
|
default: return result.error ?? t("update.error.unknown");
|
|
81
83
|
}
|
|
82
84
|
}
|
|
@@ -99,6 +99,8 @@ export declare const zh: {
|
|
|
99
99
|
'update.error.notFound': string;
|
|
100
100
|
'update.error.link': string;
|
|
101
101
|
'update.error.pnpmFailed': string;
|
|
102
|
+
'update.error.stale': string;
|
|
103
|
+
'update.error.verifyFailed': string;
|
|
102
104
|
'update.error.unknown': string;
|
|
103
105
|
};
|
|
104
106
|
/** The remote namespace key union. */
|
|
@@ -205,6 +207,8 @@ export declare const en: {
|
|
|
205
207
|
'update.error.notFound': string;
|
|
206
208
|
'update.error.link': string;
|
|
207
209
|
'update.error.pnpmFailed': string;
|
|
210
|
+
'update.error.stale': string;
|
|
211
|
+
'update.error.verifyFailed': string;
|
|
208
212
|
'update.error.unknown': string;
|
|
209
213
|
};
|
|
210
214
|
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,mEAAmE;AACnE,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwGmB,CAAA;AAElC,sCAAsC;AACtC,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,EAAE,CAAA;AAEvC,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,SAAS,CAAA;AAEvC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwGsB,CAAA"}
|
|
@@ -101,6 +101,8 @@ export const zh = {
|
|
|
101
101
|
'update.error.notFound': '未找到 dsh-web-ui 聚合包安装,无法更新。',
|
|
102
102
|
'update.error.link': '当前为本地开发模式(链接安装),无法自动更新。',
|
|
103
103
|
'update.error.pnpmFailed': '更新执行失败(pnpm 退出码 {code}),详见下方输出。',
|
|
104
|
+
'update.error.stale': '更新命令已执行,但安装版本未变化。常见原因:pnpm 11 的 minimumReleaseAge 门禁会静默跳过发布不足 24 小时的新版本。请在 profile 目录(~/.dsh/profiles/<profile>)的 pnpm-workspace.yaml 中配置 minimumReleaseAgeExclude(例如 "@linxin666/*")或 minimumReleaseAge: 0 后重新点击更新。',
|
|
105
|
+
'update.error.verifyFailed': '更新命令已执行,但无法核对安装后的版本(可能是 registry 探测失败或安装路径变化)。请查看下方输出,或稍后重试。',
|
|
104
106
|
'update.error.unknown': '更新失败,请重试。',
|
|
105
107
|
};
|
|
106
108
|
/** English dictionary, checked complete against the zh key set. */
|
|
@@ -205,5 +207,7 @@ export const en = {
|
|
|
205
207
|
'update.error.notFound': 'The dsh-web-ui aggregate package is not installed; nothing to update.',
|
|
206
208
|
'update.error.link': 'Local development mode (link install) — automatic update is unavailable.',
|
|
207
209
|
'update.error.pnpmFailed': 'The update failed (pnpm exited with code {code}); see the output below.',
|
|
210
|
+
'update.error.stale': 'The update command ran but the installed versions did not change. Likely cause: the pnpm 11 minimumReleaseAge gate silently skips releases published less than 24 hours ago. Add minimumReleaseAgeExclude (e.g. "@linxin666/*") or set minimumReleaseAge: 0 in pnpm-workspace.yaml under the profile directory (~/.dsh/profiles/<profile>), then run the update again.',
|
|
211
|
+
'update.error.verifyFailed': 'The update command ran but the installed versions could not be verified afterwards (registry probe failed or the install path changed). Inspect the output below, or retry later.',
|
|
208
212
|
'update.error.unknown': 'Update failed; try again.',
|
|
209
213
|
};
|
|
@@ -18,6 +18,14 @@ export type FieldWrite = {
|
|
|
18
18
|
export interface FieldSpec {
|
|
19
19
|
/** Field name inside the namespace section. */
|
|
20
20
|
field: string;
|
|
21
|
+
/**
|
|
22
|
+
* Whether the Host treats this field as a secret and redacts its value from
|
|
23
|
+
* the read-back (role('secret') in the section schema). Redacted secrets are
|
|
24
|
+
* never compared against the draft on save; the field lands when the scope
|
|
25
|
+
* reports the write succeeded (its secret-set marker under the bridge), so
|
|
26
|
+
* a successful secret save is not misreported as failed.
|
|
27
|
+
*/
|
|
28
|
+
secret?: boolean;
|
|
21
29
|
/** Render a stored value as draft text; the empty string when the section carries none. */
|
|
22
30
|
format: (value: unknown) => string;
|
|
23
31
|
/**
|
|
@@ -57,6 +65,12 @@ export interface CardShell {
|
|
|
57
65
|
saving: boolean;
|
|
58
66
|
/** Whether the last save did not land as staged; cleared by the next edit or save. */
|
|
59
67
|
failed: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* The rejection code/message the Host returned for the last failed save,
|
|
70
|
+
* surfaced next to the generic failure text. Undefined while no save has
|
|
71
|
+
* failed (or the failure carried no server reason).
|
|
72
|
+
*/
|
|
73
|
+
failedReason?: string;
|
|
60
74
|
}
|
|
61
75
|
/** The write actions the card's slot entry injects. */
|
|
62
76
|
export interface CardActions {
|
|
@@ -69,6 +83,37 @@ export interface CardActions {
|
|
|
69
83
|
/** Drop every staged edit. */
|
|
70
84
|
discard: () => void;
|
|
71
85
|
}
|
|
86
|
+
/** One durable write a batched settings scope performs. */
|
|
87
|
+
export interface BatchedWrite {
|
|
88
|
+
/** Field this entry writes. */
|
|
89
|
+
field: string;
|
|
90
|
+
/** set stores a value; unset drops the leaf. */
|
|
91
|
+
op: 'set' | 'unset';
|
|
92
|
+
/** Value for op set (absent for unset). */
|
|
93
|
+
value?: unknown;
|
|
94
|
+
}
|
|
95
|
+
/** Per-field outcome of one batched scope write. */
|
|
96
|
+
export interface BatchedFieldResult {
|
|
97
|
+
/** Field this entry writes. */
|
|
98
|
+
field: string;
|
|
99
|
+
/** Whether the Host accepted this field's write (per the read-back view). */
|
|
100
|
+
landed: boolean;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Result of a batched scope write. The bridge scope posts every planned write
|
|
104
|
+
* in one /mutate so the Host validate hook judges baseURL+model together; a
|
|
105
|
+
* batched refusal fails the whole save rather than per-field.
|
|
106
|
+
*/
|
|
107
|
+
export interface BatchResult {
|
|
108
|
+
/** Whether the whole mutate was accepted. */
|
|
109
|
+
ok: boolean;
|
|
110
|
+
/** Per-field success, in the request order (always present when ok). */
|
|
111
|
+
fields: BatchedFieldResult[];
|
|
112
|
+
/** Host rejection code (mutate refused). */
|
|
113
|
+
code?: string;
|
|
114
|
+
/** Host rejection message (mutate refused). */
|
|
115
|
+
message?: string;
|
|
116
|
+
}
|
|
72
117
|
/** Constraints a numeric field's accepted drafts must satisfy, mirroring the host schema. */
|
|
73
118
|
export interface NumberConstraints {
|
|
74
119
|
/** The accepted value must be a whole number. */
|
|
@@ -80,6 +125,13 @@ export interface NumberConstraints {
|
|
|
80
125
|
export declare function numberField(field: string, constraints?: NumberConstraints): FieldSpec;
|
|
81
126
|
/** A free-text field. An empty draft clears the field. */
|
|
82
127
|
export declare function textField(field: string): FieldSpec;
|
|
128
|
+
/**
|
|
129
|
+
* A free-text field the Host treats as a secret and redacts from the read-back
|
|
130
|
+
* (role('secret') in the section schema). The card still edits it like text,
|
|
131
|
+
* but a save never compares the redacted value back and relies on the scope
|
|
132
|
+
* reporting the write landed.
|
|
133
|
+
*/
|
|
134
|
+
export declare function secretField(field: string): FieldSpec;
|
|
83
135
|
/** A boolean field, edited through true/false draft text. */
|
|
84
136
|
export declare function booleanField(field: string): FieldSpec;
|
|
85
137
|
/** An enumerated string field; only the listed choices are accepted. An empty draft clears the field. */
|
|
@@ -99,6 +151,7 @@ export declare class CardForm<T> {
|
|
|
99
151
|
private readonly listeners;
|
|
100
152
|
private saving;
|
|
101
153
|
private failed;
|
|
154
|
+
private failedReason;
|
|
102
155
|
/** @param scope - the bound settings scope for this card's namespace. */
|
|
103
156
|
constructor(scope: SettingsScope<T>, specs: FieldSpec[]);
|
|
104
157
|
/** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */
|
|
@@ -111,9 +164,18 @@ export declare class CardForm<T> {
|
|
|
111
164
|
actions(): CardActions;
|
|
112
165
|
/**
|
|
113
166
|
* Write every staged edit, then re-seed from what the Host accepted.
|
|
167
|
+
*
|
|
168
|
+
* When the scope carries the optional batch surface (the dsh-web-ui
|
|
169
|
+
* bridge scope), every planned write rides one mutation so cross-field
|
|
170
|
+
* validate hooks (baseURL+model) judge the batch as a unit instead of
|
|
171
|
+
* deadlocking on per-field writes. Otherwise the per-field loop runs.
|
|
172
|
+
* A field lands only when the Host reports it held the staged value; a
|
|
173
|
+
* landed field's draft is dropped, a failed one stays staged for the user.
|
|
114
174
|
* @returns settlement after every write and the read-back.
|
|
115
175
|
*/
|
|
116
176
|
save(): Promise<void>;
|
|
177
|
+
/** The scope's batch surface when it supports one; undefined conservatively otherwise. */
|
|
178
|
+
private batchedScope;
|
|
117
179
|
/**
|
|
118
180
|
* Every staged edit a save would write. An entry whose draft is not a value
|
|
119
181
|
* its field accepts carries no write: the form is still dirty, and the save
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-form.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAyB,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAGjH,yEAAyE;AACzE,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAA;AAErB,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAA;IACb,2FAA2F;IAC3F,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAA;IAClC;;;OAGG;IACH,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAA;CAChD;AAED,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,oEAAoE;IACpE,UAAU,EAAE,OAAO,CAAA;IACnB,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,oDAAoD;AACpD,MAAM,WAAW,SAAS;IACxB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB,gDAAgD;IAChD,QAAQ,EAAE,OAAO,CAAA;IACjB,4DAA4D;IAC5D,KAAK,EAAE,OAAO,CAAA;IACd,kEAAkE;IAClE,OAAO,EAAE,OAAO,CAAA;IAChB,2CAA2C;IAC3C,MAAM,EAAE,OAAO,CAAA;IACf,sFAAsF;IACtF,MAAM,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-form.ts"],"names":[],"mappings":"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"}
|