@nsnanocat/preference-panes 0.9.16 → 1.1.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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @nsnanocat/preference-panes
2
2
 
3
- PreferencePanes 负责具体模块的设置页、共享网页组件和本地持久化 API。模块页面只接受 BoxJS JSON 与可选 CSS;业务模块自己发布版本对应的 JSON。项目主页及其客户端 SDK 调用属于调用方,不进入本包。
3
+ PreferencePanes 分别提供具体模块的设置前端和本地持久化 API。`web.js` 只返回模块 HTML 与公共浏览器资源,`api.js` 只处理模块数据和持久化;业务模块自己发布版本对应的 BoxJS JSON。项目主页及其客户端 SDK 调用属于调用方,不进入本包。
4
4
 
5
- ## 通用 API(0.8.0 form 契约)
5
+ ## 模块 API
6
6
 
7
7
  嵌入的模块页跟随宿主根元素的 `data-theme`(light/dark)和 `--pp-keyboard-height`(CSS 长度),退出时释放观察器。独立页面使用网页自身或系统主题;通用包不识别任何客户端 User-Agent。
8
8
 
@@ -12,31 +12,39 @@ PreferencePanes 负责具体模块的设置页、共享网页组件和本地持
12
12
 
13
13
  宿主也可监听 `notice` 事件,通过 `preventDefault()` 接管 `{kind, message}` 提示;被接管时模块不创建网页 Toast、不启用提示计时器。独立使用的通用面板仍提供默认通知。
14
14
 
15
- 业务模块安装同一个 `https://github.com/NSNanoCat/PreferencePanes/releases/latest/download/api.js`,不再生成绑定业务配置的读写脚本,也不需要额外安装独立设置插件。该文件由本仓库 Release 工作流发布,自动更新遵循代理工具的缓存周期。
15
+ 业务模块分别映射同一 Release 的两个产物:`api.js` 只匹配 `/api/{module}` 及其动作,`web.js` 只匹配 `/settings/{module}`、`/settings/assets/index.mjs` 和 `/settings/assets/navigation.mjs`。发布资源仍把 1.0.0 使用的 `/settings/assets/app.mjs` 映射到同一份 `index.mjs` 正文,兼容尚未更新的已安装模块,但不存在第二个页面入口实现。两者都不包含业务配置,也不需要额外安装独立设置插件。
16
16
 
17
- API POST /api/get、/api/set、/api/delete。form 字段名是完整 `@root.path`;读取和删除的值留空,写入值可以是普通文本或 JSON。API 不鉴权,不下载 JSON,也不校验控件和枚举。
17
+ 网页只调用模块 API:`HEAD /api/{module}` 探测模块,`GET /api/{module}` 取得原始 BoxJS 与当前已存值,`POST /api/{module}/get|set|delete` 执行持久化操作。`api.js` 负责取得 BoxJS、确认字段 ID 并把完整 `@root.path` 直接交给 util `Storage`;网页不直接请求配置 Mock,也不提交存储根。
18
18
 
19
19
  ```js
20
- await fetch("/api/set", {
20
+ await fetch("/api/Enhanced/set", {
21
21
  method: "POST",
22
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
23
- body: new URLSearchParams([["@BiliBili.Enhanced.Settings.Home.Top_left", JSON.stringify("mine")]]),
22
+ headers: {
23
+ "Content-Type": "application/json",
24
+ "X-PreferencePanes-JSON": "/configs/Enhanced",
25
+ },
26
+ body: JSON.stringify({ key: "Enhanced.Settings.Home.Top_left", value: "mine" }),
24
27
  });
25
28
  ```
26
29
 
27
- 前端统一 JSON.stringify 再做 form 编码,保留字符串、布尔值、数值、null、数组和对象的区别。API 通过 util Storage/Lodash 读取根、操作目标路径、写回一次;不会在写入后额外读取。缺失键返回 404,写入/删除成功返回 200。旧 /api/{module}/{path} 接口移除。
30
+ 模块 API 返回的 `boxjs` 保持上游原样,`values` 只含实际已存值,不补默认值或解释控件类型。Web `mount()` 独占控件、选项、默认值、展示元数据和已存值校验,再生成页面。写入成功后只更新当前页面快照,不追加读取。旧 `/api/get|set|delete` form 接口和 `/api/module/{module}` 草稿路径均移除。
28
31
 
