@xrxs-ai/dsh-xrxs-plugins-store 0.2.5 → 0.2.7
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/lib/client.js +215 -128
- package/lib/host/installer.d.ts +3 -0
- package/lib/host/installer.js +13 -2
- package/lib/host/routes.js +8 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -30,10 +30,10 @@ __export(index_exports, {
|
|
|
30
30
|
inject: () => inject
|
|
31
31
|
});
|
|
32
32
|
module.exports = __toCommonJS(index_exports);
|
|
33
|
-
var
|
|
33
|
+
var import_react13 = require("react");
|
|
34
34
|
|
|
35
35
|
// src/client/MarketplaceApp.tsx
|
|
36
|
-
var
|
|
36
|
+
var import_react10 = require("react");
|
|
37
37
|
|
|
38
38
|
// src/client/pages/DeveloperPage.tsx
|
|
39
39
|
var import_react4 = require("react");
|
|
@@ -462,6 +462,13 @@ function formatDate(text) {
|
|
|
462
462
|
if (d === null) return text;
|
|
463
463
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
464
464
|
}
|
|
465
|
+
function formatShortDate(text) {
|
|
466
|
+
const d = parseTime(text);
|
|
467
|
+
if (d === null) return text;
|
|
468
|
+
const now = /* @__PURE__ */ new Date();
|
|
469
|
+
const yearPrefix = d.getFullYear() === now.getFullYear() ? "" : `${String(d.getFullYear() % 100).padStart(2, "0")}-`;
|
|
470
|
+
return `${yearPrefix}${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
471
|
+
}
|
|
465
472
|
function formatRelative(text) {
|
|
466
473
|
const parsed = parseTime(text);
|
|
467
474
|
if (parsed === null) return text;
|
|
@@ -926,14 +933,27 @@ var MARKET_CSS = `
|
|
|
926
933
|
font-size: 13px; line-height: 18px; color: var(--dsw-alias-label-tertiary, #8f959e);
|
|
927
934
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
928
935
|
}
|
|
936
|
+
/* \u884C\u5C3E\u5143\u4FE1\u606F\u6309\u56FA\u5B9A\u56DB\u5217\u6392(\u7248\u672C / \u4E0B\u8F7D\u91CF / \u517C\u5BB9\u6027 / \u64CD\u4F5C),\u9010\u5217\u4E0E\u4E0A\u4E0B\u884C\u5BF9\u9F50:
|
|
937
|
+
\u82E5\u7528\u53F3\u5BF9\u9F50 flex,\u672B\u5217(\u6309\u94AE\u6216\u300C\u5DF2\u5B89\u88C5\u300D\u5FBD\u6807)\u5BBD\u5EA6\u4E0D\u540C\u4F1A\u628A\u5DE6\u8FB9\u6240\u6709\u5217\u4E00\u8D77\u63A8\u7740\u5DE6\u53F3\u6D6E\u52A8 */
|
|
929
938
|
.xps-mk-row-meta {
|
|
930
|
-
flex: none;
|
|
939
|
+
flex: none;
|
|
940
|
+
display: grid;
|
|
941
|
+
grid-template-columns: 140px 56px 124px 74px;
|
|
942
|
+
align-items: center;
|
|
943
|
+
justify-items: end;
|
|
944
|
+
column-gap: 8px;
|
|
931
945
|
font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary, #8f959e);
|
|
932
946
|
}
|
|
947
|
+
.xps-mk-row-meta > * { min-width: 0; }
|
|
933
948
|
.xps-mk-row-version {
|
|
934
949
|
font-variant-numeric: tabular-nums;
|
|
935
950
|
font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
951
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
936
952
|
}
|
|
953
|
+
.xps-mk-row-downloads { font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
954
|
+
/* \u517C\u5BB9\u6027\u5FBD\u6807\u5217\u5BBD\u56FA\u5B9A:\u8D85\u957F compatRange \u7684\u4E0D\u6362\u884C\u5FBD\u6807\u5217\u5185\u53F3\u5BF9\u9F50,\u6EA2\u51FA\u65F6\u5411\u5DE6\u8BA9\u4F4D(\u4E0D\u628A\u5217\u6491\u5BBD) */
|
|
955
|
+
.xps-mk-row-compat { display: inline-flex; justify-content: flex-end; }
|
|
956
|
+
.xps-mk-row-action { display: inline-flex; justify-content: flex-end; }
|
|
937
957
|
/* \u56FE\u6807:r11;\u5F69\u8272\u6E10\u53D8\u7531 PluginIcon \u5185\u8054 gradient,\u65E0 hairline */
|
|
938
958
|
/* \u56FE\u6807:r10(\u4E0E\u5DF2\u88C5\u9875 .xps-row-icon \u7684 40px \u5706\u89D2\u4E00\u81F4) */
|
|
939
959
|
.xps-mk-icon {
|
|
@@ -1042,30 +1062,8 @@ var MARKET_CSS = `
|
|
|
1042
1062
|
font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-primary, #1f2329);
|
|
1043
1063
|
text-align: right; word-break: break-all;
|
|
1044
1064
|
}
|
|
1045
|
-
.xps-mk-
|
|
1046
|
-
|
|
1047
|
-
width: 100%; box-sizing: border-box; padding: 4px 8px;
|
|
1048
|
-
border: none; border-radius: 8px; background: transparent; cursor: pointer;
|
|
1049
|
-
color: var(--dsw-alias-label-primary, #1f2329);
|
|
1050
|
-
font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
1051
|
-
font-size: 12px; line-height: 18px; text-align: left;
|
|
1052
|
-
transition: background-color 0.15s ease;
|
|
1053
|
-
}
|
|
1054
|
-
.xps-mk-version:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(31, 35, 41, 0.06)); }
|
|
1055
|
-
.xps-mk-version:active { background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1)); }
|
|
1056
|
-
.xps-mk-version:focus-visible {
|
|
1057
|
-
outline: 2px solid var(--dsw-alias-brand-primary, #3370ff);
|
|
1058
|
-
outline-offset: -2px;
|
|
1059
|
-
}
|
|
1060
|
-
.xps-mk-version-active, .xps-mk-version-active:hover {
|
|
1061
|
-
background: var(--dsw-alias-interactive-bg-active, rgba(38, 49, 72, 0.1));
|
|
1062
|
-
color: var(--dsw-alias-label-primary, #1f2329);
|
|
1063
|
-
}
|
|
1064
|
-
.xps-mk-version-date {
|
|
1065
|
-
flex: none; font-size: 11px; line-height: 17px;
|
|
1066
|
-
font-family: inherit;
|
|
1067
|
-
color: var(--dsw-alias-label-tertiary, #8f959e);
|
|
1068
|
-
}
|
|
1065
|
+
/* \u8BE6\u60C5\u9875\u7248\u672C\u5386\u53F2\u4E0B\u62C9:\u5360\u6EE1\u5361\u7247\u5BBD(.xps-mk-select \u9ED8\u8BA4 flex:none \u53EA\u9002\u914D\u5DE5\u5177\u680F) */
|
|
1066
|
+
.xps-mk-version-select { display: block; width: 100%; margin-top: 8px; }
|
|
1069
1067
|
|
|
1070
1068
|
/* README markdown \u767D\u540D\u5355\u6E32\u67D3 */
|
|
1071
1069
|
.xps-md {
|
|
@@ -1094,6 +1092,17 @@ var MARKET_CSS = `
|
|
|
1094
1092
|
cursor: pointer; text-decoration: none;
|
|
1095
1093
|
}
|
|
1096
1094
|
.xps-md-link:hover { text-decoration: underline; }
|
|
1095
|
+
/* README \u56FE\u7247:\u4E0D\u8D85\u51FA\u6B63\u6587\u5BBD(\u5FBD\u6807\u7C7B\u5C0F\u56FE\u4FDD\u6301\u539F\u59CB\u5C3A\u5BF8);\u52A0\u8F7D\u5931\u8D25\u964D\u7EA7\u4E3A\u7070\u8272\u6587\u672C */
|
|
1096
|
+
.xps-md-img {
|
|
1097
|
+
max-width: 100%; height: auto;
|
|
1098
|
+
border-radius: 6px; vertical-align: middle;
|
|
1099
|
+
}
|
|
1100
|
+
.xps-md-img-fallback {
|
|
1101
|
+
display: inline-block; padding: 0 4px;
|
|
1102
|
+
font-size: 12px; color: var(--dsw-alias-label-tertiary, #8f959e);
|
|
1103
|
+
background: var(--dsw-alias-bg-layer-2, #f5f6f7);
|
|
1104
|
+
border-radius: 4px;
|
|
1105
|
+
}
|
|
1097
1106
|
.xps-md-table-wrap { margin: 8px 0; overflow-x: auto; }
|
|
1098
1107
|
.xps-md-table {
|
|
1099
1108
|
border-collapse: collapse; width: 100%; font-size: 12px; line-height: 1.6;
|
|
@@ -1125,8 +1134,7 @@ var MARKET_CSS = `
|
|
|
1125
1134
|
.xps-mk-chip,
|
|
1126
1135
|
.xps-mk-row,
|
|
1127
1136
|
.xps-mk-page,
|
|
1128
|
-
.xps-mk-select
|
|
1129
|
-
.xps-mk-version {
|
|
1137
|
+
.xps-mk-select {
|
|
1130
1138
|
transition: none;
|
|
1131
1139
|
}
|
|
1132
1140
|
.xps-mk-page:active:not(:disabled) {
|
|
@@ -1807,7 +1815,7 @@ function UploadForm(props) {
|
|
|
1807
1815
|
] }),
|
|
1808
1816
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("li", { children: [
|
|
1809
1817
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: "README \u8BF7\u5C3D\u91CF\u5199\u6E05\u695A:" }),
|
|
1810
|
-
"README \u662F\u5E02\u573A\u8BE6\u60C5\u9875\u7684\u5168\u90E8\u5C55\u793A\u5185\u5BB9,\u652F\u6301\u6807\u51C6 markdown(\u6807\u9898\u3001\u5217\u8868\u3001\u8868\u683C\u3001\u4EE3\u7801\u5757\u3001\u94FE\u63A5)\u3002\u5EFA\u8BAE\u5305\u542B:\u63D2\u4EF6\u89E3\u51B3\u4EC0\u4E48\u95EE\u9898\u3001\u5982\u4F55\u5B89\u88C5\u542F\u7528\u3001\u5404\u529F\u80FD\u600E\u4E48\u7528\u3001\u6709\u54EA\u4E9B\u914D\u7F6E\u9879\u4E0E\u6CE8\u610F\u4E8B\u9879 \u2014\u2014 \u8BF4\u660E\u8D8A\u5B8C\u6574,\u8D8A\u5BB9\u6613\u901A\u8FC7\u5BA1\u6838,\u4E5F\u8D8A\u5BB9\u6613\u88AB\u4F7F\u7528\u3002"
|
|
1818
|
+
"README \u662F\u5E02\u573A\u8BE6\u60C5\u9875\u7684\u5168\u90E8\u5C55\u793A\u5185\u5BB9,\u652F\u6301\u6807\u51C6 markdown(\u6807\u9898\u3001\u5217\u8868\u3001\u8868\u683C\u3001\u4EE3\u7801\u5757\u3001\u94FE\u63A5\u3001\u56FE\u7247 \u2014\u2014 \u56FE\u7247\u4EC5\u652F\u6301 http/https \u5916\u94FE,\u4E0D\u652F\u6301\u76F8\u5BF9\u8DEF\u5F84)\u3002\u5EFA\u8BAE\u5305\u542B:\u63D2\u4EF6\u89E3\u51B3\u4EC0\u4E48\u95EE\u9898\u3001\u5982\u4F55\u5B89\u88C5\u542F\u7528\u3001\u5404\u529F\u80FD\u600E\u4E48\u7528\u3001\u6709\u54EA\u4E9B\u914D\u7F6E\u9879\u4E0E\u6CE8\u610F\u4E8B\u9879 \u2014\u2014 \u8BF4\u660E\u8D8A\u5B8C\u6574,\u8D8A\u5BB9\u6613\u901A\u8FC7\u5BA1\u6838,\u4E5F\u8D8A\u5BB9\u6613\u88AB\u4F7F\u7528\u3002"
|
|
1811
1819
|
] }),
|
|
1812
1820
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("li", { children: [
|
|
1813
1821
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: "\u4EA7\u7269\u5305(*.tgz):" }),
|
|
@@ -2267,6 +2275,12 @@ function ConfirmDialog3(props) {
|
|
|
2267
2275
|
] })
|
|
2268
2276
|
] }) });
|
|
2269
2277
|
}
|
|
2278
|
+
function byInstalledAtDesc(a, b) {
|
|
2279
|
+
const ta = a.installedAt ?? "";
|
|
2280
|
+
const tb = b.installedAt ?? "";
|
|
2281
|
+
if (ta !== tb) return ta < tb ? 1 : -1;
|
|
2282
|
+
return a.name.localeCompare(b.name);
|
|
2283
|
+
}
|
|
2270
2284
|
function InstalledPage() {
|
|
2271
2285
|
ensureMarketStyles();
|
|
2272
2286
|
const { items, push, dismiss } = useToasts();
|
|
@@ -2280,7 +2294,7 @@ function InstalledPage() {
|
|
|
2280
2294
|
const load = (0, import_react5.useCallback)(() => {
|
|
2281
2295
|
setList(null);
|
|
2282
2296
|
setError(false);
|
|
2283
|
-
void getInstalled().then((installed) => setList(installed)).catch(() => {
|
|
2297
|
+
void getInstalled().then((installed) => setList([...installed].sort(byInstalledAtDesc))).catch(() => {
|
|
2284
2298
|
setList([]);
|
|
2285
2299
|
setError(true);
|
|
2286
2300
|
});
|
|
@@ -2549,6 +2563,24 @@ function satisfies(version, range) {
|
|
|
2549
2563
|
|
|
2550
2564
|
// src/client/pages/market/InstallButton.tsx
|
|
2551
2565
|
var import_react6 = require("react");
|
|
2566
|
+
|
|
2567
|
+
// src/client/pages/market/version.ts
|
|
2568
|
+
function compareVersions(a, b) {
|
|
2569
|
+
const parse = (text) => text.trim().replace(/^v/, "").split(".").map((part) => {
|
|
2570
|
+
const numeric = /^\d+/.exec(part);
|
|
2571
|
+
return numeric === null ? 0 : Number(numeric[0]);
|
|
2572
|
+
});
|
|
2573
|
+
const left = parse(a);
|
|
2574
|
+
const right = parse(b);
|
|
2575
|
+
const length = Math.max(left.length, right.length);
|
|
2576
|
+
for (let index = 0; index < length; index += 1) {
|
|
2577
|
+
const diff = (left[index] ?? 0) - (right[index] ?? 0);
|
|
2578
|
+
if (diff !== 0) return diff > 0 ? 1 : -1;
|
|
2579
|
+
}
|
|
2580
|
+
return 0;
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
// src/client/pages/market/InstallButton.tsx
|
|
2552
2584
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2553
2585
|
function InstallButton(props) {
|
|
2554
2586
|
const [phase, setPhase] = (0, import_react6.useState)("idle");
|
|
@@ -2556,10 +2588,11 @@ function InstallButton(props) {
|
|
|
2556
2588
|
const [buildConfirm, setBuildConfirm] = (0, import_react6.useState)(null);
|
|
2557
2589
|
const [approving, setApproving] = (0, import_react6.useState)(false);
|
|
2558
2590
|
const compat = checkCompat(props.compatRange, props.dshVersion);
|
|
2559
|
-
const
|
|
2560
|
-
const
|
|
2561
|
-
|
|
2562
|
-
|
|
2591
|
+
const sameAsInstalled = props.installed !== void 0 && props.installed.version === props.version;
|
|
2592
|
+
const verb = props.installed === void 0 || sameAsInstalled ? "\u5B89\u88C5" : compareVersions(props.version, props.installed.version) >= 0 ? "\u66F4\u65B0" : "\u964D\u7EA7";
|
|
2593
|
+
const variant = verb === "\u5B89\u88C5" ? "primary" : "update";
|
|
2594
|
+
if (sameAsInstalled) {
|
|
2595
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "xps-mk-install", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Button, { size: props.size ?? "medium", variant: "primary", disabled: true, title: "\u5DF2\u5B89\u88C5\u6B64\u7248\u672C,\u91CD\u88C5\u540C\u7248\u672C\u4E0D\u4F1A\u5237\u65B0", children: "\u5DF2\u5B89\u88C5" }) });
|
|
2563
2596
|
}
|
|
2564
2597
|
if (compat.ok === false) {
|
|
2565
2598
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "xps-mk-install", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
@@ -2692,6 +2725,8 @@ function PluginRow(props) {
|
|
|
2692
2725
|
const compat = checkCompat(p.compatRange, props.dshVersion);
|
|
2693
2726
|
const installed = props.installed;
|
|
2694
2727
|
const upToDate = installed !== void 0 && !installed.updateAvailable;
|
|
2728
|
+
const versionLabel = installed !== void 0 && installed.updateAvailable ? `v${installed.version} \u2192 v${p.version}` : `v${p.version}`;
|
|
2729
|
+
const versionTitle = installed !== void 0 && installed.updateAvailable ? `\u672C\u673A\u5DF2\u5B89\u88C5 v${installed.version},\u53EF\u66F4\u65B0\u5230\u5E02\u573A\u6700\u65B0 v${p.version}` : `\u5E02\u573A\u6700\u65B0\u7248\u672C v${p.version}`;
|
|
2695
2730
|
const open = () => props.onOpen?.(p.id);
|
|
2696
2731
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
2697
2732
|
"div",
|
|
@@ -2715,23 +2750,16 @@ function PluginRow(props) {
|
|
|
2715
2750
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "xps-mk-row-summary", children: p.summary })
|
|
2716
2751
|
] }),
|
|
2717
2752
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "xps-mk-row-meta", children: [
|
|
2718
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.
|
|
2719
|
-
|
|
2720
|
-
p.version
|
|
2721
|
-
] }),
|
|
2722
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { title: `\u4E0B\u8F7D\u91CF ${p.downloads}`, children: [
|
|
2753
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "xps-mk-row-version", title: versionTitle, children: versionLabel }),
|
|
2754
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "xps-mk-row-downloads", title: `\u4E0B\u8F7D\u91CF ${p.downloads}`, children: [
|
|
2723
2755
|
"\u2B07 ",
|
|
2724
2756
|
formatDownloads(p.downloads)
|
|
2725
2757
|
] }),
|
|
2726
|
-
compat.ok === null ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { children: "? \u517C\u5BB9\u6027\u672A\u77E5" }) : compat.ok ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "success", children: "\u2714 \u517C\u5BB9\u672C\u673A" }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Badge, { tone: "warning", children: [
|
|
2758
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "xps-mk-row-compat", children: compat.ok === null ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { children: "? \u517C\u5BB9\u6027\u672A\u77E5" }) : compat.ok ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "success", children: "\u2714 \u517C\u5BB9\u672C\u673A" }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Badge, { tone: "warning", children: [
|
|
2727
2759
|
"\u26A0 \u9700 dsh ",
|
|
2728
2760
|
p.compatRange
|
|
2729
|
-
] }),
|
|
2730
|
-
|
|
2731
|
-
"\u2191 \u53EF\u66F4\u65B0 v",
|
|
2732
|
-
installed.version
|
|
2733
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "success", children: "\u2713 \u5DF2\u5B89\u88C5" })),
|
|
2734
|
-
!upToDate && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2761
|
+
] }) }),
|
|
2762
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "xps-mk-row-action", children: upToDate ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "success", children: "\u2713 \u5DF2\u5B89\u88C5" }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2735
2763
|
InstallButton,
|
|
2736
2764
|
{
|
|
2737
2765
|
pluginName: p.name,
|
|
@@ -2744,7 +2772,7 @@ function PluginRow(props) {
|
|
|
2744
2772
|
size: "small",
|
|
2745
2773
|
onToast: props.onToast
|
|
2746
2774
|
}
|
|
2747
|
-
)
|
|
2775
|
+
) })
|
|
2748
2776
|
] })
|
|
2749
2777
|
]
|
|
2750
2778
|
}
|
|
@@ -3002,9 +3030,10 @@ function MarketPage(props) {
|
|
|
3002
3030
|
}
|
|
3003
3031
|
|
|
3004
3032
|
// src/client/pages/PluginDetailPage.tsx
|
|
3005
|
-
var
|
|
3033
|
+
var import_react9 = require("react");
|
|
3006
3034
|
|
|
3007
3035
|
// src/client/pages/market/Markdown.tsx
|
|
3036
|
+
var import_react8 = require("react");
|
|
3008
3037
|
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
3009
3038
|
function Markdown(props) {
|
|
3010
3039
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "xps-md", children: renderBlocks(props.text) });
|
|
@@ -3142,16 +3171,80 @@ function renderBlocks(text, depth = 0) {
|
|
|
3142
3171
|
}
|
|
3143
3172
|
return blocks;
|
|
3144
3173
|
}
|
|
3174
|
+
function MarkdownImage(props) {
|
|
3175
|
+
const [failed, setFailed] = (0, import_react8.useState)(false);
|
|
3176
|
+
(0, import_react8.useEffect)(() => setFailed(false), [props.src]);
|
|
3177
|
+
if (failed) {
|
|
3178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "xps-md-img-fallback", title: props.alt, children: props.alt === "" ? "[\u56FE\u7247\u52A0\u8F7D\u5931\u8D25]" : `[\u56FE\u7247\u52A0\u8F7D\u5931\u8D25:${props.alt}]` });
|
|
3179
|
+
}
|
|
3180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3181
|
+
"img",
|
|
3182
|
+
{
|
|
3183
|
+
className: "xps-md-img",
|
|
3184
|
+
src: props.src,
|
|
3185
|
+
alt: props.alt,
|
|
3186
|
+
loading: "lazy",
|
|
3187
|
+
referrerPolicy: "no-referrer",
|
|
3188
|
+
onError: () => setFailed(true)
|
|
3189
|
+
}
|
|
3190
|
+
);
|
|
3191
|
+
}
|
|
3192
|
+
function renderLink(url, content, key) {
|
|
3193
|
+
if (!/^https?:\/\//.test(url)) return null;
|
|
3194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3195
|
+
"span",
|
|
3196
|
+
{
|
|
3197
|
+
className: "xps-md-link",
|
|
3198
|
+
role: "link",
|
|
3199
|
+
tabIndex: 0,
|
|
3200
|
+
onClick: () => void window.open(url, "_blank", "noopener,noreferrer"),
|
|
3201
|
+
onKeyDown: (event) => {
|
|
3202
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
3203
|
+
event.preventDefault();
|
|
3204
|
+
void window.open(url, "_blank", "noopener,noreferrer");
|
|
3205
|
+
}
|
|
3206
|
+
},
|
|
3207
|
+
children: content
|
|
3208
|
+
},
|
|
3209
|
+
key
|
|
3210
|
+
);
|
|
3211
|
+
}
|
|
3145
3212
|
function renderInline(text, keyPrefix) {
|
|
3146
3213
|
const nodes = [];
|
|
3147
|
-
const pattern = /(
|
|
3214
|
+
const pattern = /(\[!\[[^\]]*\]\(\s*[^()\s]*(?:\([^()\s]*\)[^()\s]*)?\s*\)\]\(\s*[^()\s]*(?:\([^()\s]*\)[^()\s]*)?\s*\)|!\[[^\]]*\]\(\s*[^()\s]*(?:\([^()\s]*\)[^()\s]*)?\s*\)|\*\*[^*]+\*\*|~~[^~]+~~|`[^`]+`|\[[^\]]*\]\(\s*[^()\s]*(?:\([^()\s]*\)[^()\s]*)?\s*\))/g;
|
|
3148
3215
|
let last = 0;
|
|
3149
3216
|
let seq = 0;
|
|
3150
3217
|
let m;
|
|
3151
3218
|
while ((m = pattern.exec(text)) !== null) {
|
|
3152
3219
|
if (m.index > last) nodes.push(text.slice(last, m.index));
|
|
3153
3220
|
const token = m[0];
|
|
3154
|
-
if (token.startsWith("
|
|
3221
|
+
if (token.startsWith("[;
|
|
3223
|
+
const inner = token.slice(1, split);
|
|
3224
|
+
const href = token.slice(split + 2, -1).trim();
|
|
3225
|
+
const image = /^!\[([^\]]*)\]\(([\s\S]*)\)$/.exec(inner);
|
|
3226
|
+
if (image === null) {
|
|
3227
|
+
nodes.push(token);
|
|
3228
|
+
} else {
|
|
3229
|
+
const [, alt = "", rawSrc = ""] = image;
|
|
3230
|
+
const src = rawSrc.trim();
|
|
3231
|
+
const picture = /^https?:\/\//.test(src) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MarkdownImage, { src, alt }, `${keyPrefix}-nimg${seq}`) : alt === "" ? token : alt;
|
|
3232
|
+
nodes.push(renderLink(href, picture, `${keyPrefix}-na${seq}`) ?? picture);
|
|
3233
|
+
}
|
|
3234
|
+
} else if (token.startsWith("![")) {
|
|
3235
|
+
const image = /^!\[([^\]]*)\]\((.+)\)$/.exec(token);
|
|
3236
|
+
if (image === null) {
|
|
3237
|
+
nodes.push(token);
|
|
3238
|
+
} else {
|
|
3239
|
+
const [, alt = "", rawSrc = ""] = image;
|
|
3240
|
+
const src = rawSrc.trim();
|
|
3241
|
+
if (/^https?:\/\//.test(src)) {
|
|
3242
|
+
nodes.push(/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MarkdownImage, { src, alt }, `${keyPrefix}-img${seq}`));
|
|
3243
|
+
} else {
|
|
3244
|
+
nodes.push(token);
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
} else if (token.startsWith("**")) {
|
|
3155
3248
|
nodes.push(
|
|
3156
3249
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: renderInline(token.slice(2, -2), `${keyPrefix}-b${seq}`) }, `${keyPrefix}-b${seq}`)
|
|
3157
3250
|
);
|
|
@@ -3169,32 +3262,8 @@ function renderInline(text, keyPrefix) {
|
|
|
3169
3262
|
nodes.push(token);
|
|
3170
3263
|
} else {
|
|
3171
3264
|
const [, label = "", rawUrl = ""] = link;
|
|
3172
|
-
const isImage = label.startsWith("!");
|
|
3173
|
-
const text2 = isImage ? label.slice(1) : label;
|
|
3174
3265
|
const url = rawUrl.trim();
|
|
3175
|
-
|
|
3176
|
-
nodes.push(
|
|
3177
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3178
|
-
"span",
|
|
3179
|
-
{
|
|
3180
|
-
className: "xps-md-link",
|
|
3181
|
-
role: "link",
|
|
3182
|
-
tabIndex: 0,
|
|
3183
|
-
onClick: () => void window.open(url, "_blank", "noopener,noreferrer"),
|
|
3184
|
-
onKeyDown: (event) => {
|
|
3185
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
3186
|
-
event.preventDefault();
|
|
3187
|
-
void window.open(url, "_blank", "noopener,noreferrer");
|
|
3188
|
-
}
|
|
3189
|
-
},
|
|
3190
|
-
children: text2 === "" ? url : text2
|
|
3191
|
-
},
|
|
3192
|
-
`${keyPrefix}-a${seq}`
|
|
3193
|
-
)
|
|
3194
|
-
);
|
|
3195
|
-
} else {
|
|
3196
|
-
nodes.push(isImage ? label : token);
|
|
3197
|
-
}
|
|
3266
|
+
nodes.push(renderLink(url, label === "" ? url : label, `${keyPrefix}-a${seq}`) ?? token);
|
|
3198
3267
|
}
|
|
3199
3268
|
}
|
|
3200
3269
|
last = m.index + token.length;
|
|
@@ -3226,20 +3295,40 @@ var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
|
3226
3295
|
function PluginDetailPage(props) {
|
|
3227
3296
|
ensureMarketStyles();
|
|
3228
3297
|
const pluginId = props.pluginId ?? "";
|
|
3229
|
-
const [detail, setDetail] = (0,
|
|
3230
|
-
const [status, setStatus] = (0,
|
|
3231
|
-
const [selectedVersion, setSelectedVersion] = (0,
|
|
3232
|
-
const [reloadFlag, setReloadFlag] = (0,
|
|
3233
|
-
const [dshVersion, setDshVersion] = (0,
|
|
3234
|
-
const [installed, setInstalled] = (0,
|
|
3298
|
+
const [detail, setDetail] = (0, import_react9.useState)(null);
|
|
3299
|
+
const [status, setStatus] = (0, import_react9.useState)("loading");
|
|
3300
|
+
const [selectedVersion, setSelectedVersion] = (0, import_react9.useState)(null);
|
|
3301
|
+
const [reloadFlag, setReloadFlag] = (0, import_react9.useState)(0);
|
|
3302
|
+
const [dshVersion, setDshVersion] = (0, import_react9.useState)(null);
|
|
3303
|
+
const [installed, setInstalled] = (0, import_react9.useState)(null);
|
|
3235
3304
|
const toasts = useToasts();
|
|
3236
|
-
const
|
|
3237
|
-
|
|
3238
|
-
|
|
3305
|
+
const installedSeq = (0, import_react9.useRef)(0);
|
|
3306
|
+
const loadInstalled = (0, import_react9.useCallback)(
|
|
3307
|
+
(...names) => {
|
|
3308
|
+
const seq = ++installedSeq.current;
|
|
3309
|
+
getInstalled().then((list) => {
|
|
3310
|
+
if (seq === installedSeq.current) {
|
|
3311
|
+
setInstalled(list.find((item) => names.includes(item.name)) ?? null);
|
|
3312
|
+
}
|
|
3313
|
+
}).catch(() => {
|
|
3314
|
+
if (seq === installedSeq.current) setInstalled(null);
|
|
3315
|
+
});
|
|
3239
3316
|
},
|
|
3240
3317
|
[]
|
|
3241
3318
|
);
|
|
3242
|
-
|
|
3319
|
+
const selectVersion = (version) => {
|
|
3320
|
+
setSelectedVersion(version);
|
|
3321
|
+
if (detail !== null) loadInstalled(pluginId, detail.name);
|
|
3322
|
+
};
|
|
3323
|
+
(0, import_react9.useEffect)(() => {
|
|
3324
|
+
if (detail === null) return;
|
|
3325
|
+
const onVisible = () => {
|
|
3326
|
+
if (document.visibilityState === "visible") loadInstalled(pluginId, detail.name);
|
|
3327
|
+
};
|
|
3328
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
3329
|
+
return () => document.removeEventListener("visibilitychange", onVisible);
|
|
3330
|
+
}, [detail, pluginId, loadInstalled]);
|
|
3331
|
+
(0, import_react9.useEffect)(() => {
|
|
3243
3332
|
let alive = true;
|
|
3244
3333
|
getHostInfo().then((info) => {
|
|
3245
3334
|
if (alive) setDshVersion(info.dshVersion);
|
|
@@ -3249,13 +3338,12 @@ function PluginDetailPage(props) {
|
|
|
3249
3338
|
alive = false;
|
|
3250
3339
|
};
|
|
3251
3340
|
}, []);
|
|
3252
|
-
(0,
|
|
3341
|
+
(0, import_react9.useEffect)(() => {
|
|
3253
3342
|
let alive = true;
|
|
3254
3343
|
setStatus("loading");
|
|
3255
3344
|
setDetail(null);
|
|
3256
3345
|
setSelectedVersion(null);
|
|
3257
3346
|
setInstalled(null);
|
|
3258
|
-
if (pluginId !== "") loadInstalled(pluginId);
|
|
3259
3347
|
getPluginDetail(pluginId).then((d) => {
|
|
3260
3348
|
if (!alive) return;
|
|
3261
3349
|
if (d === null) {
|
|
@@ -3264,6 +3352,7 @@ function PluginDetailPage(props) {
|
|
|
3264
3352
|
setDetail(d);
|
|
3265
3353
|
setSelectedVersion(d.version);
|
|
3266
3354
|
setStatus("ready");
|
|
3355
|
+
loadInstalled(pluginId, d.name);
|
|
3267
3356
|
}
|
|
3268
3357
|
}).catch(() => {
|
|
3269
3358
|
if (alive) setStatus("error");
|
|
@@ -3351,7 +3440,7 @@ function PluginDetailPage(props) {
|
|
|
3351
3440
|
sourceType: detail.sourceType,
|
|
3352
3441
|
dshVersion,
|
|
3353
3442
|
installed: installed ?? void 0,
|
|
3354
|
-
onInstalled: () => loadInstalled(detail.name),
|
|
3443
|
+
onInstalled: () => loadInstalled(pluginId, detail.name),
|
|
3355
3444
|
onToast: toasts.push
|
|
3356
3445
|
}
|
|
3357
3446
|
)
|
|
@@ -3380,24 +3469,22 @@ function PluginDetailPage(props) {
|
|
|
3380
3469
|
] }),
|
|
3381
3470
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "xps-mk-card", children: [
|
|
3382
3471
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "xps-mk-card-title", children: "\u7248\u672C\u5386\u53F2" }),
|
|
3383
|
-
|
|
3384
|
-
"
|
|
3472
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3473
|
+
"select",
|
|
3385
3474
|
{
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
title:
|
|
3389
|
-
|
|
3390
|
-
children: [
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
v.version
|
|
3400
|
-
))
|
|
3475
|
+
className: "xps-mk-select xps-mk-version-select",
|
|
3476
|
+
value: displayVersion,
|
|
3477
|
+
title: "\u5207\u6362\u7248\u672C",
|
|
3478
|
+
onChange: (e) => selectVersion(e.target.value),
|
|
3479
|
+
children: [...detail.versions].sort((a, b) => compareVersions(b.version, a.version)).map((v) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("option", { value: v.version, children: [
|
|
3480
|
+
"v",
|
|
3481
|
+
v.version,
|
|
3482
|
+
" \xB7 ",
|
|
3483
|
+
formatShortDate(v.publishedAt),
|
|
3484
|
+
v.version === detail.version ? " \xB7 \u6700\u65B0" : ""
|
|
3485
|
+
] }, v.version))
|
|
3486
|
+
}
|
|
3487
|
+
)
|
|
3401
3488
|
] })
|
|
3402
3489
|
] })
|
|
3403
3490
|
] })
|
|
@@ -3443,8 +3530,8 @@ var NAV_ITEMS = [
|
|
|
3443
3530
|
{ key: "developer", label: "\u6211\u7684" }
|
|
3444
3531
|
];
|
|
3445
3532
|
function MarketplaceApp() {
|
|
3446
|
-
const [nav, setNav] = (0,
|
|
3447
|
-
const [detailId, setDetailId] = (0,
|
|
3533
|
+
const [nav, setNav] = (0, import_react10.useState)("market");
|
|
3534
|
+
const [detailId, setDetailId] = (0, import_react10.useState)(null);
|
|
3448
3535
|
ensureThemeStyles();
|
|
3449
3536
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "xps-app", children: [
|
|
3450
3537
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("nav", { className: "xps-nav", children: NAV_ITEMS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
@@ -3472,7 +3559,7 @@ function MarketplaceApp() {
|
|
|
3472
3559
|
}
|
|
3473
3560
|
|
|
3474
3561
|
// src/client/settings/GeneralTokenRow.tsx
|
|
3475
|
-
var
|
|
3562
|
+
var import_react11 = require("react");
|
|
3476
3563
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
3477
3564
|
var rowStyle = {
|
|
3478
3565
|
display: "flex",
|
|
@@ -3529,12 +3616,12 @@ function messageOf2(error, fallback) {
|
|
|
3529
3616
|
return error instanceof Error && error.message !== "" ? error.message : fallback;
|
|
3530
3617
|
}
|
|
3531
3618
|
function GeneralTokenRow() {
|
|
3532
|
-
const [loading, setLoading] = (0,
|
|
3533
|
-
const [auth, setAuth] = (0,
|
|
3534
|
-
const [token, setToken] = (0,
|
|
3535
|
-
const [pending, setPending] = (0,
|
|
3536
|
-
const [error, setError] = (0,
|
|
3537
|
-
(0,
|
|
3619
|
+
const [loading, setLoading] = (0, import_react11.useState)(true);
|
|
3620
|
+
const [auth, setAuth] = (0, import_react11.useState)(null);
|
|
3621
|
+
const [token, setToken] = (0, import_react11.useState)("");
|
|
3622
|
+
const [pending, setPending] = (0, import_react11.useState)(false);
|
|
3623
|
+
const [error, setError] = (0, import_react11.useState)("");
|
|
3624
|
+
(0, import_react11.useEffect)(() => {
|
|
3538
3625
|
let alive = true;
|
|
3539
3626
|
void getAuthState().then((state) => {
|
|
3540
3627
|
if (alive) setAuth(state);
|
|
@@ -3608,7 +3695,7 @@ function GeneralTokenRow() {
|
|
|
3608
3695
|
}
|
|
3609
3696
|
|
|
3610
3697
|
// src/client/settings/GeneralUpdateRow.tsx
|
|
3611
|
-
var
|
|
3698
|
+
var import_react12 = require("react");
|
|
3612
3699
|
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3613
3700
|
var rowStyle2 = {
|
|
3614
3701
|
display: "flex",
|
|
@@ -3693,11 +3780,11 @@ function versionAtLeast(current, target) {
|
|
|
3693
3780
|
return true;
|
|
3694
3781
|
}
|
|
3695
3782
|
function GeneralUpdateRow() {
|
|
3696
|
-
const [phase, setPhase] = (0,
|
|
3783
|
+
const [phase, setPhase] = (0, import_react12.useState)(() => {
|
|
3697
3784
|
const pending = readPendingUpdate();
|
|
3698
3785
|
return pending !== null ? { kind: "updated", version: pending } : { kind: "checking" };
|
|
3699
3786
|
});
|
|
3700
|
-
const [error, setError] = (0,
|
|
3787
|
+
const [error, setError] = (0, import_react12.useState)("");
|
|
3701
3788
|
const check = () => {
|
|
3702
3789
|
setPhase({ kind: "checking" });
|
|
3703
3790
|
setError("");
|
|
@@ -3714,7 +3801,7 @@ function GeneralUpdateRow() {
|
|
|
3714
3801
|
setError(messageOf3(err, "\u68C0\u67E5\u66F4\u65B0\u5931\u8D25"));
|
|
3715
3802
|
});
|
|
3716
3803
|
};
|
|
3717
|
-
(0,
|
|
3804
|
+
(0, import_react12.useEffect)(() => {
|
|
3718
3805
|
if (readPendingUpdate() !== null) {
|
|
3719
3806
|
void checkSelfUpdate().then((result) => {
|
|
3720
3807
|
const pending = readPendingUpdate();
|
|
@@ -3801,7 +3888,7 @@ function injectTheme() {
|
|
|
3801
3888
|
function StoreIcon(props) {
|
|
3802
3889
|
const active = props.active === true;
|
|
3803
3890
|
const size = typeof props.size === "number" ? props.size : 20;
|
|
3804
|
-
return (0,
|
|
3891
|
+
return (0, import_react13.createElement)(
|
|
3805
3892
|
"svg",
|
|
3806
3893
|
{
|
|
3807
3894
|
width: size,
|
|
@@ -3812,13 +3899,13 @@ function StoreIcon(props) {
|
|
|
3812
3899
|
color: active ? "var(--dsw-alias-brand-primary, #3861fb)" : "var(--dsw-alias-label-secondary, #646a73)"
|
|
3813
3900
|
}
|
|
3814
3901
|
},
|
|
3815
|
-
(0,
|
|
3902
|
+
(0, import_react13.createElement)("path", {
|
|
3816
3903
|
d: "M4 7h16l-1.2-3.2A1 1 0 0 0 17.85 3H6.15a1 1 0 0 0-.95.8L4 7Zm0 0v12a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V7",
|
|
3817
3904
|
stroke: "currentColor",
|
|
3818
3905
|
strokeWidth: 1.6,
|
|
3819
3906
|
strokeLinejoin: "round"
|
|
3820
3907
|
}),
|
|
3821
|
-
(0,
|
|
3908
|
+
(0, import_react13.createElement)("path", {
|
|
3822
3909
|
d: "M9 11a3 3 0 0 0 6 0",
|
|
3823
3910
|
stroke: "currentColor",
|
|
3824
3911
|
strokeWidth: 1.6,
|
|
@@ -3828,13 +3915,13 @@ function StoreIcon(props) {
|
|
|
3828
3915
|
}
|
|
3829
3916
|
function BundleConfigSeat(props) {
|
|
3830
3917
|
if (props.view === "page") {
|
|
3831
|
-
return (0,
|
|
3918
|
+
return (0, import_react13.createElement)(
|
|
3832
3919
|
"div",
|
|
3833
3920
|
{ className: "xps-page-placeholder" },
|
|
3834
3921
|
"\u85AA\u4EBA\u85AA\u4E8B\u5E02\u573A\u914D\u7F6E(\u5360\u4F4D):serviceBaseUrl / cacheDir / requestTimeout / cachePolicy"
|
|
3835
3922
|
);
|
|
3836
3923
|
}
|
|
3837
|
-
return (0,
|
|
3924
|
+
return (0, import_react13.createElement)("div", null, "\u85AA\u4EBA\u85AA\u4E8B\u5E02\u573A:\u79C1\u6709\u63D2\u4EF6\u6D4F\u89C8\u3001\u5B89\u88C5\u4E0E\u5F00\u53D1\u8005\u4E0A\u4F20");
|
|
3838
3925
|
}
|
|
3839
3926
|
function apply(ctx) {
|
|
3840
3927
|
const slots = ctx.get("slots");
|
|
@@ -3867,7 +3954,7 @@ function apply(ctx) {
|
|
|
3867
3954
|
"main",
|
|
3868
3955
|
() => safe(
|
|
3869
3956
|
"main",
|
|
3870
|
-
() => slots.register({ name: "main", key: "xrxs-plugins-store" }, () => (0,
|
|
3957
|
+
() => slots.register({ name: "main", key: "xrxs-plugins-store" }, () => (0, import_react13.createElement)(MarketplaceApp))
|
|
3871
3958
|
)
|
|
3872
3959
|
),
|
|
3873
3960
|
"xrxs-plugins-store.main"
|
|
@@ -3879,7 +3966,7 @@ function apply(ctx) {
|
|
|
3879
3966
|
"settings.general.item",
|
|
3880
3967
|
() => slots.register(
|
|
3881
3968
|
{ name: "settings.general.item", id: "xrxs-plugins-store-token", order: 50 },
|
|
3882
|
-
() => (0,
|
|
3969
|
+
() => (0, import_react13.createElement)(GeneralTokenRow)
|
|
3883
3970
|
)
|
|
3884
3971
|
)
|
|
3885
3972
|
),
|
|
@@ -3892,7 +3979,7 @@ function apply(ctx) {
|
|
|
3892
3979
|
"settings.general.item",
|
|
3893
3980
|
() => slots.register(
|
|
3894
3981
|
{ name: "settings.general.item", id: "xrxs-plugins-store-update", order: 51 },
|
|
3895
|
-
() => (0,
|
|
3982
|
+
() => (0, import_react13.createElement)(GeneralUpdateRow)
|
|
3896
3983
|
)
|
|
3897
3984
|
)
|
|
3898
3985
|
),
|
|
@@ -3905,7 +3992,7 @@ function apply(ctx) {
|
|
|
3905
3992
|
"plugins.bundle.config",
|
|
3906
3993
|
() => slots.register(
|
|
3907
3994
|
{ name: "plugins.bundle.config", key: "@xrxs-ai/dsh-xrxs-plugins-store" },
|
|
3908
|
-
(props) => (0,
|
|
3995
|
+
(props) => (0, import_react13.createElement)(BundleConfigSeat, props)
|
|
3909
3996
|
)
|
|
3910
3997
|
)
|
|
3911
3998
|
),
|
package/lib/host/installer.d.ts
CHANGED
|
@@ -88,6 +88,9 @@ export interface InstalledEntry {
|
|
|
88
88
|
managed: boolean;
|
|
89
89
|
/** 已装包自身 package.json 的 description(file: 本地装的包不在市场里,简介只能从这里来);读不到为 null。 */
|
|
90
90
|
description: string | null;
|
|
91
|
+
/** 安装时间(ISO 8601);取 node_modules/<name> 的创建时间(pnpm 装包时建立,更新重装会刷新)。
|
|
92
|
+
* 目录缺失/文件系统不支持 birthtime 时为 null,页面把它排在最后。 */
|
|
93
|
+
installedAt: string | null;
|
|
91
94
|
}
|
|
92
95
|
/** 已装列表:读 <DSH_HOME>/profiles/<profile>/package.json 依赖 + dsh.profile.bundles 层栈
|
|
93
96
|
* (desktop profile 被 CLI 独占时读文件不受影响;设计文档 §3.3)。
|
package/lib/host/installer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
3
|
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
4
|
-
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { lstat, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
6
|
import { basename, delimiter, dirname, join } from 'node:path';
|
|
7
7
|
import { ApiError } from "./api-client.js";
|
|
@@ -437,7 +437,18 @@ export async function listInstalledFromProfile(host) {
|
|
|
437
437
|
}
|
|
438
438
|
if (version === '')
|
|
439
439
|
version = versionFromFileSpec(spec) ?? '';
|
|
440
|
-
|
|
440
|
+
// 安装时间:lstat 链接本身(pnpm 的 node_modules 项是指向 .pnpm 的符号链接,
|
|
441
|
+
// 链接创建时间 = 装包时间);birthtime 不可用(≤0/非法)退 mtime,再不行置 null
|
|
442
|
+
let installedAt = null;
|
|
443
|
+
try {
|
|
444
|
+
const link = await lstat(join(profileDir, 'node_modules', ...name.split('/')));
|
|
445
|
+
const time = link.birthtimeMs > 0 ? link.birthtime : link.mtime;
|
|
446
|
+
installedAt = Number.isNaN(time.getTime()) || time.getTime() <= 0 ? null : time.toISOString();
|
|
447
|
+
}
|
|
448
|
+
catch {
|
|
449
|
+
// 路径不存在:installedAt 保持 null
|
|
450
|
+
}
|
|
451
|
+
return { name, version, managed: bundles.has(name), description, installedAt };
|
|
441
452
|
}));
|
|
442
453
|
}
|
|
443
454
|
const OUTPUT_CAP = 512 * 1024;
|
package/lib/host/routes.js
CHANGED
|
@@ -301,7 +301,11 @@ async function fetchLatestVersionMap(deps) {
|
|
|
301
301
|
const version = optionalString(item.version);
|
|
302
302
|
if (name === undefined || version === undefined)
|
|
303
303
|
continue;
|
|
304
|
-
map.set(name, {
|
|
304
|
+
map.set(name, {
|
|
305
|
+
version,
|
|
306
|
+
displayName: optionalString(item.displayName) ?? null,
|
|
307
|
+
summary: optionalString(item.summary) ?? null,
|
|
308
|
+
});
|
|
305
309
|
}
|
|
306
310
|
}
|
|
307
311
|
catch (error) {
|
|
@@ -321,6 +325,9 @@ async function handleInstalled(rc) {
|
|
|
321
325
|
latestVersion,
|
|
322
326
|
updateAvailable: latestVersion !== null && latestVersion !== entry.version,
|
|
323
327
|
managed: entry.managed,
|
|
328
|
+
installedAt: entry.installedAt,
|
|
329
|
+
// 展示名来自市场;本机手装/离线的包没有,client 半自行回退包名
|
|
330
|
+
displayName: meta?.displayName ?? null,
|
|
324
331
|
// 市场简介优先;file: 本地装的包不在市场里,回退该包自己 package.json 的 description
|
|
325
332
|
summary: meta?.summary ?? entry.description,
|
|
326
333
|
};
|