dsh-folia 3.2.0 → 3.4.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/cordis.patch.yml +18 -0
- package/lib/client.js +20 -0
- package/lib/index.js +74 -1
- package/lib/routes/skins.js +42 -0
- package/package.json +1 -1
package/cordis.patch.yml
CHANGED
|
@@ -18,3 +18,21 @@
|
|
|
18
18
|
- insert:
|
|
19
19
|
- id: folia
|
|
20
20
|
name: 'dsh-folia'
|
|
21
|
+
|
|
22
|
+
# ── 内嵌皮肤中心(3.4.0 起)────────────────────────────────────────────────────
|
|
23
|
+
# 皮肤的**渲染**由皮肤中心负责:catalog、强制作用域化 CSS、六层装饰、hooks 运行时、
|
|
24
|
+
# 背景媒体、以及它自己的「设置 → 皮肤」页面(试穿 / 应用)。它的控制器不外露,所以
|
|
25
|
+
# "完整应用"只能由它自己的前端半区完成 —— 而 DSH 是**按行派发前端模块**的,
|
|
26
|
+
# 因此必须在这里给它一行,否则只有宿主路由、没有界面。
|
|
27
|
+
#
|
|
28
|
+
# 依赖已在 package.json 里声明(@linxin666/dsh-client-ui-skin-center),
|
|
29
|
+
# 所以用户装本插件就自动带上,不需要单独安装。
|
|
30
|
+
#
|
|
31
|
+
# ⚠️ 如果另一个 bundle 也挂了同一个包(典型:@linxin666/dsh-web-all 的
|
|
32
|
+
# `web-ui-skin-center` 行),就会**重复挂载**。此时请二选一:
|
|
33
|
+
# · 保留本行,把 dsh-web-all 里的 web-ui-skin-center 关掉;或
|
|
34
|
+
# · 把本行标成 `disabled: true`
|
|
35
|
+
# 本插件会在「皮肤包」页签顶部把这个冲突**显式报出来**,不会静默。
|
|
36
|
+
- insert:
|
|
37
|
+
- id: folia-skin-center
|
|
38
|
+
name: '@linxin666/dsh-client-ui-skin-center'
|
package/lib/client.js
CHANGED
|
@@ -16629,6 +16629,8 @@ window.__ModuleLoader__.load({
|
|
|
16629
16629
|
const [harnessFound, setHarnessFound] = React.useState(true);
|
|
16630
16630
|
// 皮肤中心是否在台:决定"应用"这一步交给谁(见文件头那段分工说明)
|
|
16631
16631
|
const [skinCenter, setSkinCenter] = React.useState(false);
|
|
16632
|
+
// 谁提供了皮肤中心行(用于检测重复挂载,见下方警示块)
|
|
16633
|
+
const [providers, setProviders] = React.useState([]);
|
|
16632
16634
|
const [busy, setBusy] = React.useState(""); // 正在安装 / 激活的那个 id
|
|
16633
16635
|
const [note, setNote] = React.useState(null); // 一次性提示(成功 / 失败原因)
|
|
16634
16636
|
const [q, setQ] = React.useState("");
|
|
@@ -16648,6 +16650,7 @@ window.__ModuleLoader__.load({
|
|
|
16648
16650
|
setError((r && r.error) || (resp && resp.error) || null);
|
|
16649
16651
|
setHarnessFound(!r || r.harnessFound !== false);
|
|
16650
16652
|
setSkinCenter(Boolean(r && r.skinCenter));
|
|
16653
|
+
setProviders(Array.isArray(r && r.skinCenterProviders) ? r.skinCenterProviders : []);
|
|
16651
16654
|
} catch (e) {
|
|
16652
16655
|
setError("network");
|
|
16653
16656
|
setList([]);
|
|
@@ -16784,6 +16787,23 @@ window.__ModuleLoader__.load({
|
|
|
16784
16787
|
}, loading ? weT("加载中…") : weT("刷新")),
|
|
16785
16788
|
);
|
|
16786
16789
|
|
|
16790
|
+
// ── 重复挂载警示(内嵌皮肤中心的副作用)────────────────────────────────────
|
|
16791
|
+
// 我们的 patch 加了一行 folia-skin-center;如果用户还装着 dsh-web-all,它那行
|
|
16792
|
+
// web-ui-skin-center 指向同一个包 ⇒ 同一个插件挂两次。DSH 不拦这种事,所以必须
|
|
16793
|
+
// 在界面上说清楚"去关掉一处",而不是让用户去猜为什么皮肤行为怪。
|
|
16794
|
+
if (providers.length > 1) {
|
|
16795
|
+
children.push(React.createElement("div", {
|
|
16796
|
+
key: "dup",
|
|
16797
|
+
className: "we-picker__hint",
|
|
16798
|
+
style: {
|
|
16799
|
+
margin: "4px 0 10px", padding: "7px 10px", borderRadius: "8px",
|
|
16800
|
+
background: "rgba(255,120,120,0.14)", color: "#ff9a9a", lineHeight: 1.5,
|
|
16801
|
+
},
|
|
16802
|
+
}, weT("⚠️ 检测到 ") + providers.length + weT(" 处挂载了皮肤中心(")
|
|
16803
|
+
+ providers.map((p) => p.bundle).join(" / ")
|
|
16804
|
+
+ weT(")。请只保留一处:把 dsh-web-all 里的皮肤中心行关掉,或在插件管理里停用其一,否则会重复挂载。")));
|
|
16805
|
+
}
|
|
16806
|
+
|
|
16787
16807
|
// 分工提示:皮肤中心在台 ⇒ 我们只做"选",应用由它的设置页完成(原生路径,完整)。
|
|
16788
16808
|
// 不在台 ⇒ 明说我们在兜底,避免用户以为"点了却坏了"。
|
|
16789
16809
|
if (list.length > 0) {
|
package/lib/index.js
CHANGED
|
@@ -94,7 +94,7 @@ import { registerPropsRoutes } from './routes/props.js';
|
|
|
94
94
|
import { registerLiveFrameRoutes } from './routes/live-frame.js';
|
|
95
95
|
import { registerSettingsRoutes } from './routes/settings.js';
|
|
96
96
|
import { registerCacheDirRoutes } from './routes/cache-dir.js';
|
|
97
|
-
import { registerSkinRoutes } from './routes/skins.js';
|
|
97
|
+
import { registerSkinRoutes, harnessRoot as foliaHarnessRoot } from './routes/skins.js';
|
|
98
98
|
// C8′/C6 出户的组件行(P2-1 / P2-2):组件入口**静态** import(不是动态)—— `test/verify-reachability.mjs`
|
|
99
99
|
// 只从 ENTRY 沿 import 边走,动态加载的组件入口会被判定为不可达,棘轮当场变红。
|
|
100
100
|
// 组件名 → 实现表的登记在 `applyComponent` **函数体内**(P2-1b 起;模块级常量会让门面求值期
|
|
@@ -504,6 +504,13 @@ export function apply(ctx) {
|
|
|
504
504
|
disposers, base: BASE, log,
|
|
505
505
|
});
|
|
506
506
|
|
|
507
|
+
// 皮肤中心自动挂载(可选,默认关闭)。它是标准 cordis 插件(name / inject / apply),
|
|
508
|
+
// 所以能被动态挂上 —— 用户不必再装 @linxin666/dsh-web-all 才有皮肤渲染能力。
|
|
509
|
+
// 默认关闭的原因:DSH 对"同一插件挂两次"没有保护,我们踩过(重复行 → 安全模式)。
|
|
510
|
+
try { maybeMountSkinCenter(ctx, log); } catch (err) {
|
|
511
|
+
try { log('[folia] 皮肤中心自动挂载失败(忽略):' + (err && err.message ? err.message : err)); } catch { /* ignore */ }
|
|
512
|
+
}
|
|
513
|
+
|
|
507
514
|
// fiber disposer 的语义(先逐个 disposer、再 releaseKernelLease(hostKernel)——内核引用计数
|
|
508
515
|
// 归零才 `transcodeKit.dispose()`——再 destroy 在途流、清 activeStreams / mediaMap)
|
|
509
516
|
// 逐字搬进 lib/kernel/host-session.js 的 `dispose()`。
|
|
@@ -587,6 +594,72 @@ function componentProbe() {
|
|
|
587
594
|
* —— 那条纪律写在组件入口文件头,并由 `test/verify-bundle-rows.mjs` 的判据钉住;彻底解耦(拆环)
|
|
588
595
|
* 留给 P2-2b。
|
|
589
596
|
*/
|
|
597
|
+
/**
|
|
598
|
+
* 是否已经有别的 bundle 把皮肤中心挂上了(默认假设"有",避免重复挂载)。
|
|
599
|
+
*
|
|
600
|
+
* 判据落在磁盘上的 patch 行:从 harness 根出发,扫每个 profile 的 package.json
|
|
601
|
+
* dsh.profile.bundles,把每个 bundle 包的 cordis.patch.yml 读出来,看有没有行指向
|
|
602
|
+
* @linxin666/dsh-client-ui-skin-center。有 ⇒ 别人挂了,我们不插手。
|
|
603
|
+
* 读不到 / 结构不认识 ⇒ 同样按"已挂载"处理(宁可少挂一次,也不能挂两次)。
|
|
604
|
+
*/
|
|
605
|
+
function skinCenterPatchedElsewhere(harnessRoot) {
|
|
606
|
+
try {
|
|
607
|
+
const { readdirSync, readFileSync, existsSync } = require('node:fs');
|
|
608
|
+
const { join } = require('node:path');
|
|
609
|
+
const profilesDir = join(harnessRoot, 'profiles');
|
|
610
|
+
if (!existsSync(profilesDir)) return true;
|
|
611
|
+
const SKIN_CENTER = '@linxin666/dsh-client-ui-skin-center';
|
|
612
|
+
for (const name of readdirSync(profilesDir)) {
|
|
613
|
+
if (name.startsWith('.')) continue;
|
|
614
|
+
const pkgPath = join(profilesDir, name, 'package.json');
|
|
615
|
+
if (!existsSync(pkgPath)) continue;
|
|
616
|
+
let prof;
|
|
617
|
+
try { prof = JSON.parse(readFileSync(pkgPath, 'utf8')); } catch { continue; }
|
|
618
|
+
const bundles = (prof && prof.dsh && prof.dsh.profile && prof.dsh.profile.bundles) || [];
|
|
619
|
+
for (const b of bundles) {
|
|
620
|
+
const patchPath = join(profilesDir, name, 'node_modules', b, 'cordis.patch.yml');
|
|
621
|
+
if (!existsSync(patchPath)) continue;
|
|
622
|
+
let text = '';
|
|
623
|
+
try { text = readFileSync(patchPath, 'utf8'); } catch { continue; }
|
|
624
|
+
if (text.includes(SKIN_CENTER)) return true;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return false;
|
|
628
|
+
} catch {
|
|
629
|
+
return true;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* 按需动态挂载皮肤中心。默认关闭,用 DSH_FOLIA_MOUNT_SKIN_CENTER=1 开启。
|
|
635
|
+
* 开启后仍先查"别人挂了吗",已挂则跳过 —— 重复挂载是能让 DSH 起不来的事故。
|
|
636
|
+
*/
|
|
637
|
+
function maybeMountSkinCenter(ctx, log) {
|
|
638
|
+
const flag = String(process.env.DSH_FOLIA_MOUNT_SKIN_CENTER || '').trim().toLowerCase();
|
|
639
|
+
if (flag !== '1' && flag !== 'on' && flag !== 'true') return;
|
|
640
|
+
|
|
641
|
+
const harness = (() => { try { return foliaHarnessRoot(); } catch { return null; } })();
|
|
642
|
+
if (!harness) {
|
|
643
|
+
try { log('[folia] 皮肤中心自动挂载跳过:找不到 harness 根目录'); } catch { /* ignore */ }
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (skinCenterPatchedElsewhere(harness)) {
|
|
647
|
+
try { log('[folia] 皮肤中心已由其它 bundle 挂载,跳过自动挂载'); } catch { /* ignore */ }
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
import('@linxin666/dsh-client-ui-skin-center').then((mod) => {
|
|
651
|
+
try {
|
|
652
|
+
if (!mod || typeof mod.apply !== 'function') { log('[folia] 皮肤中心模块形态不对,跳过'); return; }
|
|
653
|
+
ctx.plugin(mod);
|
|
654
|
+
log('[folia] 已自动挂载皮肤中心(DSH_FOLIA_MOUNT_SKIN_CENTER=1)');
|
|
655
|
+
} catch (err) {
|
|
656
|
+
try { log('[folia] 自动挂载皮肤中心失败:' + (err && err.message ? err.message : err)); } catch { /* ignore */ }
|
|
657
|
+
}
|
|
658
|
+
}).catch((err) => {
|
|
659
|
+
try { log('[folia] 找不到皮肤中心(可选依赖),跳过:' + (err && err.message ? err.message : err)); } catch { /* ignore */ }
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
|
|
590
663
|
export function applyComponent(root, rawConfig, component) {
|
|
591
664
|
const impls = componentImpls();
|
|
592
665
|
const impl = impls.get(component);
|
package/lib/routes/skins.js
CHANGED
|
@@ -114,6 +114,47 @@ export function harnessRoot() {
|
|
|
114
114
|
|
|
115
115
|
/* ── 索引 ────────────────────────────────────────────────────────────────── */
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* 列出**所有**提供了皮肤中心行的 bundle(跨 profile 扫 patch 文件)。
|
|
119
|
+
*
|
|
120
|
+
* 为什么必须报出来:我们在自己的 patch 里加了一行内嵌皮肤中心(folia-skin-center)。
|
|
121
|
+
* 如果用户同时还装着 @linxin666/dsh-web-all,它的 patch 里也有一行(web-ui-skin-center)
|
|
122
|
+
* 指向同一个包 ⇒ 同一个插件被挂两次。这种事要显式告诉用户去关掉一处,不能静默。
|
|
123
|
+
*/
|
|
124
|
+
function skinCenterProviders() {
|
|
125
|
+
const out = [];
|
|
126
|
+
try {
|
|
127
|
+
const harness = harnessRoot();
|
|
128
|
+
if (!harness) return out;
|
|
129
|
+
const profilesDir = join(harness, 'profiles');
|
|
130
|
+
if (!existsSync(profilesDir)) return out;
|
|
131
|
+
const SKIN_CENTER = '@linxin666/dsh-client-ui-skin-center';
|
|
132
|
+
for (const prof of readdirSync(profilesDir)) {
|
|
133
|
+
if (prof.startsWith('.')) continue;
|
|
134
|
+
const pkgPath = join(profilesDir, prof, 'package.json');
|
|
135
|
+
if (!existsSync(pkgPath)) continue;
|
|
136
|
+
let doc;
|
|
137
|
+
try { doc = JSON.parse(readFileSync(pkgPath, 'utf8')); } catch { continue; }
|
|
138
|
+
const bundles = (doc && doc.dsh && doc.dsh.profile && doc.dsh.profile.bundles) || [];
|
|
139
|
+
for (const b of bundles) {
|
|
140
|
+
const patchPath = join(profilesDir, prof, 'node_modules', b, 'cordis.patch.yml');
|
|
141
|
+
if (!existsSync(patchPath)) continue;
|
|
142
|
+
let text;
|
|
143
|
+
try { text = readFileSync(patchPath, 'utf8'); } catch { continue; }
|
|
144
|
+
if (!text.includes(SKIN_CENTER)) continue;
|
|
145
|
+
const ids = [];
|
|
146
|
+
const re = /-\s*id:\s*([A-Za-z0-9_-]+)\s*\n\s*name:\s*'([^']+)'/g;
|
|
147
|
+
let m;
|
|
148
|
+
while ((m = re.exec(text)) !== null) {
|
|
149
|
+
if (m[2].includes('dsh-client-ui-skin-center')) ids.push(m[1]);
|
|
150
|
+
}
|
|
151
|
+
if (ids.length) out.push({ profile: prof, bundle: b, rows: ids });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} catch { /* 扫描失败只是少一条提示,不影响功能 */ }
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
|
|
117
158
|
/**
|
|
118
159
|
* 拉站点索引并**精简**成客户端要的形状。永不抛;失败返回 `{ items: [], error }`。
|
|
119
160
|
*
|
|
@@ -371,6 +412,7 @@ export function registerSkinRoutes(webServer, c) {
|
|
|
371
412
|
site: skinsSiteBase(),
|
|
372
413
|
harness,
|
|
373
414
|
harnessFound: Boolean(harness),
|
|
415
|
+
skinCenterProviders: skinCenterProviders(),
|
|
374
416
|
skinCenter: await skinCenterMounted(
|
|
375
417
|
'http://' + ((req && req.headers && req.headers.host) || '127.0.0.1'),
|
|
376
418
|
(() => {
|