dsh-plugin-update 0.5.8 → 0.7.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 +16 -4
- package/README.md +46 -9
- package/dist/bilingual.d.ts +4 -4
- package/dist/bilingual.js +300 -1
- 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 +10 -2
- package/dist/entry-batch.js +21 -7
- package/dist/entry.d.ts +31 -2
- package/dist/entry.js +83 -27
- package/dist/host-batch.js +104 -13
- package/dist/http.d.ts +2 -2
- package/dist/http.js +1 -1
- package/dist/panel-batch.d.ts +53 -11
- package/dist/panel-batch.js +500 -153
- package/dist/panel.d.ts +84 -25
- package/dist/panel.js +618 -364
- package/dist/store.d.ts +42 -0
- package/dist/store.js +139 -0
- package/package.json +1 -1
package/dist/changelog.d.ts
CHANGED
|
@@ -20,11 +20,12 @@
|
|
|
20
20
|
* - 截断数值不动(100 节/每类 200 条/单条 500 字/全文 64K),解析附计数元数据只记数字;
|
|
21
21
|
* 超限类标计数小字,Security 超限进内折叠;BREAKING 前缀识别 + 行首徽标;yanked 横幅只看 to 版。
|
|
22
22
|
*/
|
|
23
|
+
import { type AppLang } from './lang.js';
|
|
23
24
|
/** 包内日志文件名(包根,与 tarball 内同名文件同一名字)。 */
|
|
24
25
|
export declare const CHANGELOG_FILENAME = "CHANGELOG.md";
|
|
25
|
-
/**
|
|
26
|
+
/** 缺日志时的中性提示(不挡安装,安装按钮状态不变;zh 原文,渲染走字典 changelog.neutral.hint,留常量只为兼容既有导入)。 */
|
|
26
27
|
export declare const CHANGELOG_NEUTRAL_HINT = "\u4F5C\u8005\u672A\u63D0\u4F9B\u66F4\u65B0\u8BF4\u660E";
|
|
27
|
-
/**
|
|
28
|
+
/** 中性提示完整行(含“安装不受影响”,把“不挡安装”说成人话;渲染走字典 changelog.neutral.line)。 */
|
|
28
29
|
export declare const CHANGELOG_NEUTRAL_LINE = "\u4F5C\u8005\u672A\u63D0\u4F9B\u66F4\u65B0\u8BF4\u660E\uFF0C\u5B89\u88C5\u4E0D\u53D7\u5F71\u54CD\u3002";
|
|
29
30
|
/** 输入上限(字符):超限截断后解析,永不抛错、不OOM。 */
|
|
30
31
|
export declare const CHANGELOG_MAX_CHARS: number;
|
|
@@ -79,8 +80,12 @@ export declare function matchVersionHeading(line: unknown): string | null;
|
|
|
79
80
|
export declare function matchCategoryHeading(line: unknown): string | null;
|
|
80
81
|
export declare function matchBulletBody(line: unknown): string | null;
|
|
81
82
|
export declare function isFenceToggle(line: unknown): boolean;
|
|
82
|
-
/** 破坏标记徽标文案(中文 UI
|
|
83
|
+
/** 破坏标记徽标文案(中文 UI 一致,原文前缀另行加粗保留;渲染走字典 changelog.breaking.badge/aria,留常量只为兼容既有导入)。 */
|
|
83
84
|
export declare const BREAKING_BADGE_TEXT = "\u4E0D\u517C\u5BB9";
|
|
85
|
+
/** 六类标题按当前语言单语组装(#66,唯一源仍是 CATEGORY_ZH,不另起第二套映射):中文「新增(Added)」观感、英文「Added」。 */
|
|
86
|
+
export declare function changelogCategoryLabel(cat: ChangelogCategory, lang?: AppLang | string | null): string;
|
|
87
|
+
/** 折叠类标题(含条数):中文「弃用预告(Deprecated)(3)」/英文「Deprecated (3)」;条数是变量值,不译。 */
|
|
88
|
+
export declare function changelogFoldedLabel(cat: ChangelogCategory, count: number, lang?: AppLang | string | null): string;
|
|
84
89
|
/** 剥行首 markdown 装饰(加粗/引用/前后空白),只为识别,渲染保留原文一字不动。 */
|
|
85
90
|
export declare function stripBreakingDecorations(s: unknown): string;
|
|
86
91
|
/** 条目是否为破坏标记(去饰后开头匹配,大小写不敏感,中英文冒号皆可)。 */
|
|
@@ -122,16 +127,16 @@ export declare function selectChangelogEntries(entries: unknown, fromExclusive:
|
|
|
122
127
|
export declare function changelogForUpdate(entries: unknown, runningVersion: unknown, latestVersion: unknown, installedVersion?: unknown): ChangelogEntry[];
|
|
123
128
|
/** 计数元数据取值(缺省视为与 sections 等长,只记数字)。 */
|
|
124
129
|
export declare function countsOf(entry: ChangelogEntry | null | undefined): Record<ChangelogCategory, number>;
|
|
125
|
-
/**
|
|
126
|
-
export declare function truncatedNoteHTML(total: number, shown: number): string;
|
|
127
|
-
/** 撤回横幅(只看 to
|
|
128
|
-
export declare function yankedBannerHTML(version: unknown): string;
|
|
129
|
-
/** 单条目 HTML
|
|
130
|
-
export declare function renderChangelogItem(item: string): string;
|
|
131
|
-
/** 单节 HTML(调用方保证已过滤 Unreleased
|
|
132
|
-
export declare function renderChangelogSection(entry: ChangelogEntry): string;
|
|
133
|
-
/** 中性提示 HTML
|
|
134
|
-
export declare function renderChangelogNeutral(): string;
|
|
130
|
+
/** 超限小字(诚实截断,#66 入字典单语,lang 缺省 zh 零回归):中文与旧文案一字不差,英文走字典。 */
|
|
131
|
+
export declare function truncatedNoteHTML(total: number, shown: number, lang?: AppLang | string | null): string;
|
|
132
|
+
/** 撤回横幅(只看 to 版,纯展示,不挡安装,#66 入字典单语,lang 缺省 zh 零回归;中文与旧文案一字不差)。 */
|
|
133
|
+
export declare function yankedBannerHTML(version: unknown, lang?: AppLang | string | null): string;
|
|
134
|
+
/** 单条目 HTML(含破坏标记徽标与前缀加粗,正文一字不动;#66 徽标与无障碍名入字典单语,lang 缺省 zh 零回归)。 */
|
|
135
|
+
export declare function renderChangelogItem(item: string, lang?: AppLang | string | null): string;
|
|
136
|
+
/** 单节 HTML(调用方保证已过滤 Unreleased 与空节,本函数再兜底一次;#66 按 lang 单语,缺省 zh 零回归)。 */
|
|
137
|
+
export declare function renderChangelogSection(entry: ChangelogEntry, lang?: AppLang | string | null): string;
|
|
138
|
+
/** 中性提示 HTML(缺日志、取不到、无区间内容时统一用它,不挡安装;#66 入字典单语,lang 缺省 zh 零回归)。 */
|
|
139
|
+
export declare function renderChangelogNeutral(lang?: AppLang | string | null): string;
|
|
135
140
|
/**
|
|
136
141
|
* 区间渲染 HTML(纯函数):
|
|
137
142
|
* entries 非数组/空、无可见区间内容一律回中性提示;
|
|
@@ -140,6 +145,7 @@ export declare function renderChangelogNeutral(): string;
|
|
|
140
145
|
export declare function renderChangelogHTML(entries: unknown, opts?: {
|
|
141
146
|
from?: string | null;
|
|
142
147
|
to?: string | null;
|
|
148
|
+
lang?: AppLang | string | null;
|
|
143
149
|
}): string;
|
|
144
150
|
/** 校验诊断(一行一码,行号为原文件 1-based,诊断按行号排序)。 */
|
|
145
151
|
export interface ChangelogDiagnostic {
|
package/dist/changelog.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// AUTO-GENERATED by node build.mjs — DO NOT EDIT. Source: src/changelog.ts
|
|
2
2
|
import { compareReleaseVersions, validReleaseVersion } from "./service.js";
|
|
3
|
+
import { copyText } from "./bilingual.js";
|
|
4
|
+
import { normalizeLangTag } from "./lang.js";
|
|
3
5
|
const CHANGELOG_FILENAME = "CHANGELOG.md";
|
|
4
6
|
const CHANGELOG_NEUTRAL_HINT = "\u4F5C\u8005\u672A\u63D0\u4F9B\u66F4\u65B0\u8BF4\u660E";
|
|
5
7
|
const CHANGELOG_NEUTRAL_LINE = "\u4F5C\u8005\u672A\u63D0\u4F9B\u66F4\u65B0\u8BF4\u660E\uFF0C\u5B89\u88C5\u4E0D\u53D7\u5F71\u54CD\u3002";
|
|
@@ -109,6 +111,18 @@ function isFenceToggle(line) {
|
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
const BREAKING_BADGE_TEXT = "\u4E0D\u517C\u5BB9";
|
|
114
|
+
function changelogCategoryLabel(cat, lang) {
|
|
115
|
+
const l = normalizeLangTag(lang ?? "zh");
|
|
116
|
+
const zh = CHANGELOG_CATEGORY_ZH[cat];
|
|
117
|
+
if (l === "en") return cat;
|
|
118
|
+
return zh + "\uFF08" + cat + "\uFF09";
|
|
119
|
+
}
|
|
120
|
+
function changelogFoldedLabel(cat, count, lang) {
|
|
121
|
+
const l = normalizeLangTag(lang ?? "zh");
|
|
122
|
+
const n = String(Math.floor(count));
|
|
123
|
+
if (l === "en") return cat + " (" + n + ")";
|
|
124
|
+
return CHANGELOG_CATEGORY_ZH[cat] + "\uFF08" + cat + "\uFF09\uFF08" + n + "\uFF09";
|
|
125
|
+
}
|
|
112
126
|
function stripBreakingDecorations(s) {
|
|
113
127
|
try {
|
|
114
128
|
let t = String(s !== null && s !== void 0 ? s : "").trim();
|
|
@@ -331,26 +345,31 @@ function countsOf(entry) {
|
|
|
331
345
|
return { Added: 0, Fixed: 0, Changed: 0, Deprecated: 0, Removed: 0, Security: 0 };
|
|
332
346
|
}
|
|
333
347
|
}
|
|
334
|
-
function truncatedNoteHTML(total, shown) {
|
|
348
|
+
function truncatedNoteHTML(total, shown, lang) {
|
|
335
349
|
try {
|
|
350
|
+
const l = normalizeLangTag(lang ?? "zh");
|
|
336
351
|
const m = Math.floor(total);
|
|
337
352
|
const n = Math.floor(shown);
|
|
338
|
-
|
|
353
|
+
const text = copyText("changelog.truncated.count", l, { m: String(m), n: String(n) });
|
|
354
|
+
return '<div class="dsh-upd-changelog-count">' + escapeChangelogHtml(text) + "</div>";
|
|
339
355
|
} catch {
|
|
340
356
|
return "";
|
|
341
357
|
}
|
|
342
358
|
}
|
|
343
|
-
function yankedBannerHTML(version) {
|
|
359
|
+
function yankedBannerHTML(version, lang) {
|
|
344
360
|
try {
|
|
361
|
+
const l = normalizeLangTag(lang ?? "zh");
|
|
345
362
|
const v = typeof version === "string" ? version.trim() : "";
|
|
346
363
|
if (!v) return "";
|
|
347
|
-
|
|
364
|
+
const text = copyText("changelog.yanked.banner", l, { version: v });
|
|
365
|
+
return '<div class="dsh-upd-changelog-yanked" role="alert">' + escapeChangelogHtml(text) + "</div>";
|
|
348
366
|
} catch {
|
|
349
367
|
return "";
|
|
350
368
|
}
|
|
351
369
|
}
|
|
352
|
-
function renderChangelogItem(item) {
|
|
370
|
+
function renderChangelogItem(item, lang) {
|
|
353
371
|
try {
|
|
372
|
+
const l = normalizeLangTag(lang ?? "zh");
|
|
354
373
|
const s = String(item !== null && item !== void 0 ? item : "");
|
|
355
374
|
if (!s) return "";
|
|
356
375
|
const split = splitBreakingPrefix(s);
|
|
@@ -358,22 +377,25 @@ function renderChangelogItem(item) {
|
|
|
358
377
|
const head = escapeChangelogHtml(split.head);
|
|
359
378
|
const prefix = escapeChangelogHtml(split.prefix);
|
|
360
379
|
const rest = escapeChangelogHtml(split.rest);
|
|
361
|
-
const
|
|
380
|
+
const badgeText = copyText("changelog.breaking.badge", l);
|
|
381
|
+
const badgeAria = copyText("changelog.breaking.aria", l);
|
|
382
|
+
const badge = '<span class="dsh-upd-breaking-badge" role="img" aria-label="' + escapeChangelogHtml(badgeAria) + '">' + escapeChangelogHtml(badgeText) + "</span> ";
|
|
362
383
|
return "<li>" + head + badge + "<strong>" + prefix + "</strong>" + rest + "</li>";
|
|
363
384
|
} catch {
|
|
364
385
|
return "";
|
|
365
386
|
}
|
|
366
387
|
}
|
|
367
|
-
function renderChangelogSection(entry) {
|
|
388
|
+
function renderChangelogSection(entry, lang) {
|
|
368
389
|
try {
|
|
369
390
|
if (!entry || typeof entry !== "object") return "";
|
|
370
391
|
const version = String(entry.version !== void 0 && entry.version !== null ? String(entry.version) : "").trim();
|
|
371
392
|
if (!version || isUnreleasedVersion(version)) return "";
|
|
372
393
|
if (!hasVisibleSections(entry)) return "";
|
|
394
|
+
const l = normalizeLangTag(lang ?? "zh");
|
|
373
395
|
const dateRaw = entry.date;
|
|
374
396
|
const date = typeof dateRaw === "string" ? dateRaw : "";
|
|
375
397
|
const yankedFlag = entry.yanked === true;
|
|
376
|
-
const yankedSuffix = yankedFlag ? "
|
|
398
|
+
const yankedSuffix = yankedFlag ? copyText("changelog.yanked.suffix", l) : "";
|
|
377
399
|
const title = (date ? version + " \xB7 " + date : version) + yankedSuffix;
|
|
378
400
|
const counts = countsOf(entry);
|
|
379
401
|
const parts = [];
|
|
@@ -382,42 +404,44 @@ function renderChangelogSection(entry) {
|
|
|
382
404
|
for (const cat of CHANGELOG_MUST_SHOW) {
|
|
383
405
|
const items = Array.isArray(entry.sections ? entry.sections[cat] : null) ? entry.sections[cat] : [];
|
|
384
406
|
if (!items || items.length === 0) continue;
|
|
385
|
-
const label = cat
|
|
407
|
+
const label = changelogCategoryLabel(cat, l);
|
|
386
408
|
parts.push('<div class="dsh-upd-changelog-cat" data-cat="' + cat + '">');
|
|
387
409
|
parts.push('<div class="dsh-upd-changelog-catname">' + escapeChangelogHtml(label) + "</div>");
|
|
388
410
|
const total = counts[cat];
|
|
389
411
|
const shown = items.length;
|
|
390
412
|
if (total > shown) {
|
|
391
|
-
parts.push(truncatedNoteHTML(total, shown));
|
|
413
|
+
parts.push(truncatedNoteHTML(total, shown, l));
|
|
392
414
|
}
|
|
393
415
|
parts.push("<ul>");
|
|
394
416
|
for (const item of items) {
|
|
395
417
|
if (!item) continue;
|
|
396
|
-
const li = renderChangelogItem(item);
|
|
418
|
+
const li = renderChangelogItem(item, l);
|
|
397
419
|
if (li) parts.push(li);
|
|
398
420
|
}
|
|
399
421
|
parts.push("</ul>");
|
|
400
422
|
if (cat === "Security" && total > shown) {
|
|
401
423
|
const restCount = total - shown;
|
|
402
|
-
|
|
424
|
+
const sumText = copyText("changelog.security.summary", l, { n: String(restCount) });
|
|
425
|
+
const noteText = copyText("changelog.security.note", l);
|
|
426
|
+
parts.push('<details class="dsh-upd-changelog-security-more"><summary>' + escapeChangelogHtml(sumText) + '</summary><div class="dsh-upd-changelog-more-note">' + escapeChangelogHtml(noteText) + "</div></details>");
|
|
403
427
|
}
|
|
404
428
|
parts.push("</div>");
|
|
405
429
|
}
|
|
406
430
|
for (const cat of CHANGELOG_FOLDED) {
|
|
407
431
|
const items = Array.isArray(entry.sections ? entry.sections[cat] : null) ? entry.sections[cat] : [];
|
|
408
432
|
if (!items || items.length === 0) continue;
|
|
409
|
-
const label = cat
|
|
433
|
+
const label = changelogFoldedLabel(cat, items.length, l);
|
|
410
434
|
parts.push('<details class="dsh-upd-changelog-fold" data-cat="' + cat + '">');
|
|
411
435
|
parts.push("<summary>" + escapeChangelogHtml(label) + "</summary>");
|
|
412
436
|
const total = counts[cat];
|
|
413
437
|
const shown = items.length;
|
|
414
438
|
if (total > shown) {
|
|
415
|
-
parts.push(truncatedNoteHTML(total, shown));
|
|
439
|
+
parts.push(truncatedNoteHTML(total, shown, l));
|
|
416
440
|
}
|
|
417
441
|
parts.push("<ul>");
|
|
418
442
|
for (const item of items) {
|
|
419
443
|
if (!item) continue;
|
|
420
|
-
const li = renderChangelogItem(item);
|
|
444
|
+
const li = renderChangelogItem(item, l);
|
|
421
445
|
if (li) parts.push(li);
|
|
422
446
|
}
|
|
423
447
|
parts.push("</ul></details>");
|
|
@@ -428,12 +452,19 @@ function renderChangelogSection(entry) {
|
|
|
428
452
|
return "";
|
|
429
453
|
}
|
|
430
454
|
}
|
|
431
|
-
function renderChangelogNeutral() {
|
|
432
|
-
|
|
455
|
+
function renderChangelogNeutral(lang) {
|
|
456
|
+
try {
|
|
457
|
+
const l = normalizeLangTag(lang ?? "zh");
|
|
458
|
+
const text = copyText("changelog.neutral.line", l);
|
|
459
|
+
return `<div class="dsh-upd-changelog-neutral">${escapeChangelogHtml(text)}</div>`;
|
|
460
|
+
} catch {
|
|
461
|
+
return "";
|
|
462
|
+
}
|
|
433
463
|
}
|
|
434
464
|
function renderChangelogHTML(entries, opts) {
|
|
435
465
|
try {
|
|
436
|
-
|
|
466
|
+
const l = normalizeLangTag(opts?.lang ?? "zh");
|
|
467
|
+
if (!Array.isArray(entries) || entries.length === 0) return renderChangelogNeutral(l);
|
|
437
468
|
const from = opts && typeof opts.from === "string" ? opts.from : null;
|
|
438
469
|
const to = opts && typeof opts.to === "string" ? opts.to : null;
|
|
439
470
|
let ranged;
|
|
@@ -449,14 +480,19 @@ function renderChangelogHTML(entries, opts) {
|
|
|
449
480
|
}
|
|
450
481
|
});
|
|
451
482
|
}
|
|
452
|
-
if (ranged.length === 0) return renderChangelogNeutral();
|
|
453
|
-
const blocks = ranged.map((e) => renderChangelogSection(e)).filter((s) => !!s);
|
|
454
|
-
if (blocks.length === 0) return renderChangelogNeutral();
|
|
483
|
+
if (ranged.length === 0) return renderChangelogNeutral(l);
|
|
484
|
+
const blocks = ranged.map((e) => renderChangelogSection(e, l)).filter((s) => !!s);
|
|
485
|
+
if (blocks.length === 0) return renderChangelogNeutral(l);
|
|
455
486
|
return `<div class="dsh-upd-changelog">
|
|
456
487
|
${blocks.join("\n")}
|
|
457
488
|
</div>`;
|
|
458
489
|
} catch {
|
|
459
|
-
|
|
490
|
+
try {
|
|
491
|
+
const ll = normalizeLangTag(opts?.lang ?? "zh");
|
|
492
|
+
return renderChangelogNeutral(ll);
|
|
493
|
+
} catch {
|
|
494
|
+
return "";
|
|
495
|
+
}
|
|
460
496
|
}
|
|
461
497
|
}
|
|
462
498
|
const CHANGELOG_VALIDATE_HINTS = {
|
|
@@ -639,6 +675,8 @@ export {
|
|
|
639
675
|
RE_VERSION_HEADING,
|
|
640
676
|
RE_VERSION_NUM,
|
|
641
677
|
RE_YANKED,
|
|
678
|
+
changelogCategoryLabel,
|
|
679
|
+
changelogFoldedLabel,
|
|
642
680
|
changelogForUpdate,
|
|
643
681
|
countsOf,
|
|
644
682
|
hasVisibleSections,
|
package/dist/diag.d.ts
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* 构造全程 best-effort:任何一步异常即回 undefined(调用方按无 diag 的旧形状返回,
|
|
32
32
|
* 新面板×旧载荷仍为正常缺省,不抛)。
|
|
33
33
|
*/
|
|
34
|
+
import { type AppLang } from './lang.js';
|
|
34
35
|
/** diag 对象版本:只管大门,新增可选键不 bump,面板永不分支于版本。 */
|
|
35
36
|
export declare const DIAG_VERSION = 1;
|
|
36
37
|
/** 阶段枚举(冻结 6 值,与真实接缝对齐)。 */
|
|
@@ -67,6 +68,8 @@ export interface DiagInput {
|
|
|
67
68
|
environmentKind?: unknown;
|
|
68
69
|
/** 本次电话耗时毫秒(只收有限非负数)。 */
|
|
69
70
|
latencyMs?: unknown;
|
|
71
|
+
/** 人话兜底渲染语言(#66 单语:缺省 zh 零回归;电话侧无 DOM 信号时仍落 zh,面板侧 free-text 英文混入属正常见 #57 v2 非目标)。 */
|
|
72
|
+
lang?: AppLang | string | null;
|
|
70
73
|
}
|
|
71
74
|
export interface DiagObject {
|
|
72
75
|
v: number;
|
package/dist/diag.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// AUTO-GENERATED by node build.mjs — DO NOT EDIT. Source: src/diag.ts
|
|
2
2
|
import { DIAG_INLINE_BUDGET_BYTES, diagByteLength, enforceDiagBudget, resolveRegistryHost, sanitizeDetail } from "./redaction.js";
|
|
3
3
|
import { validReleaseVersion, validRequestId } from "./service.js";
|
|
4
|
+
import { copyText } from "./bilingual.js";
|
|
5
|
+
import { normalizeLangTag } from "./lang.js";
|
|
4
6
|
const DIAG_VERSION = 1;
|
|
5
7
|
const DIAG_STAGES = [
|
|
6
8
|
"read-installed",
|
|
@@ -116,7 +118,7 @@ function pickEnvironmentKind(raw) {
|
|
|
116
118
|
function pickId(raw) {
|
|
117
119
|
return typeof raw === "string" && validRequestId(raw) ? raw.trim() : null;
|
|
118
120
|
}
|
|
119
|
-
function pickDetail(errorCode, error, httpStatus, phoneKind) {
|
|
121
|
+
function pickDetail(errorCode, error, httpStatus, phoneKind, lang) {
|
|
120
122
|
try {
|
|
121
123
|
const rawDetail = error?.detail;
|
|
122
124
|
if (typeof rawDetail === "string" && rawDetail.trim()) {
|
|
@@ -132,24 +134,34 @@ function pickDetail(errorCode, error, httpStatus, phoneKind) {
|
|
|
132
134
|
}
|
|
133
135
|
const code = String(errorCode || "");
|
|
134
136
|
const phone = String(phoneKind || "");
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
else if (code === "check-failed" &&
|
|
140
|
-
else if (code === "check-failed"
|
|
141
|
-
else if (code === "
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
else if (code === "
|
|
145
|
-
else if (code === "
|
|
146
|
-
else if (code === "
|
|
147
|
-
else if (code === "
|
|
148
|
-
else if (code === "
|
|
149
|
-
else if (code === "
|
|
150
|
-
else if (code === "
|
|
151
|
-
else if (code === "
|
|
152
|
-
else if (code === "
|
|
137
|
+
const l = normalizeLangTag(lang ?? "zh");
|
|
138
|
+
let key = "diag.fallback.generic";
|
|
139
|
+
let values;
|
|
140
|
+
if (code === "check-failed" && phone === "update-status") key = "diag.fallback.read-installed";
|
|
141
|
+
else if ((code === "check-failed" || code === "internal") && phone === "update-install") key = "diag.fallback.revalidate-fetch";
|
|
142
|
+
else if (code === "check-failed" && httpStatus === 429) key = "diag.fallback.rate-limited";
|
|
143
|
+
else if (code === "check-failed" && typeof httpStatus === "number") {
|
|
144
|
+
key = "diag.fallback.http-status";
|
|
145
|
+
values = { status: String(httpStatus) };
|
|
146
|
+
} else if (code === "check-failed" || code === "internal") key = "panel.failure.check-failed.title";
|
|
147
|
+
else if (code === "invalid-release") key = "diag.fallback.invalid-release";
|
|
148
|
+
else if (code === "check-expired") key = "panel.failure.check-expired.title";
|
|
149
|
+
else if (code === "update-busy") key = "panel.failure.update-busy.title";
|
|
150
|
+
else if (code === "install-failed") key = "diag.fallback.install-failed";
|
|
151
|
+
else if (code === "unknown-profile") key = "diag.fallback.unknown-profile";
|
|
152
|
+
else if (code === "source-install") key = "diag.fallback.source-install";
|
|
153
|
+
else if (code === "invalid-installation") key = "diag.fallback.invalid-installation";
|
|
154
|
+
else if (code === "installation-changed") key = "diag.fallback.installation-changed";
|
|
155
|
+
else if (code === "pending-restart") key = "diag.fallback.pending-restart";
|
|
156
|
+
else if (code === "incompatible-node") key = "diag.fallback.incompatible-node";
|
|
157
|
+
else if (code === "registry-conflict") key = "diag.fallback.registry-conflict";
|
|
158
|
+
else if (code === "recovery-required") key = "diag.fallback.recovery-required";
|
|
159
|
+
let fallback;
|
|
160
|
+
try {
|
|
161
|
+
fallback = copyText(key, l, values);
|
|
162
|
+
} catch {
|
|
163
|
+
fallback = copyText("diag.fallback.generic", "zh");
|
|
164
|
+
}
|
|
153
165
|
const clean = sanitizeDetail(fallback);
|
|
154
166
|
return clean ? clean : null;
|
|
155
167
|
} catch {
|
|
@@ -176,7 +188,7 @@ function buildDiag(input) {
|
|
|
176
188
|
const httpStatus = pickHttpStatus(stage, input?.error);
|
|
177
189
|
const exitCode = pickExitCode(stage, input?.error);
|
|
178
190
|
const latencyMs = pickLatencyMs(input?.latencyMs);
|
|
179
|
-
const detail = pickDetail(errorCode, input?.error, httpStatus, phoneKind);
|
|
191
|
+
const detail = pickDetail(errorCode, input?.error, httpStatus, phoneKind, input?.lang ?? "zh");
|
|
180
192
|
const targetPackageName = pickPackageName(input?.targetPackageName);
|
|
181
193
|
const runningVersion = pickVersion(input?.runningVersion);
|
|
182
194
|
const latestVersion = pickVersion(input?.latestVersion);
|
package/dist/entry-batch.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type BilingualKey } from './bilingual.js';
|
|
2
2
|
import { type AppLang, type LocaleOption } from './lang.js';
|
|
3
3
|
import { type BatchRowView } from './panel-batch.js';
|
|
4
|
-
import { type UpdatePanelTheme } from './panel.js';
|
|
4
|
+
import { type UpdatePanelTheme, type UpdateThemeTokens } from './panel.js';
|
|
5
5
|
/** 批量入口件的形态(与单入口同一套取值)。 */
|
|
6
6
|
export type BatchEntryVariant = 'button' | 'badge' | 'inline';
|
|
7
7
|
/** 什么时候主动查一次(只读;与单入口同一口径)。 */
|
|
@@ -40,10 +40,16 @@ export interface UpdateBatchEntryOptions {
|
|
|
40
40
|
/** 调宿主电话:(phoneName, args) => Promise<reply>。 */
|
|
41
41
|
call: (name: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
42
42
|
variant?: BatchEntryVariant;
|
|
43
|
-
/** 主题:与单入口/面板同一套(default/archive
|
|
43
|
+
/** 主题:与单入口/面板同一套(default/archive)。 */
|
|
44
44
|
theme?: UpdatePanelTheme;
|
|
45
|
+
/** 主题变量覆盖:见 panel 的 UpdateThemeTokens;批量入口根 + 打开的批量面板同步生效,不传即零回归。 */
|
|
46
|
+
themeTokens?: UpdateThemeTokens;
|
|
45
47
|
/** 缺省 'mount':进页面静默查一次(只调 .batchStatus,只读)。'never' 则只在用户点击时查。 */
|
|
46
48
|
autoCheck?: BatchEntryAutoCheck;
|
|
49
|
+
/** 打开面板自动查(#59 D3,透传给批量面板):缺省 true;面板按用户偏好 > 本选项 > 缺省,并与入口预查共用知识时间戳去重(一击只查一次)。 */
|
|
50
|
+
checkOnOpen?: boolean;
|
|
51
|
+
/** 自动继续未终态轮次(#59 Q3,透传给批量面板):缺省 true,与显式按钮并存。 */
|
|
52
|
+
autoResume?: boolean;
|
|
47
53
|
/** 缺省 'always':查完总是开批量面板(见本类型说明)。 */
|
|
48
54
|
openOn?: BatchEntryOpenOn;
|
|
49
55
|
/** 覆盖默认按钮文案(不传就用聚合文案)。 */
|
|
@@ -78,6 +84,8 @@ export interface UpdateBatchEntryController {
|
|
|
78
84
|
/** 当前聚合读数(含七档计数,接入方排版与 onActivate 共用)。 */
|
|
79
85
|
summary(): BatchEntrySummary;
|
|
80
86
|
setTheme(theme: UpdatePanelTheme): void;
|
|
87
|
+
/** 换一套主题变量(重绘;打开的批量面板同步;传 undefined 即清掉覆盖)。 */
|
|
88
|
+
setThemeTokens(tokens: UpdateThemeTokens | undefined): void;
|
|
81
89
|
unmount(): void;
|
|
82
90
|
}
|
|
83
91
|
/**
|
package/dist/entry-batch.js
CHANGED
|
@@ -11,7 +11,8 @@ import {
|
|
|
11
11
|
} from "./panel-batch.js";
|
|
12
12
|
import {
|
|
13
13
|
failureCodeOf,
|
|
14
|
-
normalizePanelTheme
|
|
14
|
+
normalizePanelTheme,
|
|
15
|
+
themeTokensStyleFor
|
|
15
16
|
} from "./panel.js";
|
|
16
17
|
function isObject(value) {
|
|
17
18
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -145,10 +146,12 @@ function mountUpdateBatchEntry(container, options) {
|
|
|
145
146
|
if (openOn !== "has-update" && openOn !== "always" && openOn !== "manual" && openOn !== "direct") {
|
|
146
147
|
throw new Error("[dsh-plugin-update] \u70B9\u51FB\u53BB\u5411\u975E\u6CD5\uFF1A\u53EA\u6536 has-update / always / manual / direct\uFF08\u6536\u5230 " + JSON.stringify(options.openOn) + "\uFF09");
|
|
147
148
|
}
|
|
148
|
-
if (options.theme !== void 0 && options.theme !== "default" && options.theme !== "archive"
|
|
149
|
-
throw new Error("[dsh-plugin-update] \u4E3B\u9898\u975E\u6CD5\uFF1A\u53EA\u6536 default \u6216 archive\
|
|
149
|
+
if (options.theme !== void 0 && options.theme !== "default" && options.theme !== "archive") {
|
|
150
|
+
throw new Error("[dsh-plugin-update] \u4E3B\u9898\u975E\u6CD5\uFF1A\u53EA\u6536 default \u6216 archive\uFF08\u6536\u5230 " + JSON.stringify(options.theme) + "\uFF09");
|
|
150
151
|
}
|
|
151
152
|
let theme = normalizePanelTheme(options.theme ?? "default");
|
|
153
|
+
themeTokensStyleFor(options.themeTokens ?? void 0);
|
|
154
|
+
let themeTokens = options.themeTokens;
|
|
152
155
|
const pollMs = options.pollMs;
|
|
153
156
|
if (pollMs !== void 0 && (typeof pollMs !== "number" || !Number.isFinite(pollMs) || pollMs < MIN_PANEL_POLL_MS)) {
|
|
154
157
|
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");
|
|
@@ -220,9 +223,11 @@ function mountUpdateBatchEntry(container, options) {
|
|
|
220
223
|
const labelText = labelOverride ?? (activating ? copyText("batch-entry.action.checking", lang) : copyText(batchEntryBilingualKeyFor(stateOf()), lang, batchEntryBilingualValuesFor(stateOf())));
|
|
221
224
|
const busyAttr = activating ? ' disabled aria-busy="true"' : "";
|
|
222
225
|
const themeAttr = theme === "archive" ? ' data-theme="archive"' : "";
|
|
226
|
+
const tokensStyle = themeTokensStyleFor(themeTokens ?? void 0);
|
|
227
|
+
const tokensAttr = tokensStyle ? ' style="' + tokensStyle + '"' : "";
|
|
223
228
|
const control = variant === "badge" ? '<button type="button" class="dsh-upd-entry-dot" ' + ENTRY_ATTR + '="activate" title="' + escapeHtml(labelText) + '" aria-label="' + escapeHtml(labelText) + '"' + busyAttr + "></button>" : '<button type="button" class="dsh-upd-entry-btn" ' + ENTRY_ATTR + '="activate"' + busyAttr + ">" + labelHTML + "</button>";
|
|
224
229
|
const noteHTML = note ? '<span class="dsh-upd-entry-note" data-dsh-upd-note="1">' + escapeHtml(note) + "</span>" : "";
|
|
225
|
-
return "<style>" + UPDATE_ENTRY_CSS + "\n" + BILINGUAL_CSS + '</style>\n<span class="dsh-upd-entry" data-variant="' + variant + '" data-state="' + summary.kind + '"' + themeAttr + ">" + control + noteHTML + "</span>";
|
|
230
|
+
return "<style>" + UPDATE_ENTRY_CSS + "\n" + BILINGUAL_CSS + '</style>\n<span class="dsh-upd-entry" data-variant="' + variant + '" data-state="' + summary.kind + '"' + themeAttr + tokensAttr + ">" + control + noteHTML + "</span>";
|
|
226
231
|
}
|
|
227
232
|
function render() {
|
|
228
233
|
if (!mounted) return;
|
|
@@ -267,12 +272,15 @@ function mountUpdateBatchEntry(container, options) {
|
|
|
267
272
|
prefix: options.prefix,
|
|
268
273
|
mode,
|
|
269
274
|
theme,
|
|
275
|
+
themeTokens,
|
|
270
276
|
pollMs,
|
|
271
277
|
titles,
|
|
272
278
|
onRestartRequested: options.onRestartRequested,
|
|
273
279
|
copyText: options.copyText,
|
|
274
280
|
autoChangelog: options.autoChangelog,
|
|
275
281
|
locale: localeOpt,
|
|
282
|
+
checkOnOpen: options.checkOnOpen,
|
|
283
|
+
autoResume: options.autoResume,
|
|
276
284
|
// 面板点「关闭」即走入口件的完整关闭(收 dialog + 还原按钮 + 重查一次),不再是面板自己停轮询。
|
|
277
285
|
onCloseRequested: () => close(),
|
|
278
286
|
call: panelCall
|
|
@@ -337,13 +345,19 @@ function mountUpdateBatchEntry(container, options) {
|
|
|
337
345
|
render();
|
|
338
346
|
}
|
|
339
347
|
function setTheme(next) {
|
|
340
|
-
if (next !== "default" && next !== "archive"
|
|
341
|
-
throw new Error("[dsh-plugin-update] \u4E3B\u9898\u975E\u6CD5\uFF1A\u53EA\u6536 default \u6216 archive\
|
|
348
|
+
if (next !== "default" && next !== "archive") {
|
|
349
|
+
throw new Error("[dsh-plugin-update] \u4E3B\u9898\u975E\u6CD5\uFF1A\u53EA\u6536 default \u6216 archive\uFF08\u6536\u5230 " + JSON.stringify(next) + "\uFF09");
|
|
342
350
|
}
|
|
343
351
|
theme = normalizePanelTheme(next);
|
|
344
352
|
if (panel) void panel.setTheme(theme);
|
|
345
353
|
else render();
|
|
346
354
|
}
|
|
355
|
+
function setThemeTokens(next) {
|
|
356
|
+
themeTokensStyleFor(next ?? void 0);
|
|
357
|
+
themeTokens = next ?? void 0;
|
|
358
|
+
if (panel) void panel.setThemeTokens(themeTokens);
|
|
359
|
+
else render();
|
|
360
|
+
}
|
|
347
361
|
function onClick(ev) {
|
|
348
362
|
if (!mounted) return;
|
|
349
363
|
try {
|
|
@@ -406,7 +420,7 @@ function mountUpdateBatchEntry(container, options) {
|
|
|
406
420
|
if (variant === "inline") mountPanel("embedded");
|
|
407
421
|
else render();
|
|
408
422
|
if (autoCheck === "mount") void refresh();
|
|
409
|
-
return { refresh, open, close, label: currentLabel, summary: summaryOf, setTheme, unmount };
|
|
423
|
+
return { refresh, open, close, label: currentLabel, summary: summaryOf, setTheme, setThemeTokens, unmount };
|
|
410
424
|
}
|
|
411
425
|
export {
|
|
412
426
|
batchEntryBilingualHTMLFor,
|
package/dist/entry.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type UpdatePanelContainer, type UpdatePanelTheme } from './panel.js';
|
|
1
|
+
import { type UpdatePanelContainer, type UpdatePanelTheme, type UpdateThemeTokens } from './panel.js';
|
|
2
2
|
import type { UpdateSnapshot } from './ports.js';
|
|
3
3
|
import { type BilingualKey } from './bilingual.js';
|
|
4
4
|
import { type AppLang, type LocaleOption } from './lang.js';
|
|
@@ -21,6 +21,24 @@ export interface UpdateEntryState {
|
|
|
21
21
|
snapshot: UpdateSnapshot | null;
|
|
22
22
|
error: string | null;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* 入口件按钮尺寸覆盖(#69):只影响 button 本体(字号/内边距/圆角/整体缩放),不碰 dialog 面板。
|
|
26
|
+
* 缺省(不传)保持现状、零回归;badge 圆点与 inline 内嵌不读这些变量,天然不受影响。
|
|
27
|
+
* 实现口径与现有 `--dsh-update-*` 颜色变量一致:本选项只是把同样的 CSS 变量以内联方式写到容器上,
|
|
28
|
+
* 手写 CSS 变量(`--dsh-update-entry-font-size` / `--dsh-update-entry-padding` /
|
|
29
|
+
* `--dsh-update-entry-border-radius` / `--dsh-update-entry-scale`)同样生效,两者等价。
|
|
30
|
+
* `scale` 即宿主临时方案里容器 `zoom: 1` 开关的正式形态:改一个数即缩放(默认 1)。
|
|
31
|
+
*/
|
|
32
|
+
export interface EntrySizing {
|
|
33
|
+
/** 按钮字号(CSS font-size 值,如 '12px'),不传即 13px 默认。 */
|
|
34
|
+
fontSize?: string;
|
|
35
|
+
/** 按钮内边距(CSS padding 值,如 '2px 8px'),不传即 '4px 12px' 默认。 */
|
|
36
|
+
padding?: string;
|
|
37
|
+
/** 按钮圆角(CSS border-radius 值,如 '8px'),不传即默认主题 6px / archive 主题 3px。 */
|
|
38
|
+
borderRadius?: string;
|
|
39
|
+
/** 整体缩放(对应 CSS `zoom`,如 1.2 放大、0.9 缩小),须为大于 0 的有限数,不传即 1。 */
|
|
40
|
+
scale?: number;
|
|
41
|
+
}
|
|
24
42
|
export interface UpdateEntryOptions {
|
|
25
43
|
pluginId: string;
|
|
26
44
|
/** 单插件电话前缀(与宿主侧一致)。 */
|
|
@@ -28,7 +46,7 @@ export interface UpdateEntryOptions {
|
|
|
28
46
|
/** 调宿主电话:(phoneName, args) => Promise<reply>。 */
|
|
29
47
|
call: (name: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
30
48
|
variant?: EntryVariant;
|
|
31
|
-
/**
|
|
49
|
+
/** 主题:与面板同一套(`default` 最小可用,`archive` 档案卷纸面浅色)。 */
|
|
32
50
|
theme?: UpdatePanelTheme;
|
|
33
51
|
/** 缺省 'mount':进页面静默查一次(只读)。'never' 则只在用户点击时查。 */
|
|
34
52
|
autoCheck?: EntryAutoCheck;
|
|
@@ -36,6 +54,10 @@ export interface UpdateEntryOptions {
|
|
|
36
54
|
openOn?: EntryOpenOn;
|
|
37
55
|
/** 覆盖默认按钮文案(不传就用状态联动文案)。 */
|
|
38
56
|
label?: string;
|
|
57
|
+
/** 按钮尺寸覆盖(#69):见 EntrySizing;不传即零回归,badge/inline 不受影响。 */
|
|
58
|
+
sizing?: EntrySizing;
|
|
59
|
+
/** 主题变量覆盖:见 panel 的 UpdateThemeTokens;入口件根 + 打开的 dialog 面板同步生效,不传即零回归。 */
|
|
60
|
+
themeTokens?: UpdateThemeTokens;
|
|
39
61
|
/** 语言覆盖(#60 v2):'zh' | 'en' | { getActive(): string; subscribe?(cb): () => void },不传即跟随 html[lang] > navigator > zh。 */
|
|
40
62
|
locale?: LocaleOption;
|
|
41
63
|
profileName?: string;
|
|
@@ -62,6 +84,8 @@ export interface UpdateEntryController {
|
|
|
62
84
|
/** 当前按钮上的状态文案(接入方做自定义排版时读它)。 */
|
|
63
85
|
label(): string;
|
|
64
86
|
setTheme(theme: UpdatePanelTheme): void;
|
|
87
|
+
/** 换一套主题变量(重绘;打开的 dialog 面板同步;传 undefined 即清掉覆盖)。 */
|
|
88
|
+
setThemeTokens(tokens: UpdateThemeTokens | undefined): void;
|
|
65
89
|
unmount(): void;
|
|
66
90
|
}
|
|
67
91
|
/**
|
|
@@ -82,5 +106,10 @@ export declare function entryBilingualHTMLFor(state: UpdateEntryState | null | u
|
|
|
82
106
|
export declare function entryBilingualTextFor(state: UpdateEntryState | null | undefined, lang?: AppLang | string | null): string;
|
|
83
107
|
/** 入口件文案第二出口(唯一出处:测试与接入方都读它;与 HTML 出口同语言,v2 起按 lang 取字典,不再硬编码中文)。 */
|
|
84
108
|
export declare function entryLabelFor(state: UpdateEntryState | null | undefined, lang?: AppLang | string | null): string;
|
|
109
|
+
/**
|
|
110
|
+
* `sizing` → 容器 style 属性体(纯函数:同一输入永远算出同一串;空/缺省回空串,即不写 style)。
|
|
111
|
+
* 非法即抛(未知键、空串、注入字符、非正有限 scale 都不收)。
|
|
112
|
+
*/
|
|
113
|
+
export declare function entrySizingStyleFor(sizing: EntrySizing | null | undefined): string;
|
|
85
114
|
export declare const UPDATE_ENTRY_CSS: string;
|
|
86
115
|
export declare function mountUpdateEntry(container: UpdatePanelContainer, options: UpdateEntryOptions): UpdateEntryController;
|