@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 +24 -16
- package/dist/api.js +1454 -967
- package/dist/module/index.html +1 -1
- package/dist/module/index.mjs +1519 -0
- package/dist/module/navigation.mjs +7 -6
- package/dist/preference-panes.mjs +861 -849
- package/dist/web.js +1202 -0
- package/package.json +1 -1
- package/src/api.mjs +191 -0
- package/src/browser/ModuleStatus.mjs +7 -6
- package/src/browser/Navigation.d.mts +8 -6
- package/src/{lib → browser}/boxjs.mjs +72 -16
- package/src/browser/client.d.mts +43 -133
- package/src/browser/client.mjs +146 -186
- package/src/browser/index.d.ts +21 -10
- package/src/browser/index.mjs +95 -72
- package/src/browser/module.html +1 -1
- package/src/browser/mount.mjs +119 -0
- package/src/browser/panel.mjs +470 -441
- package/src/build.mjs +4 -5
- package/src/index.d.ts +16 -2
- package/src/web.mjs +52 -0
- package/dist/module/app.mjs +0 -1461
- package/src/BoxJS.mjs +0 -72
- package/src/Store.mjs +0 -114
- package/src/browser/app.mjs +0 -51
- package/src/lib/response.mjs +0 -16
- package/src/proxy/handler.mjs +0 -39
- package/src/proxy/response.mjs +0 -16
package/src/build.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
-
import {
|
|
2
|
+
import { normalizeBoxJs } from "./browser/boxjs.mjs";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* 仅生成模块前端文件,不复制配置或生成绑定业务的读写脚本。
|
|
@@ -10,12 +10,11 @@ import { BoxJS } from "./BoxJS.mjs";
|
|
|
10
10
|
*/
|
|
11
11
|
export async function build(boxjs, css = "") {
|
|
12
12
|
if (typeof css !== "string") throw new TypeError("CSS must be a string");
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
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")]);
|
|
13
|
+
const module = normalizeBoxJs(boxjs).module;
|
|
14
|
+
const [html, index] = await Promise.all([readFile(new URL("../dist/module/index.html", import.meta.url), "utf8"), readFile(new URL("../dist/module/index.mjs", import.meta.url), "utf8")]);
|
|
16
15
|
return {
|
|
17
16
|
[`settings/${module}/index.html`]: html,
|
|
18
|
-
"settings/assets/
|
|
17
|
+
"settings/assets/index.mjs": index,
|
|
19
18
|
[`settings/assets/${module}.css`]: css,
|
|
20
19
|
};
|
|
21
20
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -92,8 +92,8 @@ export interface SettingsRequest {
|
|
|
92
92
|
*/
|
|
93
93
|
headers?: Record<string, string | undefined>;
|
|
94
94
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
95
|
+
* 模块动作的 JSON 正文
|
|
96
|
+
* JSON body for a module action.
|
|
97
97
|
*/
|
|
98
98
|
body?: string;
|
|
99
99
|
}
|
|
@@ -268,6 +268,20 @@ 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
|
+
}
|
|
271
285
|
/**
|
|
272
286
|
* 生成模块前端文件,不复制配置、不生成绑定模块的代理脚本。
|
|
273
287
|
* Build module frontend files without copying configuration or producing bound proxy scripts.
|
package/src/web.mjs
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { URL } from "@nsnanocat/url";
|
|
2
|
+
import { $app } from "@nsnanocat/util/lib/app.mjs";
|
|
3
|
+
import { done } from "@nsnanocat/util/lib/done.mjs";
|
|
4
|
+
import assets from "#assets";
|
|
5
|
+
import { pageInputs } from "./lib/page-inputs.mjs";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 返回模块页面及其公共浏览器资源,不处理 API、网络或持久化。
|
|
9
|
+
* Serve module pages and common browser assets without handling APIs, network access or persistence.
|
|
10
|
+
* @returns {void} 响应已交给代理宿主 / Response delivered to the proxy host.
|
|
11
|
+
*/
|
|
12
|
+
function run() {
|
|
13
|
+
const request = globalThis.$request;
|
|
14
|
+
let result;
|
|
15
|
+
try {
|
|
16
|
+
const url = new URL(request.url);
|
|
17
|
+
if (/^\/settings\/[a-zA-Z0-9_-]+\/?$/.test(url.pathname)) {
|
|
18
|
+
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
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
const asset = assets[url.pathname];
|
|
25
|
+
if (asset) result = ["GET", "HEAD"].includes(request.method) ? response(request, 200, asset.body, asset.type) : response(request, 405, { error: "Method not allowed" });
|
|
26
|
+
}
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(`PreferencePanes Web: ${error.message}`);
|
|
29
|
+
result = response(request, 500, { error: error.message });
|
|
30
|
+
}
|
|
31
|
+
if (!result) done({});
|
|
32
|
+
else done($app === "Quantumult X" ? result : { response: result });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 构造静态资源响应,HEAD 请求不返回正文。
|
|
37
|
+
* Build a static resource response without a body for HEAD requests.
|
|
38
|
+
* @param {import("./index.js").SettingsRequest} request 代理请求 / Proxy request.
|
|
39
|
+
* @param {number} status HTTP 状态 / HTTP status.
|
|
40
|
+
* @param {unknown} body 响应正文 / Response body.
|
|
41
|
+
* @param {string} [type] 媒体类型 / Media type.
|
|
42
|
+
* @returns {import("./index.js").SettingsResponse} 静态资源响应 / Static resource response.
|
|
43
|
+
*/
|
|
44
|
+
function response(request, status, body, type = "application/json") {
|
|
45
|
+
return {
|
|
46
|
+
status,
|
|
47
|
+
headers: { "Content-Type": `${type}; charset=utf-8`, "Cache-Control": "no-store", "X-Content-Type-Options": "nosniff" },
|
|
48
|
+
body: request.method === "HEAD" ? "" : type === "application/json" ? JSON.stringify(body) : body,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
run();
|