dsh-plugin-update 0.5.7 → 0.6.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 +17 -4
- package/README.md +29 -10
- package/dist/bilingual.d.ts +23 -13
- package/dist/bilingual.js +324 -10
- package/dist/changelog.d.ts +19 -13
- package/dist/changelog.js +60 -22
- package/dist/diag.d.ts +3 -0
- package/dist/diag.js +32 -20
- package/dist/entry-batch.d.ts +22 -5
- package/dist/entry-batch.js +86 -19
- package/dist/entry.d.ts +37 -9
- package/dist/entry.js +105 -51
- package/dist/host-batch.js +104 -13
- package/dist/http.d.ts +2 -2
- package/dist/http.js +1 -1
- package/dist/lang.js +150 -0
- package/dist/panel-batch.d.ts +50 -9
- package/dist/panel-batch.js +484 -150
- package/dist/panel.d.ts +37 -22
- package/dist/panel.js +504 -362
- package/dist/store.d.ts +42 -0
- package/dist/store.js +139 -0
- package/package.json +1 -1
package/dist/lang.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// AUTO-GENERATED by node build.mjs — DO NOT EDIT. Source: src/lang.ts
|
|
2
|
+
function normalizeLangTag(tag) {
|
|
3
|
+
if (typeof tag !== "string") return "zh";
|
|
4
|
+
const s = tag.trim().toLowerCase().replace(/_/g, "-");
|
|
5
|
+
if (!s) return "zh";
|
|
6
|
+
if (s === "zh" || s.startsWith("zh-")) return "zh";
|
|
7
|
+
if (s === "en" || s.startsWith("en-")) return "en";
|
|
8
|
+
if (/^[a-z]{2,3}(-[a-z0-9]+)*$/.test(s)) return "en";
|
|
9
|
+
return "zh";
|
|
10
|
+
}
|
|
11
|
+
function readDocumentLang() {
|
|
12
|
+
try {
|
|
13
|
+
const g = globalThis;
|
|
14
|
+
const v = g.document?.documentElement?.lang;
|
|
15
|
+
if (typeof v === "string" && v.trim()) return v;
|
|
16
|
+
} catch {
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function readNavigatorLangs() {
|
|
21
|
+
try {
|
|
22
|
+
const g = globalThis;
|
|
23
|
+
const nav = g.navigator;
|
|
24
|
+
if (!nav) return [];
|
|
25
|
+
const out = [];
|
|
26
|
+
if (Array.isArray(nav.languages)) {
|
|
27
|
+
for (const c of nav.languages) {
|
|
28
|
+
if (typeof c === "string" && c.trim()) out.push(c);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (typeof nav.language === "string" && nav.language.trim()) out.push(nav.language);
|
|
32
|
+
return out;
|
|
33
|
+
} catch {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function resolveLang(override) {
|
|
38
|
+
if (override !== null && typeof override === "object") {
|
|
39
|
+
try {
|
|
40
|
+
const fn = override.getActive;
|
|
41
|
+
if (typeof fn === "function") {
|
|
42
|
+
const v = fn.call(override);
|
|
43
|
+
if (typeof v === "string" && v.trim()) return normalizeLangTag(v);
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
} else if (typeof override === "string" && override.trim()) {
|
|
48
|
+
return normalizeLangTag(override);
|
|
49
|
+
}
|
|
50
|
+
const docLang = readDocumentLang();
|
|
51
|
+
if (docLang !== null) return normalizeLangTag(docLang);
|
|
52
|
+
const navs = readNavigatorLangs();
|
|
53
|
+
for (const c of navs) {
|
|
54
|
+
return normalizeLangTag(c);
|
|
55
|
+
}
|
|
56
|
+
return "zh";
|
|
57
|
+
}
|
|
58
|
+
const entries = /* @__PURE__ */ new Set();
|
|
59
|
+
let mo = null;
|
|
60
|
+
function ensureGlobalObserver() {
|
|
61
|
+
if (mo !== null) return;
|
|
62
|
+
try {
|
|
63
|
+
const g = globalThis;
|
|
64
|
+
const docEl = g.document?.documentElement;
|
|
65
|
+
const MO = g.MutationObserver;
|
|
66
|
+
if (!docEl || typeof MO !== "function") return;
|
|
67
|
+
const obs = new MO(() => {
|
|
68
|
+
notifyAll();
|
|
69
|
+
});
|
|
70
|
+
obs.observe(docEl, { attributes: true, attributeFilter: ["lang"] });
|
|
71
|
+
mo = obs;
|
|
72
|
+
} catch {
|
|
73
|
+
mo = null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function notifyAll() {
|
|
77
|
+
for (const e of [...entries]) {
|
|
78
|
+
try {
|
|
79
|
+
const next = resolveLang(e.override);
|
|
80
|
+
if (next !== e.last) {
|
|
81
|
+
e.last = next;
|
|
82
|
+
e.cb(next);
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function subscribeLang(cb, override) {
|
|
89
|
+
if (typeof cb !== "function") throw new Error("[dsh-plugin-update] subscribeLang needs a function");
|
|
90
|
+
const entry = { cb, override: override ?? void 0, last: resolveLang(override), serviceUnsub: null };
|
|
91
|
+
entries.add(entry);
|
|
92
|
+
ensureGlobalObserver();
|
|
93
|
+
try {
|
|
94
|
+
if (entry.override !== null && typeof entry.override === "object") {
|
|
95
|
+
const sub = entry.override.subscribe;
|
|
96
|
+
if (typeof sub === "function") {
|
|
97
|
+
const un = sub.call(entry.override, () => {
|
|
98
|
+
try {
|
|
99
|
+
const next = resolveLang(entry.override);
|
|
100
|
+
if (next !== entry.last) {
|
|
101
|
+
entry.last = next;
|
|
102
|
+
entry.cb(next);
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
if (typeof un === "function") entry.serviceUnsub = un;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
let done = false;
|
|
113
|
+
return () => {
|
|
114
|
+
if (done) return;
|
|
115
|
+
done = true;
|
|
116
|
+
entries.delete(entry);
|
|
117
|
+
try {
|
|
118
|
+
entry.serviceUnsub?.();
|
|
119
|
+
} catch {
|
|
120
|
+
}
|
|
121
|
+
entry.serviceUnsub = null;
|
|
122
|
+
if (entries.size === 0) {
|
|
123
|
+
try {
|
|
124
|
+
mo?.disconnect();
|
|
125
|
+
} catch {
|
|
126
|
+
}
|
|
127
|
+
mo = null;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function __resetLangState() {
|
|
132
|
+
for (const e of [...entries]) {
|
|
133
|
+
try {
|
|
134
|
+
e.serviceUnsub?.();
|
|
135
|
+
} catch {
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
entries.clear();
|
|
139
|
+
try {
|
|
140
|
+
mo?.disconnect();
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
143
|
+
mo = null;
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
__resetLangState,
|
|
147
|
+
normalizeLangTag,
|
|
148
|
+
resolveLang,
|
|
149
|
+
subscribeLang
|
|
150
|
+
};
|
package/dist/panel-batch.d.ts
CHANGED
|
@@ -54,9 +54,23 @@ export interface BatchPanelOptions {
|
|
|
54
54
|
* 不传则回退为只停轮询(unmount),DOM 留给调用方处理。入口件打开的 dialog 已内置(收 dialog + 还原按钮)。
|
|
55
55
|
*/
|
|
56
56
|
onCloseRequested?: () => void | Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* 语言覆盖(#59 起消费:新文案走集中字典单语渲染;既有散落文案保持基线不变)。
|
|
59
|
+
* 形态与入口件一致:'zh' | 'en' | { getActive(): string; subscribe?(cb): () => void }。
|
|
60
|
+
*/
|
|
61
|
+
locale?: unknown;
|
|
62
|
+
/**
|
|
63
|
+
* 打开面板自动查(#59 D3):缺省 true。false 即手动挡(行为回今天,只修文案)。
|
|
64
|
+
* 优先级:用户偏好(prefs.json)> 本选项 > 缺省。
|
|
65
|
+
*/
|
|
66
|
+
checkOnOpen?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* 自动继续未终态轮次(#59 Q3:与显式按钮并存,常开)。false 可关(测试与特殊集成用)。
|
|
69
|
+
*/
|
|
70
|
+
autoResume?: boolean;
|
|
57
71
|
}
|
|
58
72
|
/** 面板可点的动作(HTML 上 data-act 一一对应;测试走同一条路)。 */
|
|
59
|
-
export type BatchPanelActionKind = 'check' | 'install' | 'resume' | 'cancel' | 'row-install' | 'row-skip' | 'row-resume-skip' | 'row-cancel-queue' | 'row-copy-manual' | 'row-copy-diag' | 'toggle-details' | 'restart' | 'close';
|
|
73
|
+
export type BatchPanelActionKind = 'check' | 'install' | 'resume' | 'cancel' | 'row-install' | 'row-skip' | 'row-resume-skip' | 'row-cancel-queue' | 'row-copy-manual' | 'row-copy-diag' | 'toggle-details' | 'restart' | 'close' | 'toggle-check-on-open';
|
|
60
74
|
/** 挂载点:只要有 innerHTML 的容器即可(浏览器元素或测试替身都行)。 */
|
|
61
75
|
export interface BatchPanelContainer {
|
|
62
76
|
innerHTML: string;
|
|
@@ -71,20 +85,22 @@ export interface BatchPanelController {
|
|
|
71
85
|
setMode(mode: BatchPanelMode): void;
|
|
72
86
|
unmount(): void;
|
|
73
87
|
}
|
|
74
|
-
/**
|
|
88
|
+
/** 批量七个电话名(与宿主侧 MultiHostUpdate.phoneNames 同一形状)。 */
|
|
75
89
|
export interface BatchPhoneNames {
|
|
76
90
|
status: string;
|
|
77
91
|
check: string;
|
|
78
92
|
install: string;
|
|
79
93
|
resume: string;
|
|
80
94
|
cancel: string;
|
|
95
|
+
prefs: string;
|
|
96
|
+
prefsSave: string;
|
|
81
97
|
}
|
|
82
98
|
/** 批量面板轮询口径(默认 1.5 秒、下限 250 毫秒,与单插件面板同一套下限)。 */
|
|
83
99
|
export declare const BATCH_PANEL_POLL: {
|
|
84
100
|
readonly defaultMs: 1500;
|
|
85
101
|
readonly minMs: 250;
|
|
86
102
|
};
|
|
87
|
-
/** 批量电话名拼法:前缀 +
|
|
103
|
+
/** 批量电话名拼法:前缀 + 七个固定动作名(前缀形状校验与单插件面板同一套)。 */
|
|
88
104
|
export declare function buildBatchPhoneNames(prefix: string): BatchPhoneNames;
|
|
89
105
|
export interface BatchLedgerCounts {
|
|
90
106
|
/** phase=ready:有新版、还没安装。 */
|
|
@@ -109,20 +125,37 @@ export interface BatchLedgerCounts {
|
|
|
109
125
|
* 宿主忙时先写占位再回 update-busy,面板把它翻回「可更新」,免得总账把它报成失败。
|
|
110
126
|
*/
|
|
111
127
|
export declare function batchLedgerCounts(rows: readonly BatchRowView[]): BatchLedgerCounts;
|
|
112
|
-
/** 分类计数 → 一句话总账(只出现非零档,顺序固定:可更新 · 安装中 · 待查 · 待重启 · 失败 · 已跳过 ·
|
|
113
|
-
export declare function batchLedgerText(counts: BatchLedgerCounts): string;
|
|
128
|
+
/** 分类计数 → 一句话总账(只出现非零档,顺序固定:可更新 · 安装中 · 待查 · 待重启 · 失败 · 已跳过 · 已最新;#64 单语:缺省 zh 零回归)。 */
|
|
129
|
+
export declare function batchLedgerText(counts: BatchLedgerCounts, lang?: unknown): string;
|
|
114
130
|
/**
|
|
115
131
|
* 排队中的状态词:只回答「还要等多久」。位置从该行的队列视图来。
|
|
116
132
|
* queue.ts 的 position 是 waiting 顺位(队首为 1、0 = 自己正在装),而正在装的那一家也压在这一家前面,
|
|
117
133
|
* 所以「前方 N 个」= position N(队首那家前方正好 1 个:正在装的拥有者)。
|
|
118
134
|
* 位置取不到(宿主只记了忙、没给占位读数)就说「等前面安装完」,不猜数字。
|
|
119
135
|
*/
|
|
120
|
-
export declare function batchQueuedStatus(position: number | null): string;
|
|
136
|
+
export declare function batchQueuedStatus(position: number | null, lang?: unknown): string;
|
|
137
|
+
/** 知识账本里的一行(只做展示,不参与安装决策)。 */
|
|
138
|
+
export interface BatchKnowledgeEntry {
|
|
139
|
+
lastCheckedAt: number;
|
|
140
|
+
installedVersion: string | null;
|
|
141
|
+
latestVersion: string | null;
|
|
142
|
+
canInstall: boolean | null;
|
|
143
|
+
error: string | null;
|
|
144
|
+
}
|
|
145
|
+
/** 有未终态行(控制区出现条件:盘上有没做完的一轮)。 */
|
|
146
|
+
export declare function hasUnfinishedRows(rows: readonly BatchRowView[], session?: unknown): boolean;
|
|
147
|
+
export declare function unfinishedCount(rows: readonly BatchRowView[], session?: unknown): number;
|
|
121
148
|
/**
|
|
122
149
|
* 一行的状态词:只回答一个问题——这家的**下一步**是什么。
|
|
123
150
|
* 中文可执行,不写相位英文(相位只留在 data-phase 属性上,给人看的这句永远是动作)。
|
|
151
|
+
* (#59 D2:调用方在无轮次 + 有知识时优先用 batchRowKnowledgeText;本函数语义冻结,旧快照不动。)
|
|
152
|
+
*/
|
|
153
|
+
export declare function batchRowStatus(row: BatchRowView, skippedVersion?: string | null, lang?: unknown): string;
|
|
154
|
+
/**
|
|
155
|
+
* 无轮次时的知识行(#59 D2):pending + 有知识即按知识展示;有轮次未做完仍走执行态。
|
|
156
|
+
* 无知识(从没查过)回 null,调用方回退旧 pending 文案。
|
|
124
157
|
*/
|
|
125
|
-
export declare function
|
|
158
|
+
export declare function batchRowKnowledgeText(row: BatchRowView, entry: BatchKnowledgeEntry | null, lang?: unknown): string | null;
|
|
126
159
|
export interface BatchPanelRenderInput {
|
|
127
160
|
rows?: readonly BatchRowView[];
|
|
128
161
|
theme?: UpdatePanelTheme;
|
|
@@ -146,15 +179,23 @@ export interface BatchPanelRenderInput {
|
|
|
146
179
|
noticeKey?: string | null;
|
|
147
180
|
/** 键 -> 该行已取到的日志全文(只传有文本的;取不到与没展开即中性提示,不挡安装)。 */
|
|
148
181
|
changelogs?: Record<string, string | null>;
|
|
182
|
+
/** 轮次会话(有未终态行才画控制区;不传按行相位回退旧口径,兼容旧快照)。 */
|
|
183
|
+
session?: unknown;
|
|
184
|
+
/** 知识账本(无轮次时行按知识展示;只做展示,不参与安装决策)。 */
|
|
185
|
+
inventory?: unknown;
|
|
186
|
+
/** 偏好(底部勾选的受控状态;不传不画勾选)。 */
|
|
187
|
+
prefs?: unknown;
|
|
188
|
+
/** 语言(单语渲染新文案用;不传跟随全局信号)。 */
|
|
189
|
+
lang?: unknown;
|
|
149
190
|
}
|
|
150
191
|
/** 整面板 HTML(含样式;重绘即整体替换 innerHTML,故每次都带 style 也只留一份)。 */
|
|
151
192
|
export declare function renderBatchPanelHTML(input: BatchPanelRenderInput): string;
|
|
152
193
|
export declare const UPDATE_BATCH_PANEL_CSS: string;
|
|
153
194
|
/**
|
|
154
|
-
* 批量面板的
|
|
195
|
+
* 批量面板的 Archive 皮肤(#20 同一套口径:只换颜色/字体/间距,不改顺序、不藏东西)。
|
|
155
196
|
* 卷宗抬头右侧给大印章留 120px(与单插件面板档案头同一处理)。
|
|
156
197
|
*/
|
|
157
|
-
export declare const
|
|
198
|
+
export declare const UPDATE_BATCH_PANEL_ARCHIVE_CSS: string;
|
|
158
199
|
/**
|
|
159
200
|
* 挂批量面板(调用方一行即跑):
|
|
160
201
|
* ```js
|