dsh-folia 4.6.0 → 4.8.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/lib/index.js CHANGED
@@ -77,11 +77,7 @@ import { assertSubpackagesResolvable, assertSubpackagesResolvableInHost, httpVie
77
77
  // `extOf` 反向传给会话段(清单载荷的容器后缀判据 ⇒ 见该文件头)。
78
78
  import { createHostSession } from './kernel/host-session.js';
79
79
  export { extOf };
80
- import { registerInventoryRoutes, warmInventorySiteCache } from './routes/inventory.js';
81
- import { registerModulesRoutes, warmModulesCache } from './routes/modules.js';
82
- import { registerBootRoutes } from './routes/boot.js';
83
- import { registerSiteThumbRoutes } from './routes/site-thumb.js';
84
- import { registerPetsRoutes } from './routes/pets.js';
80
+ import { registerFeatureRoutes, warmFeatureCaches } from './route-registry.js';
85
81
  import { installBootInjection } from './boot/index.js';
86
82
  import { registerDiagRoutes } from './routes/diag.js';
87
83
  // 遮挡消息桥族(上游新增域模块):hub 处理 x11 遮挡探针,路由对外暴露状态/控制面。
@@ -291,30 +287,17 @@ export function apply(ctx) {
291
287
  }
292
288
  }
293
289
 
