@nsnanocat/preference-panes 1.0.0 → 1.1.1

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/src/index.d.ts CHANGED
@@ -268,25 +268,3 @@ export interface BoxJSSubscription extends BoxJSMetadata {
268
268
  * The sole data configuration input.
269
269
  */
270
270
  export type BoxJSInput = BoxJSSetting[] | BoxJSApp | BoxJSSubscription;
271
- /**
272
- * 模块 API 返回的原始 BoxJS 与当前值模型。
273
- * Raw BoxJS and current-value model returned by the module API.
274
- */
275
- export interface ModuleModel {
276
- /** 模块路径段 / Module path segment. */
277
- module: string;
278
- /** API 获取的原始 BoxJS JSON / Raw BoxJS JSON fetched by the API. */
279
- boxjs: BoxJSInput;
280
- /** API 读取到的原始已保存字段值 / Raw persisted field values read by the API. */
281
- values: Record<string, JsonValue>;
282
- /** 后续 API 动作使用的 BoxJS JSON 地址 / BoxJS JSON URL used by later API actions. */
283
- configURL: string;
284
- }
285
- /**
286
- * 生成模块前端文件,不复制配置、不生成绑定模块的代理脚本。
287
- * Build module frontend files without copying configuration or producing bound proxy scripts.
288
- * @param boxjs 恰好包含一个模块的 BoxJS JSON / BoxJS JSON describing exactly one module.
289
- * @param css 可选 CSS 正文 / Optional CSS text.
290
- * @returns 相对路径到文件内容的映射 / Relative paths mapped to file contents.
291
- */
292
- export function build(boxjs: BoxJSInput, css?: string): Promise<Record<string, string>>;
package/src/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
- * 仅接收 BoxJS JSON 与可选 CSS 的构建入口。
3
- * Build entry accepting only BoxJS JSON and optional CSS.
2
+ * PreferencePanes 公共类型根入口;浏览器运行时由子路径导出。
3
+ * PreferencePanes public type root; browser runtimes are exported from subpaths.
4
4
  * @module @nsnanocat/preference-panes
5
5
  */
6
- export { build } from "./build.mjs";
6
+ export {};
package/src/web.mjs CHANGED
@@ -2,7 +2,6 @@ import { URL } from "@nsnanocat/url";
2
2
  import { $app } from "@nsnanocat/util/lib/app.mjs";
3
3
  import { done } from "@nsnanocat/util/lib/done.mjs";
4
4
  import assets from "#assets";
5
- import { pageInputs } from "./lib/page-inputs.mjs";
6
5
 
7
6
  /**
8
7
  * 返回模块页面及其公共浏览器资源,不处理 API、网络或持久化。
@@ -16,10 +15,7 @@ function run() {
16
15
  const url = new URL(request.url);
17
16
  if (/^\/settings\/[a-zA-Z0-9_-]+\/?$/.test(url.pathname)) {
18
17
  if (!["GET", "HEAD"].includes(request.method)) result = response(request, 405, { error: "Method not allowed" });
19
- else {
20
- const inputs = encodeURIComponent(JSON.stringify(pageInputs(url, request.headers)));
21
- result = response(request, 200, assets.page.body.replace("</head>", `<meta name="preference-panes-inputs" content="${inputs}"></head>`), "text/html");
22
- }
18
+ else result = response(request, 200, assets.page.body, "text/html");
23
19
  } else {
24
20
  const asset = assets[url.pathname];
25
21
  if (asset) result = ["GET", "HEAD"].includes(request.method) ? response(request, 200, asset.body, asset.type) : response(request, 405, { error: "Method not allowed" });
@@ -1,49 +0,0 @@
1
- import { pageInputs } from "../lib/page-inputs.mjs";
2
- import { statusView } from "./components.mjs";
3
- import { mount } from "./index.mjs";
4
- import { installDefaultStyles } from "./styles.mjs";
5
-
6
- installDefaultStyles(document);
7
- let view;
8
- /**
9
- * 从 URL 或代理传递的 Header 导入 JSON/CSS,支持独立文档与 srcdoc。
10
- * Import JSON/CSS from the URL or proxy-carried headers in standalone and srcdoc documents.
11
- * @returns {Promise<void>} 启动完成 / Startup completion.
12
- */
13
- async function start() {
14
- try {
15
- view?.destroy();
16
- view = undefined;
17
- document.querySelector("#preferences").replaceChildren(statusView("读取设置…"));
18
- const context = document.querySelector('meta[name="preference-panes-inputs"]');
19
- const embedded = window.frameElement?.dataset.preferencePanes;
20
- let inputs;
21
- switch (true) {
22
- case embedded !== undefined:
23
- inputs = JSON.parse(embedded);
24
- document.documentElement.dataset.preferencePanesEmbedded = "";
25
- break;
26
- case context !== null:
27
- inputs = JSON.parse(decodeURIComponent(context.content));
28
- break;
29
- default:
30
- inputs = pageInputs(new URL(location.href));
31
- }
32
- const apiURL = new URL(`/api/${encodeURIComponent(inputs.module)}`, inputs.url).href;
33
- const resources = [inputs.css].map(source => {
34
- if (!source) return null;
35
- const url = new URL(source, inputs.url);
36
- if (!["http:", "https:"].includes(url.protocol)) throw new TypeError("Resources must use HTTP(S) URLs");
37
- return url.href;
38
- });
39
- const [style, modelResponse] = await Promise.all([...resources.map(url => (url ? fetch(url, { cache: "no-store", credentials: "omit" }) : null)), fetch(apiURL, { cache: "no-store", credentials: "omit", headers: { Accept: "application/json", "X-PreferencePanes-JSON": inputs.json } })]);
40
- if ((style && style.status !== 200) || modelResponse.status !== 200) throw new Error(`HTTP ${modelResponse.status !== 200 ? modelResponse.status : style.status}`);
41
- view = mount(await modelResponse.json(), style ? await style.text() : "");
42
- } catch (error) {
43
- document.querySelector("#preferences").replaceChildren(statusView(`加载失败:${error.message}`, start));
44
- }
45
- }
46
- start();
47
- window.addEventListener("pageshow", event => {
48
- if (event.persisted) start();
49
- });
package/src/build.mjs DELETED
@@ -1,20 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { normalizeBoxJs } from "./browser/boxjs.mjs";
3
-
4
- /**
5
- * 仅生成模块前端文件,不复制配置或生成绑定业务的读写脚本。
6
- * Build module frontend files without copying configuration or generating bound storage scripts.
7
- * @param {unknown} boxjs 仅包含一个模块的 BoxJS JSON / BoxJS JSON containing exactly one module.
8
- * @param {string} [css] 可选自定义 CSS 正文 / Optional custom CSS text.
9
- * @returns {Promise<Record<string, string>>} 相对路径到文件正文的映射 / Relative file paths mapped to file contents.
10
- */
11
- export async function build(boxjs, css = "") {
12
- if (typeof css !== "string") throw new TypeError("CSS must be a string");
13
- const module = normalizeBoxJs(boxjs).module;
14
- const [html, app] = await Promise.all([readFile(new URL("../dist/module/index.html", import.meta.url), "utf8"), readFile(new URL("../dist/module/app.mjs", import.meta.url), "utf8")]);
15
- return {
16
- [`settings/${module}/index.html`]: html,
17
- "settings/assets/app.mjs": app,
18
- [`settings/assets/${module}.css`]: css,
19
- };
20
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * 统一解析模块页的资源地址:Header 优先于查询参数,再使用模块约定。
3
- * Resolve module resource locations: headers override query parameters and module conventions.
4
- * @param {URL} url 已解析的页面请求地址 / Parsed page request URL.
5
- * @param {Record<string, string | undefined>} [headers] 请求头,名称不区分大小写 / Case-insensitive request headers.
6
- * @returns {{url: string, module: string, json: string, css: string}} 页面上下文与两个资源输入 / Page context and two resource inputs.
7
- */
8
- export function pageInputs(url, headers = {}) {
9
- const match = /^\/settings\/([a-zA-Z0-9_-]+)\/?$/.exec(url.pathname);
10
- if (!match) throw new TypeError("Open a concrete module URL");
11
- const module = match[1];
12
- const values = Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]));
13
- const json = values["x-preferencepanes-json"] ?? url.searchParams.get("json") ?? `/configs/${module}`;
14
- const css = values["x-preferencepanes-css"] ?? url.searchParams.get("css") ?? "";
15
- if (!json.trim()) throw new TypeError("JSON resource URL is required");
16
- return { url: url.href, module, json, css };
17
- }