29
32
  ## 页面与输入
30
33
 
31
34
  ```js
32
- import { mount } from "@nsnanocat/preference-panes/browser";
33
- const page = mount(boxjs, ".pp-panel { --pp-accent: #16866a; }");
35
+ import { PreferencesView } from "@nsnanocat/preference-panes/browser";
36
+ const model = await fetch("/api/Module", {
37
+ headers: { "X-PreferencePanes-JSON": "/configs/Module" },
38
+ }).then(response => response.json());
39
+ const page = new PreferencesView(model, ".pp-panel { --pp-accent: #16866a; }");
34
40
  page.destroy();
35
41
  ```
36
42
 
37
- 支持字段数组、单 app 和仅包含一个模块的 apps 订阅。控件、名称、图标和默认值从 BoxJS 解析;`@Root.Module.Settings.key` 直接给出存储根与键路径,不需要额外映射配置。省略 CSS 使用内置样式。
43
+ 浏览器生命周期依次由 `ModulePage`、`PreferencesView`、`PreferencesPanel` `PreferencesClient` 管理:页面入口读取输入并请求初始模型,视图负责 BoxJS 解析、校验、样式与主题,面板负责控件和导航,客户端只负责 API 请求与页面值快照。`mount(model, css?)` 仍作为创建 `PreferencesView` 的便捷入口。
38
44
 
39
- `/settings/{module}` 由通用 api.js 返回模块文档。页面可通过 json/css 查询参数或 X-PreferencePanes-JSON/CSS Header 指定资源 URL;默认 JSON /configs/{module},CSS 默认空。Header 分别优先。
45
+ API 支持字段数组、单 app apps 订阅,只扫描 `@Root.Module.Settings.key` 形式的字段 ID。浏览器从 API 返回的同一份 BoxJS 解析控件、名称、图标和默认值;省略 CSS 使用内置样式。
46
+
47
+ `/settings/{module}` 由独立 `web.js` 返回模块文档。页面可通过 json/css 查询参数或 X-PreferencePanes-JSON/CSS Header 指定资源 URL;默认 JSON 是 /configs/{module},CSS 默认空。Header 分别优先。`web.js` 不访问网络或存储,浏览器执行其中的 `index.mjs` 后才调用 `api.js`。
40
48
 