294
- // 1. Inventory JSON → lib/routes/inventory.js(路径/头/状态码/错误文案逐字未变)。
295
- // `componentsProbe` 是**只读**行状态面(与 3c-6 的 /diag-log 同一个探针、同一批账):
296
- // 浏览器半边按它在 `/inventory` 里的 `components` 字段决定"该组件的界面渲不渲染"
297
- // (ADR-0013 D3 的状态面;形状与失效口径写在那个族的文件头)。
298
- registerInventoryRoutes(webServer, {
299
- disposers, base: BASE, mediaOriginApi, buildInventory, componentsProbe: componentProbe,
290
+ // 1. 功能族路由:**注册表驱动**(lib/route-registry.js)。
291
+ // 装配点不再逐个点名 —— 加一个功能只改注册表,这里永远是同一次调用。
292
+ // 已迁移:inventory / modules / boot / site-thumb / pets;
293
+ // 未迁移的族列在 INLINE_ROUTE_FAMILIES(棘轮,只许缩小),仍由下面的显式调用装载。
294
+ registerFeatureRoutes(webServer, {
295
+ disposers, base: BASE, log, mediaOriginApi, buildInventory,
296
+ componentProbe, ensureImagePreview,
300
297
  });
301
- // 数据模块索引(站点侧声明「有哪些数据模块」)→ lib/routes/modules.js。
302
- // 与 inventory 同一套站点基址;读不到就退回内置集合,绝不让面板因为索引文件而空白。
303
- registerModulesRoutes(webServer, { disposers, base: BASE });
304
-
305
- // 开机动画 → lib/routes/boot.js(HTTP 面)+ lib/boot/index.js(注入与屏幕脚本)。
306
- // 注入是「关就一行都不注」:没有选片时不产生任何脚本、不产生任何请求。
307
- registerBootRoutes(webServer, { disposers, base: BASE, log });
308
-
309
- // 站点图片缩略图代理 → lib/routes/site-thumb.js。卡片用 320px 小图,不再每张下 500 KB 原图。
310
- registerSiteThumbRoutes(webServer, { disposers, base: BASE, ensureImagePreview, log });
311
298
 
312
299
  // 启动预热(有意不阻塞):站点清单与模块索引各拉一次,让第一次打开面板不冷。
313
- // 桌宠:自渲染(不依赖第三方宠物插件)—— 站点当分发通道,我们负责安装与绘制。
314
- registerPetsRoutes(webServer, { disposers, base: BASE, log });
315
-
316
- warmInventorySiteCache();
317
- warmModulesCache();
300
+ warmFeatureCaches();
318
301
  installBootInjection(ctx, (m) => { try { log(m); } catch { /* ignore */ } });
319
302
 
320
303
  // 3./3a. 派生媒体族路由(源元信息 / 抽帧转码 + 进度 / 视频缩略图)→ lib/routes/media-derived.js。
@@ -0,0 +1,115 @@
1
+ /**
2
+ * lib/route-registry.js — **功能路由注册表**(宿主侧)。
3
+ *
4
+ * 为什么要它:`lib/index.js` 过去逐个 `registerXxxRoutes(webServer, {…})`,加一个功能就得
5
+ * 在那个 400 行装配文件里挑一处插进去,并保证依赖对象拼对。客户端已经收口成注册表
6
+ * (`src/features.js`),宿主侧对称过来,装配点就只剩一次循环。
7
+ *
8
+ * 纪律(由 `test/verify-route-registry.mjs` 机器校验):
9
+ * · 本表里写出的族**必须在** `lib/routes/` 里真实存在,且 `deps` 只从传入的上下文取键;
10
+ * · `INLINE_ROUTE_FAMILIES` 是**尚未迁移**的族(大依赖:mediaMap / hub / 转码器等),
11
+ * 它是**棘轮**:只许缩小 —— 迁一个删一个,不许往回调;
12
+ * · 两表并集必须覆盖 `lib/routes/*.js`(不许有第三处偷偷注册的族)。
13
+ *
14
+ * 迁移一个族的步骤:把 `lib/index.js` 里那段调用删掉 → 在 `FEATURE_ROUTE_FAMILIES` 加一条 →
15
+ * 从 `INLINE_ROUTE_FAMILIES` 删掉 → 跑守卫。
16
+ */
17
+
18
+ import { registerInventoryRoutes, warmInventorySiteCache } from './routes/inventory.js';
19
+ import { registerModulesRoutes, warmModulesCache } from './routes/modules.js';
20
+ import { registerBootRoutes } from './routes/boot.js';
21
+ import { registerSiteThumbRoutes } from './routes/site-thumb.js';
22
+ import { registerPetsRoutes } from './routes/pets.js';
23
+
24
+ /**
25
+ * 已迁移的功能族。
26
+ *
27
+ * `deps(c)` 只从上下文取键 —— 这样"某个族需要什么"是**声明式**的,装配点不需要知道。
28
+ * 上下文由门面按需提供(见 lib/index.js 的 `registerFeatureRoutes(webServer, { … })`)。
29
+ *
30
+ * @type {{ id: string, file: string, register: Function, deps: (c: any) => any, warm?: Function }[]}
31
+ */
32
+ export const FEATURE_ROUTE_FAMILIES = [
33
+ {
34
+ id: 'inventory',
35
+ file: 'lib/routes/inventory.js',
36
+ register: registerInventoryRoutes,
37
+ // 清单族需要"本机清单构建器 + 组件行状态探针 + 媒体源访问器":三者都是门面现算的,
38
+ // 所以只能由调用方传进来(族自己拿不到)。
39
+ deps: (c) => ({
40
+ disposers: c.disposers,
41
+ base: c.base,
42
+ mediaOriginApi: c.mediaOriginApi,
43
+ buildInventory: c.buildInventory,
44
+ componentsProbe: c.componentProbe,
45
+ }),
46
+ warm: warmInventorySiteCache,
47
+ },
48
+ {
49
+ id: 'modules',
50
+ file: 'lib/routes/modules.js',
51
+ register: registerModulesRoutes,
52
+ deps: (c) => ({ disposers: c.disposers, base: c.base }),
53
+ warm: warmModulesCache,
54
+ },
55
+ {
56
+ id: 'boot',
57
+ file: 'lib/routes/boot.js',
58
+ register: registerBootRoutes,
59
+ deps: (c) => ({ disposers: c.disposers, base: c.base, log: c.log }),
60
+ },
61
+ {
62
+ id: 'site-thumb',
63
+ file: 'lib/routes/site-thumb.js',
64
+ register: registerSiteThumbRoutes,
65
+ // 缩略图复用内核的 ffmpeg 套件(ensureImagePreview),不自己 spawn。
66
+ deps: (c) => ({ disposers: c.disposers, base: c.base, ensureImagePreview: c.ensureImagePreview, log: c.log }),
67
+ },
68
+ {
69
+ id: 'pets',
70
+ file: 'lib/routes/pets.js',
71
+ register: registerPetsRoutes,
72
+ deps: (c) => ({ disposers: c.disposers, base: c.base, log: c.log }),
73
+ },
74
+ ];
75
+
76
+ /**
77
+ * **尚未迁移**的族(棘轮:只许缩小)。
78
+ *
79
+ * 为什么留在门面里:它们的依赖是内核的活对象(mediaMap / occlusionHub / transcodeKit /
80
+ * sceneFrameSlot / uploadStoreKit …),搬进本表需要把那些对象也传进来,属于另一轮改动。
81
+ * 这张清单存在的意义是**把"还剩多少"写下来**,守卫据此防止有人往回调。
82
+ */
83
+ export const INLINE_ROUTE_FAMILIES = [
84
+ // 每条写「族 id + 门面里的注册函数名」:两者**不总同形**(presets → registerGlassPresetsRoutes),
85
+ // 靠名字猜会在守卫里制造假红。迁移一个族 = 在 FEATURE_ROUTE_FAMILIES 加一条 + 删这里一行。
86
+ { id: 'media-bytes', fn: 'registerMediaBytesRoutes' },
87
+ { id: 'media-derived', fn: 'registerMediaDerivedRoutes' },
88
+ { id: 'scene-frame', fn: 'registerSceneFrameRoutes' },
89
+ { id: 'scene-serve', fn: 'registerSceneServeRoutes' },
90
+ { id: 'scene-media', fn: 'registerSceneMediaRoutes' },
91
+ { id: 'live-frame', fn: 'registerLiveFrameRoutes' },
92
+ { id: 'props', fn: 'registerPropsRoutes' },
93
+ { id: 'occlusion', fn: 'registerOcclusionRoutes' },
94
+ { id: 'diag', fn: 'registerDiagRoutes' },
95
+ { id: 'we-assets', fn: 'registerWeAssetsRoutes' },
96
+ { id: 'upload', fn: 'registerUploadRoutes' },
97
+ { id: 'presets', fn: 'registerGlassPresetsRoutes' },
98
+ { id: 'settings', fn: 'registerSettingsRoutes' },
99
+ { id: 'cache-dir', fn: 'registerCacheDirRoutes' },
100
+ ];
101
+
102
+ /** 按注册表挂载全部已迁移族;`warm` 钩子显式调用(预热是有意不阻塞的)。 */
103
+ export function registerFeatureRoutes(webServer, ctx) {
104
+ for (const fam of FEATURE_ROUTE_FAMILIES) {
105
+ fam.register(webServer, fam.deps(ctx));
106
+ }
107
+ }
108
+
109
+ /** 启动预热(站点清单与模块索引各拉一次)。失败静默 —— 预热只是优化。 */
110
+ export function warmFeatureCaches() {
111
+ for (const fam of FEATURE_ROUTE_FAMILIES) {
112
+ if (typeof fam.warm !== 'function') continue;
113
+ try { fam.warm(); } catch { /* 预热失败不影响启动 */ }
114
+ }
115
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * lib/settings/ownership.js — **设置键归属清单**(每个键属于哪个功能)。
3
+ *
4
+ * 为什么要有它:`lib/settings-schema.js` 有 138 个 DEFAULTS 键 / 134 个 KINDS 键,过去"这个键
5
+ * 属于哪个功能"只存在于人脑里。后果是真实出现过的:加一个功能要往那张 2000 行的表里挑地方插,
6
+ * 而删一个功能时没人敢删键(不知道还有谁在用)。
7
+ *
8
+ * 这张表把归属写成数据,由 `test/verify-settings-ownership.mjs` 机器校验三条:
9
+ * ① 每个键**恰好**有一个归属(没归属 = 有人偷偷加键;两个归属 = 归属不清);
10
+ * ② 每条模式都要**真的匹配到东西**(写错了 / 功能删了留着的模式会被判红);
11
+ * ③ 五个功能(wallpaper / playback / appearance / components / system)都非空 ——
12
+ * 防止有人把整表塞进一个兜底桶。
13
+ *
14
+ * 为什么现在只写数据、不拆文件:拆 `settings-schema.js` 要动 DEFAULTS / KINDS / 一堆
15
+ * 引用这些常量的消毒器,属于高风险改动;先把**归属**固定住,拆分才有对账依据。
16
+ * 拆分时的目标形态已经写在这里:每个 `files` 条目将来对应 `lib/settings/<id>.js`。
17
+ */
18
+
19
+ /** @typedef {{ id: string, name: string, why: string, files?: string[], keys?: string[], prefixes?: string[] }} FeatureKeys */
20
+
21
+ /** @type {FeatureKeys[]} */
22
+ export const SETTINGS_OWNERS = [
23
+ {
24
+ id: 'wallpaper',
25
+ name: '壁纸',
26
+ why: '壁纸本体的显示参数:着色/裁切/图层几何/场景帧/评分与来源筛选/自定义属性。',
27
+ files: ['lib/routes/inventory.js', 'src/quick-panel.js', 'src/picker-model.js'],
28
+ keys: [
29
+ 'scrim', 'border', 'blur', 'wallpaperBlur', 'wallpaperOpacity', 'objectFit', 'flip',
30
+ 'backgroundBrightness', 'backgroundContrast', 'backgroundSaturate',
31
+ 'layerPositionX', 'layerPositionY', 'layerScale',
32
+ 'hiddenIds', 'contentRatingFilter', 'typeFilter', 'sourceFilter', 'pickerLayout',
33
+ 'sceneFrameUrl', 'sceneLive', 'sceneLiveFps', 'sceneLiveFailures',
34
+ 'customFrames', 'frameVariants', 'userProps', 'edgeCompat',
35
+ ],
36
+ },
37
+ {
38
+ id: 'playback',
39
+ name: '播放',
40
+ why: '播放与轮换的时序:轮换间隔/过场、倍速、帧率上限、声音、暂停策略。',
41
+ files: ['src/client-rotation.js', 'src/client-audio-playback.js', 'src/panel-tabs-advanced.js'],
42
+ keys: [
43
+ 'rotationEnabled', 'rotationInterval', 'rotationGroupId', 'rotationGroups', 'rotationSeeded',
44
+ 'switchTransition', 'switchTransitionDir', 'switchTransitionSpeed',
45
+ 'playbackRate', 'fpsCap', 'videoVolume', 'videoAudioEnabled',
46
+ 'pauseOnHidden', 'pauseOnBlur', 'pauseOnBattery', 'liveBootDelay',
47
+ ],
48
+ },
49
+ {
50
+ id: 'appearance',
51
+ name: '外观',
52
+ why: '玻璃 / 主题 / 字体 / 配色 / 胶囊与侧栏装饰:改的是界面自身的观感。',
53
+ files: ['src/glass.js', 'src/glass-panel.js', 'src/theme-follow.js', 'src/system-fonts.js'],
54
+ prefixes: ['glass', 'sidebar', 'titlebar', 'capsule', 'leftSidebar', 'rightSidebar', 'uiColor', 'theme', 'font', 'accent', 'chatGlass', 'extraGlass', 'rope', 'caretColor', 'globalFamily', 'componentFonts', 'noticeSeen'],
55
+ },
56
+ {
57
+ id: 'components',
58
+ name: '可选组件(fx / parallax / 头像 / 立绘)',
59
+ why: '七个组件行各自的外观参数:点击拖尾、3D 视差、自定义头像与立绘。',
60
+ files: ['lib/components/fx/index.js', 'lib/components/parallax/index.js', 'lib/components/mascot-avatar/index.js'],
61
+ prefixes: ['fx', 'parallax', 'avatar', 'mascotImage'],
62
+ },
63
+ {
64
+ id: 'system',
65
+ name: '系统',
66
+ why: '不属于任何单一功能的全局项:设置表版本、皮肤互操作标记、媒体适配目标。',
67
+ files: ['lib/kernel/config.js', 'lib/kernel/host-kernel.js'],
68
+ keys: [
69
+ 'settingsVersion', 'skinYieldRestoreId', 'skinYieldRestoreRotation',
70
+ 'adapterTarget', 'mediaIntegration', 'audioSource', 'mediaLyricsOnline',
71
+ 'thinkingGlass', 'thinkingNative',
72
+ // `id` 不是"设置"而是设置记录的标识字段(DEFAULTS 里与真实设置同形存在)。
73
+ 'id',
74
+ ],
75
+ },
76
+ ];
77
+
78
+ /**
79
+ * 「兜底键」的显式豁免:没有任何模式匹配、且确实只给系统用的少数键。
80
+ *
81
+ * ⚠️ 这张表是**棘轮**:只许缩小。往这里加一条 = 又有一个键没人负责。
82
+ */
83
+ export const UNOWNED_WHY = {
84
+ // 目前为空:所有键都能被上面的模式覆盖。
85
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-folia",
3
- "version": "4.6.0",
3
+ "version": "4.8.0",
4
4
  "description": "Folia 壁纸引擎:把本机 Wallpaper Engine 壁纸搬进 DSH 界面(场景实时渲染 / 视频 / 网页),内置液态玻璃与 Folia 吉祥物,并可从自建站点拉取壁纸。单包形态(组件已合并)。",
5
5
  "type": "module",
6
6
  "engines": {
@@ -156,7 +156,9 @@
156
156
  "README.en.md",
157
157
  "README.beginner.md",
158
158
  "lib/components/",
159
- "lib/features.js"
159
+ "lib/features.js",
160
+ "lib/route-registry.js",
161
+ "lib/settings/"
160
162
  ],
161
163
  "dsh": {
162
164
  "bundle": {
@@ -195,7 +197,8 @@
195
197
  "test:pets": "node test/pets-http.mjs",
196
198
  "test:pets-layer": "node test/pets-layer.mjs",
197
199
  "test:features": "node test/verify-features.mjs",
198
- "gate": "node scripts/build-client.mjs \u0026\u0026 node test/run-guards.mjs smoke \u0026\u0026 node test/verify-features.mjs \u0026\u0026 node test/boot-http.mjs \u0026\u0026 node test/pets-http.mjs \u0026\u0026 node test/pets-layer.mjs"
200
+ "audit": "node test/run-audit.mjs",
201
+ "gate": "node scripts/build-client.mjs \u0026\u0026 node test/run-guards.mjs smoke \u0026\u0026 node test/verify-features.mjs \u0026\u0026 node test/verify-route-registry.mjs \u0026\u0026 node test/verify-settings-ownership.mjs \u0026\u0026 node test/boot-http.mjs \u0026\u0026 node test/pets-http.mjs \u0026\u0026 node test/pets-layer.mjs"
199
202
  },
200
203
  "peerDependencies": {
201
204
  "@deepseek-ai/cordis": "^4.0.4",