dsh-plugin-update 0.3.1 → 0.5.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/CHANGELOG.md +21 -0
- package/README.md +57 -13
- package/dist/client.d.ts +4 -4
- package/dist/client.js +2 -1
- package/dist/config.d.ts +4 -1
- package/dist/config.js +8 -1
- package/dist/entry.d.ts +9 -2
- package/dist/entry.js +47 -12
- package/dist/host.d.ts +4 -4
- package/dist/host.js +77 -6
- package/dist/http.d.ts +2 -2
- package/dist/http.js +3 -2
- package/dist/panel-batch.d.ts +9 -0
- package/dist/panel-batch.js +125 -13
- package/dist/panel.d.ts +29 -2
- package/dist/panel.js +170 -25
- package/dist/service.d.ts +14 -0
- package/dist/service.js +50 -0
- package/package.json +1 -1
package/dist/panel.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// AUTO-GENERATED by node build.mjs — DO NOT EDIT. Source: src/panel.ts
|
|
2
|
-
import { buildPhoneNames, DEFAULT_PANEL_POLL_MS, MIN_PANEL_POLL_MS } from "./config.js";
|
|
2
|
+
import { buildChangelogPhoneName, buildPhoneNames, DEFAULT_PANEL_POLL_MS, MIN_PANEL_POLL_MS } from "./config.js";
|
|
3
3
|
import { COPY_BUDGET_CHARS, sanitizeForCopy } from "./redaction.js";
|
|
4
4
|
import { validReleaseVersion } from "./service.js";
|
|
5
5
|
import {
|
|
@@ -7,6 +7,9 @@ import {
|
|
|
7
7
|
parseChangelog,
|
|
8
8
|
renderChangelogHTML
|
|
9
9
|
} from "./changelog.js";
|
|
10
|
+
function normalizePanelTheme(value) {
|
|
11
|
+
return value === "d5-paper" || value === "archive" ? "d5-paper" : "default";
|
|
12
|
+
}
|
|
10
13
|
const BLOCKED_COPY = {
|
|
11
14
|
"unknown-profile": {
|
|
12
15
|
title: "\u4F7F\u7528\u8303\u56F4\u6216\u63D2\u4EF6\u4F4D\u7F6E\u8BA4\u4E0D\u51FA",
|
|
@@ -551,8 +554,25 @@ const UPDATE_PANEL_CSS = [
|
|
|
551
554
|
".dsh-upd-prog-bar{display:block;height:100%;background:var(--dsh-upd-primary,#2563eb);transition:width .3s}",
|
|
552
555
|
".dsh-upd-progtxt{font-size:12.5px;opacity:.75}",
|
|
553
556
|
".dsh-upd-skipline{font-size:13px;margin-top:8px}",
|
|
557
|
+
// 骨架微光:只在首帧 loading 出现;reduced-motion 下静止占位,不断语义。
|
|
558
|
+
".dsh-upd-skv{display:inline-block;min-width:64px;border-radius:3px;color:transparent !important;user-select:none;",
|
|
559
|
+
"background:linear-gradient(90deg,var(--dsh-upd-line,#e5e7eb) 25%,var(--dsh-upd-soft,#f3f4f6) 50%,var(--dsh-upd-line,#e5e7eb) 75%);",
|
|
560
|
+
"background-size:200% 100%;animation:dsh-upd-shimmer 1.2s linear infinite}",
|
|
561
|
+
"@keyframes dsh-upd-shimmer{to{background-position:-200% 0}}",
|
|
554
562
|
".dsh-upd-tag{display:inline-block;border:1px dashed currentColor;border-radius:3px;padding:1px 8px;margin-right:8px;font-family:Consolas,Menlo,monospace;font-size:12px}",
|
|
555
563
|
".dsh-upd-err{font-size:13px;margin:0 0 6px}",
|
|
564
|
+
// —— 全按钮交互反馈(#36:悬停/按下/过渡/在途忙态;浅深双主题通用写法,不碰上面的既有串)——
|
|
565
|
+
".dsh-upd button{transition:background-color .15s ease,border-color .15s ease,color .15s ease,transform .06s ease}",
|
|
566
|
+
".dsh-upd button:hover:not(:disabled){border-color:var(--dsh-upd-focus,#2563eb)}",
|
|
567
|
+
'.dsh-upd button[data-primary="1"]:hover:not(:disabled){filter:brightness(.93)}',
|
|
568
|
+
".dsh-upd button:active:not(:disabled){transform:translateY(1px)}",
|
|
569
|
+
'.dsh-upd button[aria-busy="true"]{cursor:wait;animation:dsh-upd-pulse 1s ease-in-out infinite}',
|
|
570
|
+
"@keyframes dsh-upd-pulse{0%,100%{opacity:1}50%{opacity:.55}}",
|
|
571
|
+
// 在途转圈:纯 CSS ::after,不加 DOM 节点(内核 DOM 冻结);转的是边框缺口,不是 emoji。
|
|
572
|
+
'.dsh-upd button[aria-busy="true"]::after{content:"";display:inline-block;width:11px;height:11px;margin-left:8px;vertical-align:-1px;',
|
|
573
|
+
"border:2px solid currentColor;border-top-color:transparent;border-radius:50%;animation:dsh-upd-spin .8s linear infinite}",
|
|
574
|
+
"@keyframes dsh-upd-spin{to{transform:rotate(360deg)}}",
|
|
575
|
+
'@media (prefers-reduced-motion: reduce){.dsh-upd button{transition:none}.dsh-upd button:active:not(:disabled){transform:none}.dsh-upd button[aria-busy="true"]{animation:none}.dsh-upd-skv{animation:none}}',
|
|
556
576
|
"@media (prefers-color-scheme: dark){.dsh-upd{--dsh-upd-fg:#e5e7eb;--dsh-upd-bg:#111827;--dsh-upd-line:#374151;",
|
|
557
577
|
"--dsh-upd-btn:#1f2937;--dsh-upd-soft:#1f2937;--dsh-upd-primary:#3b82f6;--dsh-upd-focus:#93c5fd;",
|
|
558
578
|
// 横幅深色覆盖:底色用低透明度同色系(不是浅色原值),边线提亮,保证「深底浅字」可读。
|
|
@@ -681,6 +701,11 @@ function chapterOf(index, inner, note = "") {
|
|
|
681
701
|
const title = CHAPTER_TITLES[index - 1];
|
|
682
702
|
return `<section class="dsh-upd-chapter" data-chapter="${no}"><div class="dsh-upd-chap-head"><span class="dsh-upd-chap-no">${no}</span><h3 class="dsh-upd-chap-title">${escapeHtml(title)}</h3><span class="dsh-upd-chap-rule"></span>${note}</div>${inner}</section>`;
|
|
683
703
|
}
|
|
704
|
+
function skeletonStrip(loading) {
|
|
705
|
+
if (!loading) return "";
|
|
706
|
+
const cell = (k) => `<div><span class="dsh-upd-strip-k">${escapeHtml(k)}</span><span class="dsh-upd-strip-v dsh-upd-skv" aria-hidden="true">\u2026</span></div>`;
|
|
707
|
+
return `<div class="dsh-upd-strip" aria-hidden="true">` + cell("\u8FD0\u884C") + cell("\u78C1\u76D8") + cell("\u8FDC\u7AEF") + `</div>`;
|
|
708
|
+
}
|
|
684
709
|
function versionStrip(snapshot) {
|
|
685
710
|
const cell = (k, v) => `<div><span class="dsh-upd-strip-k">${escapeHtml(k)}</span><span class="dsh-upd-strip-v">${escapeHtml(v ?? "\u672A\u77E5")}</span></div>`;
|
|
686
711
|
if (!snapshot) return "";
|
|
@@ -712,31 +737,34 @@ function renderUpdatePanelKernel(input, view) {
|
|
|
712
737
|
parts.push(`<div><strong>${escapeHtml(b.title)}</strong></div>`);
|
|
713
738
|
if (b.action) parts.push(`<div>${escapeHtml(b.action)}</div>`);
|
|
714
739
|
parts.push("</div>");
|
|
715
|
-
parts.push(versionStrip(snapshot));
|
|
740
|
+
parts.push(snapshot ? versionStrip(snapshot) : skeletonStrip(view.banner.kind === "loading"));
|
|
716
741
|
const showActions = input.actions !== "none";
|
|
717
742
|
const actions = [];
|
|
718
743
|
if (showActions) {
|
|
744
|
+
const busyAct = input.busyAct;
|
|
745
|
+
const checkBusy = busyAct === "check";
|
|
746
|
+
const installBusy = busyAct === "install";
|
|
719
747
|
actions.push('<div class="dsh-upd-actions">');
|
|
720
748
|
actions.push(
|
|
721
|
-
`<button type="button" data-action="check">\u67E5\u65B0\u7248</button
|
|
749
|
+
(checkBusy ? `<button type="button" data-action="check" disabled aria-busy="true" title="\u6B63\u5728\u5411\u5B98\u65B9\u6E90\u67E5\u8BE2\uFF0C\u8BF7\u7A0D\u5019">\u6B63\u5728\u67E5\u65B0\u7248\u2026</button>` : `<button type="button" data-action="check" title="\u91CD\u65B0\u5411\u5B98\u65B9\u6E90\u67E5\u4E00\u6B21\u65B0\u7248\uFF08\u53EA\u8BFB\uFF0C\u4E0D\u5B89\u88C5\uFF09">\u67E5\u65B0\u7248</button>`) + (installBusy ? `<button type="button" data-action="install" data-primary="1" disabled aria-busy="true" title="\u6B63\u5728\u5B89\u88C5\uFF0C\u8BF7\u7A0D\u5019">\u6B63\u5728\u5B89\u88C5\u2026</button>` : `<button type="button" data-action="install" data-primary="1" title="\u7528\u7CBE\u786E\u7248\u672C\u5B89\u88C5\uFF1B\u540C\u4E00\u4F7F\u7528\u8303\u56F4\u540C\u65F6\u53EA\u88C5\u4E00\u4E2A"${view.installEnabled ? "" : " disabled"}>${escapeHtml(view.installLabel)}</button>`)
|
|
722
750
|
);
|
|
723
751
|
if (snapshot?.latestVersion && !view.skippedLatest && view.banner.kind === "update") {
|
|
724
|
-
actions.push(`<button type="button" data-action="skip">\u8DF3\u8FC7\u8BE5\u7248\u672C</button>`);
|
|
752
|
+
actions.push(`<button type="button" data-action="skip" title="\u8BE5\u7248\u672C\u4E0D\u518D\u63D0\u9192\uFF1B\u6709\u66F4\u65B0\u7684\u65B0\u7248\u672C\u7167\u5E38\u63D0\u9192">\u8DF3\u8FC7\u8BE5\u7248\u672C</button>`);
|
|
725
753
|
}
|
|
726
754
|
if (view.showReset && snapshot?.latestVersion) {
|
|
727
|
-
actions.push(`<button type="button" data-action="reset-skip">\u6062\u590D\uFF08${escapeHtml(snapshot.latestVersion)}\uFF09</button>`);
|
|
755
|
+
actions.push(`<button type="button" data-action="reset-skip" title="\u64A4\u9500\u8DF3\u8FC7\uFF0C\u8BE5\u7248\u672C\u91CD\u65B0\u63D0\u9192">\u6062\u590D\uFF08${escapeHtml(snapshot.latestVersion)}\uFF09</button>`);
|
|
728
756
|
}
|
|
729
757
|
if (view.showManual && manual) {
|
|
730
|
-
actions.push(`<button type="button" data-action="copy-manual">\u590D\u5236\u624B\u5DE5\u547D\u4EE4</button>`);
|
|
758
|
+
actions.push(`<button type="button" data-action="copy-manual" title="\u590D\u5236\u624B\u5DE5\u547D\u4EE4\uFF0C\u7C98\u5230\u7EC8\u7AEF\u6574\u884C\u6267\u884C">\u590D\u5236\u624B\u5DE5\u547D\u4EE4</button>`);
|
|
731
759
|
}
|
|
732
760
|
if (b.kind === "restart") {
|
|
733
|
-
actions.push(`<button type="button" data-action="restart-hint" data-primary="1">\u91CD\u542F\u5BBF\u4E3B</button>`);
|
|
761
|
+
actions.push(`<button type="button" data-action="restart-hint" data-primary="1" title="\u5BBF\u4E3B\u6CA1\u6709\u81EA\u91CD\u542F\u7535\u8BDD\uFF1A\u8BF7\u624B\u52A8\u91CD\u542F\u5BBF\u4E3B">\u91CD\u542F\u5BBF\u4E3B</button>`);
|
|
734
762
|
}
|
|
735
763
|
if (snapshot) {
|
|
736
|
-
actions.push(`<button type="button" data-action="copy-diag">\u590D\u5236\u8BCA\u65AD</button>`);
|
|
764
|
+
actions.push(`<button type="button" data-action="copy-diag" title="\u590D\u5236\u5DF2\u8131\u654F\u8BCA\u65AD\uFF0C\u76F4\u63A5\u7C98\u7ED9\u63D2\u4EF6\u4F5C\u8005">\u590D\u5236\u8BCA\u65AD</button>`);
|
|
737
765
|
}
|
|
738
766
|
if (mode === "dialog") {
|
|
739
|
-
actions.push(`<button type="button" data-action="close-view">\u5173\u95ED</button>`);
|
|
767
|
+
actions.push(`<button type="button" data-action="close-view" title="\u5173\u95ED\u9762\u677F\uFF08\u5B89\u88C5\u5728\u5BBF\u4E3B\u4FA7\u7EE7\u7EED\u8DD1\uFF0C\u53EF\u91CD\u5F00\u6062\u590D\u663E\u793A\uFF09">\u5173\u95ED</button>`);
|
|
740
768
|
}
|
|
741
769
|
actions.push("</div>");
|
|
742
770
|
}
|
|
@@ -838,7 +866,7 @@ ${changelogHTML}
|
|
|
838
866
|
function renderUpdatePanelHTML(input) {
|
|
839
867
|
const view = panelViewModel(input);
|
|
840
868
|
const kernel = renderUpdatePanelKernel(input, view);
|
|
841
|
-
const d5 = input.theme === "d5-paper";
|
|
869
|
+
const d5 = normalizePanelTheme(input.theme) === "d5-paper";
|
|
842
870
|
const attr = d5 ? ' data-theme="d5-paper"' : "";
|
|
843
871
|
const sealAttr = ` data-seal="${escapeHtml(view.seal.text)}" data-seal-tone="${view.seal.tone}"`;
|
|
844
872
|
const body = input.mode === "dialog" ? `<div class="dsh-upd-overlay" data-mode="dialog"><div class="dsh-upd" data-mode="dialog" data-plugin="${escapeHtml(input.pluginId)}"${sealAttr}${attr}>
|
|
@@ -918,6 +946,13 @@ function mountUpdatePanel(container, options) {
|
|
|
918
946
|
}
|
|
919
947
|
const prefix = options.prefix === void 0 ? "wf" : options.prefix;
|
|
920
948
|
const phoneNames = buildPhoneNames(prefix);
|
|
949
|
+
const changelogPhone = buildChangelogPhoneName(prefix);
|
|
950
|
+
const autoChangelogEnabled = typeof options.changelogMarkdown !== "string" && options.autoChangelog !== false;
|
|
951
|
+
let manualChangelogOverride = typeof options.changelogMarkdown === "string";
|
|
952
|
+
const changelogCache = /* @__PURE__ */ new Map();
|
|
953
|
+
const changelogInflight = /* @__PURE__ */ new Set();
|
|
954
|
+
const changelogFailed = /* @__PURE__ */ new Set();
|
|
955
|
+
let autoSeq = 0;
|
|
921
956
|
const pollMs = options.pollMs === void 0 ? DEFAULT_PANEL_POLL_MS : options.pollMs;
|
|
922
957
|
if (typeof pollMs !== "number" || !Number.isFinite(pollMs) || pollMs < MIN_PANEL_POLL_MS) {
|
|
923
958
|
throw new Error(`[dsh-plugin-update] \u9762\u677F\u8F6E\u8BE2\u95F4\u9694\u975E\u6CD5\uFF1A\u4E0D\u5F97\u5C0F\u4E8E 250 \u6BEB\u79D2\uFF08\u6536\u5230 ${JSON.stringify(options.pollMs)}\uFF09`);
|
|
@@ -926,13 +961,15 @@ function mountUpdatePanel(container, options) {
|
|
|
926
961
|
if (mode !== "embedded" && mode !== "dialog") {
|
|
927
962
|
throw new Error(`[dsh-plugin-update] \u6446\u653E\u5F62\u6001\u975E\u6CD5\uFF1A\u53EA\u6536 embedded \u6216 dialog\uFF08\u6536\u5230 ${JSON.stringify(options.mode)}\uFF09`);
|
|
928
963
|
}
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
throw new Error(`[dsh-plugin-update] \u4E3B\u9898\u975E\u6CD5\uFF1A\u53EA\u6536 default \u6216 d5-paper\uFF08\u6536\u5230 ${JSON.stringify(options.theme)}\uFF09`);
|
|
964
|
+
if (options.theme !== void 0 && options.theme !== "default" && options.theme !== "archive" && options.theme !== "d5-paper") {
|
|
965
|
+
throw new Error(`[dsh-plugin-update] \u4E3B\u9898\u975E\u6CD5\uFF1A\u53EA\u6536 default \u6216 archive\uFF08d5-paper \u4E3A\u65E7\u522B\u540D\u4ECD\u53EF\u7528\uFF09\uFF08\u6536\u5230 ${JSON.stringify(options.theme)}\uFF09`);
|
|
932
966
|
}
|
|
967
|
+
let theme = normalizePanelTheme(options.theme ?? "default");
|
|
933
968
|
let showOthers = options.showOthers === true;
|
|
934
969
|
const call = options.call;
|
|
935
970
|
const onRestartRequested = options.onRestartRequested;
|
|
971
|
+
const onCloseRequested = typeof options.onCloseRequested === "function" ? options.onCloseRequested : null;
|
|
972
|
+
let lastHTML = "";
|
|
936
973
|
const copyText = options.copyText ?? defaultCopyText;
|
|
937
974
|
const skipStore = options.skipStore ?? createBrowserSkipStore(pluginId);
|
|
938
975
|
const hostKind = typeof options.hostKind === "string" && options.hostKind ? options.hostKind : null;
|
|
@@ -948,20 +985,36 @@ function mountUpdatePanel(container, options) {
|
|
|
948
985
|
let lastErrorKind = null;
|
|
949
986
|
let lastDiag = null;
|
|
950
987
|
let copyNotice = null;
|
|
988
|
+
let noticeExpiresAt = 0;
|
|
989
|
+
let busyAct = null;
|
|
951
990
|
let mounted = true;
|
|
952
991
|
let envProfileName = null;
|
|
953
992
|
let envHostKind = null;
|
|
993
|
+
function sayCopy(text) {
|
|
994
|
+
copyNotice = text;
|
|
995
|
+
try {
|
|
996
|
+
noticeExpiresAt = Date.now() + 5e3;
|
|
997
|
+
} catch {
|
|
998
|
+
noticeExpiresAt = 0;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
954
1001
|
function queueArgs() {
|
|
955
1002
|
return { includeQueue: true, includeEnv: true, showOthers, ...requestId ? { requestId } : {} };
|
|
956
1003
|
}
|
|
957
1004
|
function render() {
|
|
958
1005
|
if (!mounted) return;
|
|
1006
|
+
if (!copyNotice) noticeExpiresAt = 0;
|
|
1007
|
+
else if (noticeExpiresAt && Date.now() > noticeExpiresAt) {
|
|
1008
|
+
copyNotice = null;
|
|
1009
|
+
noticeExpiresAt = 0;
|
|
1010
|
+
}
|
|
959
1011
|
const latest = snapshot?.latestVersion ?? null;
|
|
960
1012
|
const skippedLatest = !!latest && validReleaseVersion(latest) && skipStore.has(latest);
|
|
961
|
-
|
|
1013
|
+
const nextHTML = renderUpdatePanelHTML({
|
|
962
1014
|
snapshot,
|
|
963
1015
|
manual,
|
|
964
1016
|
queue,
|
|
1017
|
+
busyAct,
|
|
965
1018
|
skippedLatest,
|
|
966
1019
|
lastError,
|
|
967
1020
|
errorKind: lastErrorKind,
|
|
@@ -975,6 +1028,10 @@ function mountUpdatePanel(container, options) {
|
|
|
975
1028
|
profileName: profileNameOption ?? envProfileName,
|
|
976
1029
|
hostKind: hostKind ?? envHostKind
|
|
977
1030
|
});
|
|
1031
|
+
if (nextHTML !== lastHTML) {
|
|
1032
|
+
lastHTML = nextHTML;
|
|
1033
|
+
container.innerHTML = nextHTML;
|
|
1034
|
+
}
|
|
978
1035
|
}
|
|
979
1036
|
function applyStatusReply(reply) {
|
|
980
1037
|
if (!isObject(reply)) return;
|
|
@@ -1003,6 +1060,44 @@ function mountUpdatePanel(container, options) {
|
|
|
1003
1060
|
lastDiag = Object.prototype.hasOwnProperty.call(reply, "diag") ? reply["diag"] : null;
|
|
1004
1061
|
}
|
|
1005
1062
|
}
|
|
1063
|
+
function pendingAutoChangelogVersion() {
|
|
1064
|
+
if (!autoChangelogEnabled || manualChangelogOverride || !mounted) return null;
|
|
1065
|
+
const v = snapshot?.latestVersion ?? null;
|
|
1066
|
+
if (typeof v !== "string" || !validReleaseVersion(v)) return null;
|
|
1067
|
+
if (!snapshot || snapshot.canInstall !== true) return null;
|
|
1068
|
+
try {
|
|
1069
|
+
if (skipStore.has(v)) return null;
|
|
1070
|
+
} catch {
|
|
1071
|
+
}
|
|
1072
|
+
if (changelogCache.has(v) || changelogInflight.has(v) || changelogFailed.has(v)) return null;
|
|
1073
|
+
return v;
|
|
1074
|
+
}
|
|
1075
|
+
function maybeAutoChangelog() {
|
|
1076
|
+
const v = pendingAutoChangelogVersion();
|
|
1077
|
+
if (v === null) return;
|
|
1078
|
+
changelogInflight.add(v);
|
|
1079
|
+
const seq = autoSeq;
|
|
1080
|
+
void Promise.resolve().then(() => call(changelogPhone, { version: v })).then(
|
|
1081
|
+
(reply) => {
|
|
1082
|
+
changelogInflight.delete(v);
|
|
1083
|
+
if (!mounted || seq !== autoSeq) return;
|
|
1084
|
+
if (!reply || typeof reply !== "object" || reply["ok"] !== true) {
|
|
1085
|
+
changelogFailed.add(v);
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
const md = reply["markdown"];
|
|
1089
|
+
changelogCache.set(v, typeof md === "string" ? md : null);
|
|
1090
|
+
if (typeof md === "string") {
|
|
1091
|
+
changelogMarkdown = md;
|
|
1092
|
+
render();
|
|
1093
|
+
}
|
|
1094
|
+
},
|
|
1095
|
+
() => {
|
|
1096
|
+
changelogInflight.delete(v);
|
|
1097
|
+
if (mounted && seq === autoSeq) changelogFailed.add(v);
|
|
1098
|
+
}
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1006
1101
|
async function refresh() {
|
|
1007
1102
|
if (!mounted) return;
|
|
1008
1103
|
try {
|
|
@@ -1016,26 +1111,40 @@ function mountUpdatePanel(container, options) {
|
|
|
1016
1111
|
lastDiag = null;
|
|
1017
1112
|
}
|
|
1018
1113
|
render();
|
|
1114
|
+
maybeAutoChangelog();
|
|
1019
1115
|
}
|
|
1020
1116
|
async function act(kind, arg) {
|
|
1021
1117
|
if (!mounted) return;
|
|
1022
1118
|
copyNotice = null;
|
|
1023
1119
|
switch (kind) {
|
|
1024
1120
|
case "check": {
|
|
1121
|
+
if (busyAct) return;
|
|
1122
|
+
busyAct = "check";
|
|
1123
|
+
copyNotice = "\u6B63\u5728\u67E5\u65B0\u7248\u2026";
|
|
1124
|
+
render();
|
|
1025
1125
|
try {
|
|
1026
1126
|
const reply = await call(phoneNames.updateCheck, queueArgs());
|
|
1027
1127
|
if (!mounted) return;
|
|
1028
1128
|
applyStatusReply(reply);
|
|
1129
|
+
changelogFailed.clear();
|
|
1029
1130
|
} catch {
|
|
1030
1131
|
if (!mounted) return;
|
|
1031
1132
|
lastError = "check-failed";
|
|
1032
1133
|
lastErrorKind = null;
|
|
1033
1134
|
lastDiag = null;
|
|
1135
|
+
} finally {
|
|
1136
|
+
busyAct = null;
|
|
1137
|
+
if (copyNotice === "\u6B63\u5728\u67E5\u65B0\u7248\u2026") copyNotice = null;
|
|
1034
1138
|
}
|
|
1035
1139
|
render();
|
|
1140
|
+
maybeAutoChangelog();
|
|
1036
1141
|
return;
|
|
1037
1142
|
}
|
|
1038
1143
|
case "install": {
|
|
1144
|
+
if (busyAct) return;
|
|
1145
|
+
busyAct = "install";
|
|
1146
|
+
copyNotice = "\u6B63\u5728\u5B89\u88C5\u2026";
|
|
1147
|
+
render();
|
|
1039
1148
|
try {
|
|
1040
1149
|
if (!receipt) {
|
|
1041
1150
|
const checked = await call(phoneNames.updateCheck, queueArgs());
|
|
@@ -1063,8 +1172,12 @@ function mountUpdatePanel(container, options) {
|
|
|
1063
1172
|
lastError = "check-failed";
|
|
1064
1173
|
lastErrorKind = null;
|
|
1065
1174
|
lastDiag = null;
|
|
1175
|
+
} finally {
|
|
1176
|
+
busyAct = null;
|
|
1177
|
+
if (copyNotice === "\u6B63\u5728\u5B89\u88C5\u2026") copyNotice = null;
|
|
1066
1178
|
}
|
|
1067
1179
|
render();
|
|
1180
|
+
maybeAutoChangelog();
|
|
1068
1181
|
return;
|
|
1069
1182
|
}
|
|
1070
1183
|
case "skip": {
|
|
@@ -1090,9 +1203,9 @@ function mountUpdatePanel(container, options) {
|
|
|
1090
1203
|
if (manual) {
|
|
1091
1204
|
try {
|
|
1092
1205
|
await copyText(manual);
|
|
1093
|
-
|
|
1206
|
+
sayCopy("\u624B\u5DE5\u547D\u4EE4\u5DF2\u590D\u5236\uFF0C\u7C98\u5230\u7EC8\u7AEF\u6574\u884C\u6267\u884C\u5373\u53EF\u3002");
|
|
1094
1207
|
} catch {
|
|
1095
|
-
|
|
1208
|
+
sayCopy("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u4E2D\u4E0A\u9762\u7684\u547D\u4EE4\u3002");
|
|
1096
1209
|
}
|
|
1097
1210
|
}
|
|
1098
1211
|
render();
|
|
@@ -1123,9 +1236,9 @@ function mountUpdatePanel(container, options) {
|
|
|
1123
1236
|
});
|
|
1124
1237
|
try {
|
|
1125
1238
|
await copyText(text);
|
|
1126
|
-
|
|
1239
|
+
sayCopy("\u8BCA\u65AD\u5DF2\u590D\u5236\uFF0C\u76F4\u63A5\u7C98\u7ED9\u63D2\u4EF6\u4F5C\u8005\u5373\u53EF\uFF08\u5DF2\u8131\u654F\uFF09\u3002");
|
|
1127
1240
|
} catch {
|
|
1128
|
-
|
|
1241
|
+
sayCopy("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u4E2D\u4E0A\u9762\u7684\u4FE1\u606F\u3002");
|
|
1129
1242
|
}
|
|
1130
1243
|
render();
|
|
1131
1244
|
return;
|
|
@@ -1141,18 +1254,18 @@ function mountUpdatePanel(container, options) {
|
|
|
1141
1254
|
try {
|
|
1142
1255
|
if (typeof onRestartRequested === "function") {
|
|
1143
1256
|
await onRestartRequested();
|
|
1144
|
-
|
|
1257
|
+
sayCopy("\u5DF2\u6309\u8C03\u7528\u65B9\u7684\u91CD\u542F\u6D41\u7A0B\u5904\u7406\uFF1B\u91CD\u542F\u540E\u65B0\u7248\u751F\u6548\u3002");
|
|
1145
1258
|
} else {
|
|
1146
|
-
|
|
1259
|
+
sayCopy("\u672C\u5BBF\u4E3B\u672A\u63D0\u4F9B\u91CD\u542F\u5165\u53E3\uFF1A\u8BF7\u624B\u52A8\u91CD\u542F\u5BBF\u4E3B\uFF0C\u91CD\u542F\u540E\u65B0\u7248\u751F\u6548\u3002");
|
|
1147
1260
|
}
|
|
1148
1261
|
} catch {
|
|
1149
|
-
|
|
1262
|
+
sayCopy("\u91CD\u542F\u5165\u53E3\u8C03\u7528\u5931\u8D25\uFF1A\u8BF7\u624B\u52A8\u91CD\u542F\u5BBF\u4E3B\uFF0C\u91CD\u542F\u540E\u65B0\u7248\u751F\u6548\u3002");
|
|
1150
1263
|
}
|
|
1151
1264
|
render();
|
|
1152
1265
|
return;
|
|
1153
1266
|
}
|
|
1154
1267
|
case "close-view": {
|
|
1155
|
-
|
|
1268
|
+
await requestDialogClose();
|
|
1156
1269
|
return;
|
|
1157
1270
|
}
|
|
1158
1271
|
}
|
|
@@ -1165,10 +1278,10 @@ function mountUpdatePanel(container, options) {
|
|
|
1165
1278
|
render();
|
|
1166
1279
|
}
|
|
1167
1280
|
async function setTheme(next) {
|
|
1168
|
-
if (next !== "default" && next !== "d5-paper") {
|
|
1169
|
-
throw new Error(`[dsh-plugin-update] \u4E3B\u9898\u975E\u6CD5\uFF1A\u53EA\u6536 default \u6216
|
|
1281
|
+
if (next !== "default" && next !== "archive" && next !== "d5-paper") {
|
|
1282
|
+
throw new Error(`[dsh-plugin-update] \u4E3B\u9898\u975E\u6CD5\uFF1A\u53EA\u6536 default \u6216 archive\uFF08d5-paper \u4E3A\u65E7\u522B\u540D\u4ECD\u53EF\u7528\uFF09\uFF08\u6536\u5230 ${JSON.stringify(next)}\uFF09`);
|
|
1170
1283
|
}
|
|
1171
|
-
theme = next;
|
|
1284
|
+
theme = normalizePanelTheme(next);
|
|
1172
1285
|
render();
|
|
1173
1286
|
}
|
|
1174
1287
|
async function setShowOthers(show) {
|
|
@@ -1185,13 +1298,34 @@ function mountUpdatePanel(container, options) {
|
|
|
1185
1298
|
} catch {
|
|
1186
1299
|
}
|
|
1187
1300
|
}
|
|
1301
|
+
async function requestDialogClose() {
|
|
1302
|
+
if (!mounted || mode !== "dialog") return;
|
|
1303
|
+
if (onCloseRequested) {
|
|
1304
|
+
try {
|
|
1305
|
+
await onCloseRequested();
|
|
1306
|
+
} catch {
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
unmount();
|
|
1310
|
+
}
|
|
1311
|
+
function onKeyDown(ev) {
|
|
1312
|
+
try {
|
|
1313
|
+
const e = ev;
|
|
1314
|
+
if (!mounted || mode !== "dialog" || !e || e.key !== "Escape") return;
|
|
1315
|
+
void requestDialogClose();
|
|
1316
|
+
} catch {
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1188
1319
|
function setChangelogMarkdown(markdown) {
|
|
1189
1320
|
changelogMarkdown = typeof markdown === "string" ? markdown : null;
|
|
1321
|
+
if (typeof markdown === "string") manualChangelogOverride = true;
|
|
1190
1322
|
render();
|
|
1191
1323
|
}
|
|
1192
1324
|
function unmount() {
|
|
1193
1325
|
if (!mounted) return;
|
|
1194
1326
|
mounted = false;
|
|
1327
|
+
autoSeq++;
|
|
1328
|
+
changelogInflight.clear();
|
|
1195
1329
|
try {
|
|
1196
1330
|
timer.clear(handle);
|
|
1197
1331
|
} catch {
|
|
@@ -1200,12 +1334,20 @@ function mountUpdatePanel(container, options) {
|
|
|
1200
1334
|
container.removeEventListener?.("click", onClick);
|
|
1201
1335
|
} catch {
|
|
1202
1336
|
}
|
|
1337
|
+
try {
|
|
1338
|
+
container.removeEventListener?.("keydown", onKeyDown);
|
|
1339
|
+
} catch {
|
|
1340
|
+
}
|
|
1203
1341
|
}
|
|
1204
1342
|
render();
|
|
1205
1343
|
try {
|
|
1206
1344
|
container.addEventListener?.("click", onClick);
|
|
1207
1345
|
} catch {
|
|
1208
1346
|
}
|
|
1347
|
+
try {
|
|
1348
|
+
container.addEventListener?.("keydown", onKeyDown);
|
|
1349
|
+
} catch {
|
|
1350
|
+
}
|
|
1209
1351
|
const timer = getTimer();
|
|
1210
1352
|
const handle = timer.set(() => {
|
|
1211
1353
|
void refresh();
|
|
@@ -1219,6 +1361,7 @@ function mountUpdatePanel(container, options) {
|
|
|
1219
1361
|
return { refresh, act, setMode, setTheme, setShowOthers, setChangelogMarkdown, unmount };
|
|
1220
1362
|
}
|
|
1221
1363
|
import { buildPhoneNames as buildPhoneNames2 } from "./config.js";
|
|
1364
|
+
import { buildChangelogPhoneName as buildChangelogPhoneName2 } from "./config.js";
|
|
1222
1365
|
const PANEL_POLL = {
|
|
1223
1366
|
defaultMs: DEFAULT_PANEL_POLL_MS,
|
|
1224
1367
|
minMs: MIN_PANEL_POLL_MS
|
|
@@ -1270,6 +1413,7 @@ export {
|
|
|
1270
1413
|
UPDATE_PANEL_D5_CSS,
|
|
1271
1414
|
blockedCopy,
|
|
1272
1415
|
buildDiagnosticText,
|
|
1416
|
+
buildChangelogPhoneName2 as buildPanelChangelogPhoneName,
|
|
1273
1417
|
buildPhoneNames2 as buildPanelPhoneNames,
|
|
1274
1418
|
buildUpdateDiagCopy,
|
|
1275
1419
|
changelogForUpdate2 as changelogForUpdate,
|
|
@@ -1284,6 +1428,7 @@ export {
|
|
|
1284
1428
|
isQueueBusy,
|
|
1285
1429
|
isUnreleasedVersion,
|
|
1286
1430
|
mountUpdatePanel,
|
|
1431
|
+
normalizePanelTheme,
|
|
1287
1432
|
normalizeQueueState,
|
|
1288
1433
|
panelViewModel,
|
|
1289
1434
|
parseChangelog2 as parseChangelog,
|
package/dist/service.d.ts
CHANGED
|
@@ -69,4 +69,18 @@ export declare function fetchNpmRelease(fetchImpl: FetchImpl, timeoutMs?: number
|
|
|
69
69
|
registryUrl?: string;
|
|
70
70
|
releaseChannel?: ReleaseChannel;
|
|
71
71
|
}): Promise<ReleaseInfo>;
|
|
72
|
+
/**
|
|
73
|
+
* 按版本号取发行信息(#38 更新日志电话用:面板说要哪版就取哪版)。
|
|
74
|
+
*
|
|
75
|
+
* 与 fetchNpmRelease 同一信任根:只接受名字对得上、版本与请求完全一致且发行合法、
|
|
76
|
+
* 包地址与完整性校验全合规的返回,否则按版本信息无效处理。通道门禁同样复用
|
|
77
|
+
* (stable 只要纯三段,prerelease 才收预发布)。取的是版本文档(与 latest 文档同量级),
|
|
78
|
+
* 不是全量包元数据。
|
|
79
|
+
*/
|
|
80
|
+
export declare function fetchNpmVersionRelease(fetchImpl: FetchImpl, timeoutMs: number | undefined, opts: {
|
|
81
|
+
targetPackageName?: string;
|
|
82
|
+
registryUrl?: string;
|
|
83
|
+
releaseChannel?: ReleaseChannel;
|
|
84
|
+
version: string;
|
|
85
|
+
}): Promise<ReleaseInfo>;
|
|
72
86
|
export declare function createUpdateCore(ports: UpdatePorts): UpdateCore;
|
package/dist/service.js
CHANGED
|
@@ -226,6 +226,55 @@ async function fetchNpmRelease(fetchImpl, timeoutMs = CHECK_TIMEOUT_MS, opts) {
|
|
|
226
226
|
throw checkFailedWithStatus(response);
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
|
+
async function fetchNpmVersionRelease(fetchImpl, timeoutMs = CHECK_TIMEOUT_MS, opts) {
|
|
230
|
+
const targetName = opts?.targetPackageName ?? PACKAGE_NAME;
|
|
231
|
+
const registry = opts?.registryUrl ?? NPM_REGISTRY;
|
|
232
|
+
const channel = opts?.releaseChannel === "prerelease" ? "prerelease" : "stable";
|
|
233
|
+
const version = opts?.version;
|
|
234
|
+
if (typeof version !== "string" || !validReleaseVersion(version) || !isVersionAllowedInChannel(version, channel)) {
|
|
235
|
+
throw updateError("invalid-release");
|
|
236
|
+
}
|
|
237
|
+
let response = null;
|
|
238
|
+
try {
|
|
239
|
+
response = await fetchImpl(`${registry}${encodeURIComponent(targetName)}/${encodeURIComponent(version)}`, {
|
|
240
|
+
headers: { accept: "application/json" },
|
|
241
|
+
redirect: "error",
|
|
242
|
+
signal: timeoutSignal(timeoutMs)
|
|
243
|
+
});
|
|
244
|
+
} catch {
|
|
245
|
+
throw updateError("check-failed");
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
if (!response.ok) throw checkFailedWithStatus(response);
|
|
249
|
+
const declared = Number(response.headers.get("content-length"));
|
|
250
|
+
if (Number.isFinite(declared) && declared > MAX_METADATA_BYTES) throw updateError("invalid-release");
|
|
251
|
+
const text = await response.text();
|
|
252
|
+
if (byteLength(text) > MAX_METADATA_BYTES) throw updateError("invalid-release");
|
|
253
|
+
const value = JSON.parse(text);
|
|
254
|
+
if (value.name !== targetName || value.version !== version || !isVersionAllowedInChannel(value.version, channel)) {
|
|
255
|
+
throw updateError("invalid-release");
|
|
256
|
+
}
|
|
257
|
+
const nodeRange = value.engines?.node;
|
|
258
|
+
if (nodeRange !== void 0 && typeof nodeRange !== "string") throw updateError("invalid-release");
|
|
259
|
+
const tarballText = value.dist?.tarball;
|
|
260
|
+
const integrity = value.dist?.integrity;
|
|
261
|
+
let tarball;
|
|
262
|
+
try {
|
|
263
|
+
tarball = new URL(String(tarballText));
|
|
264
|
+
} catch {
|
|
265
|
+
throw updateError("invalid-release");
|
|
266
|
+
}
|
|
267
|
+
const registryOrigin = new URL(registry).origin;
|
|
268
|
+
const shapeOk = tarball.origin === registryOrigin && !tarball.username && !tarball.password && !tarball.search && !tarball.hash && tarball.pathname === `/${targetName}/-/${targetName}-${version}.tgz` && typeof integrity === "string" && new RegExp(INTEGRITY_PATTERN).test(integrity);
|
|
269
|
+
if (!shapeOk) throw updateError("invalid-release");
|
|
270
|
+
return { version, nodeRange: typeof nodeRange === "string" ? nodeRange : "*", integrity, tarball: tarball.href };
|
|
271
|
+
} catch (error) {
|
|
272
|
+
if (error?.code === "check-failed") throw error;
|
|
273
|
+
if (error?.code === "invalid-release") throw error;
|
|
274
|
+
if (response !== null && response.ok) throw updateError("invalid-release");
|
|
275
|
+
throw checkFailedWithStatus(response);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
229
278
|
function createUpdateCore(ports) {
|
|
230
279
|
const checkTimeoutMs = ports.checkTimeoutMs ?? CHECK_TIMEOUT_MS;
|
|
231
280
|
const confirmationTtlMs = ports.confirmationTtlMs ?? CONFIRMATION_TTL_MS;
|
|
@@ -446,6 +495,7 @@ export {
|
|
|
446
495
|
compareVersions,
|
|
447
496
|
createUpdateCore,
|
|
448
497
|
fetchNpmRelease,
|
|
498
|
+
fetchNpmVersionRelease,
|
|
449
499
|
isPrereleaseVersion,
|
|
450
500
|
isVersionAllowedInChannel,
|
|
451
501
|
satisfiesNodeRange,
|