41
49
  ```js
42
50
  import { ModuleFrame, Navigation } from "@nsnanocat/preference-panes/navigation";
@@ -53,15 +61,15 @@ frame.destroy();
53
61
 
54
62
  ModuleFrame 在 iframe 元素上保存原请求上下文,HTML 原样加载,不从 about:srcdoc 猜模块、不注入临时 CSS。框架自身管理嵌入模式,通过事件发布标题、忙碌状态和返回能力。Navigation 统一管理 fragment 历史、滑动、滚动保留、加载取消及动画结束后释放;项目提供根页、子页工厂和布局。
55
63
 
56
- 项目主页可按需使用导出的 `probeModule`、ModuleStatus、ModuleFrame 和 Navigation,也可以自行实现入口。`probeModule(url)` 是版本检测的公共 API:它只对模块 JSON Mock 发送一次 HEAD,并原样返回浏览器 `Response`;调用方通过 `response.status` 判断 HTTP 状态,通过 `response.headers.get("X-PreferencePanes-Version")` 读取版本。ModuleStatus 仅负责把同一响应渲染到状态行。PreferencePanes 不提供主页运行脚本,不识别具体 App,不加载或调用任何客户端 Bridge SDK。调用方若运行在原生 WebView,应在自己的 HTML/页面脚本中直接接入该客户端的官方 SDK,再把 ModuleFrame 事件映射到原生界面。
64
+ 项目主页可按需使用导出的 `probeModule`、ModuleStatus、ModuleFrame 和 Navigation,也可以自行实现入口。`probeModule("/api/Module", { json: "/configs/Module" })` 只对模块 API 发送一次 HEAD,并原样返回浏览器 `Response`;代理 API 负责探测 BoxJS 上游并透传状态和 `X-PreferencePanes-Version`。ModuleStatus 仅负责把同一响应渲染到状态行。PreferencePanes 不提供主页运行脚本,不识别具体 App,不加载或调用任何客户端 Bridge SDK。调用方若运行在原生 WebView,应在自己的 HTML/页面脚本中直接接入该客户端的官方 SDK,再把 ModuleFrame 事件映射到原生界面。
57
65
 
58
- 每次进入模块读取 JSON/CSS 和设置一次。二级多选返回复用内存缓存,修改立即写入;成功提示、失败回滚由公共组件处理。Caches 按需查看/清空,重置只删除指定模块子树。
66
+ 每次进入模块通过 API 取得 JSON 和设置一次,同时读取可选 CSS。二级多选返回复用内存缓存,修改经 Web 校验后提交 API;成功提示、失败回滚由公共组件处理。Caches 按需通过 API 查看/清空,重置只删除指定模块子树。
59
67
 
60
- 标题栏只显示文字;嵌入模式隐藏模块自身标题栏,由宿主显示原生标题或自己的导航。模块数据操作位于标题栏右侧三点菜单,页面不再平铺维护按钮。`ActionMenu` 是共用的底部操作菜单:独立网页由其三点按钮打开;网页宿主或只有原生按钮、没有原生菜单的 WebView 宿主,将 `frame.state.actions` 传给 `menu.update(actions, busy)`,在宿主按钮点击时调用 `menu.open()`,选择后调用 `frame.perform(id)`。查看设置和缓存都会通过 `POST /api/get` 按需读取最新子树,再进入可返回的 JSON 详情子页;返回详情页不会触发额外读取,清空和重置设置仍要求确认。菜单组件提供遮罩、取消按钮、外部点击、Escape 与方向键操作,弹层挂载在文档根部,不依赖模块标题栏是否显示;宿主不访问 iframe 内部 DOM。
68
+ 标题栏只显示文字;嵌入模式隐藏模块自身标题栏,由宿主显示原生标题或自己的导航。模块数据操作位于标题栏右侧三点菜单,页面不再平铺维护按钮。`ActionMenu` 是共用的底部操作菜单:独立网页由其三点按钮打开;网页宿主或只有原生按钮、没有原生菜单的 WebView 宿主,将 `frame.state.actions` 传给 `menu.update(actions, busy)`,在宿主按钮点击时调用 `menu.open()`,选择后调用 `frame.perform(id)`。查看设置和缓存都会通过 `POST /api/{module}/get` 按需读取最新子树,再进入可返回的 JSON 详情子页;返回详情页不会触发额外读取,清空和重置设置通过 `/delete` 且仍要求确认。菜单组件提供遮罩、取消按钮、外部点击、Escape 与方向键操作,弹层挂载在文档根部,不依赖模块标题栏是否显示;宿主不访问 iframe 内部 DOM。
61
69
 
62
70
  ## 构建与验证
63
71
 
64
- `npm run build` 生成无业务配置的 dist/api.js 和公共前端;Release 工作流只上传包含页面与运行资源的 api.js。`build(boxjs, css?)` 仅输出 `settings/{module}/index.html`、公共 `settings/assets/app.mjs` 和可选模块 CSS,不复制配置、导航组件或重复 HTML。
72
+ `npm run build` 生成无业务配置的 `dist/api.js`、`dist/web.js` 和公共前端模块;Release 工作流分别上传后端 API 与前端响应脚本。`build(boxjs, css?)` 仅输出 `settings/{module}/index.html`、公共 `settings/assets/index.mjs` 和可选模块 CSS,不复制配置、导航组件或重复 HTML。
65
73
 
66
74
  `npm run preview` 提供文件导入测试台,上传 JSON/CSS 后在隔离 iframe 预览;测试存储只在内存中。`npm run check` 检查代码、类型、行为;`npm run apifox:generate` 和 `npm run apifox:check` 维护原生接口文档。
67
75