@nsnanocat/preference-panes 1.2.3 → 1.2.5

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/web.mjs DELETED
@@ -1,88 +0,0 @@
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
-
6
- /**
7
- * 按标准 URL 语义解析样式地址,并限制为 HTTP(S)。
8
- * Resolve a stylesheet reference with standard URL semantics and require HTTP(S).
9
- * @param {string} source 样式地址 / Stylesheet reference.
10
- * @param {URL} base 模块页面地址 / Module page URL.
11
- * @returns {URL} 绝对样式地址 / Absolute stylesheet URL.
12
- */
13
- function stylesheetURL(source, base) {
14
- const scheme = /^([a-zA-Z][a-zA-Z\d+.-]*:)/.exec(source)?.[1].toLowerCase();
15
- if (scheme && !["http:", "https:"].includes(scheme)) throw new TypeError("CSS resource must use HTTP(S)");
16
- let resource;
17
- if (scheme) resource = new URL(source);
18
- else if (source.startsWith("//")) resource = new URL(`${base.protocol}${source}`);
19
- else {
20
- const [, path, query, hash] = /^([^?#]*)(\?[^#]*)?(#.*)?$/.exec(source);
21
- const pathname = path.startsWith("/") ? path : `${base.pathname.slice(0, base.pathname.lastIndexOf("/") + 1)}${path}`;
22
- const segments = [];
23
- for (const segment of pathname.split("/")) {
24
- if (segment === ".") continue;
25
- if (segment === "..") {
26
- if (segments.length > 1) segments.pop();
27
- } else segments.push(segment);
28
- }
29
- const normalized = segments.join("/") || "/";
30
- resource = new URL(`${base.origin}${normalized}${query ?? (path ? "" : base.search)}${hash ?? ""}`);
31
- }
32
- if (!["http:", "https:"].includes(resource.protocol.toLowerCase())) throw new TypeError("CSS resource must use HTTP(S)");
33
- return resource;
34
- }
35
-
36
- /**
37
- * 返回模块页面及其公共浏览器资源,不处理 API、网络或持久化。
38
- * Serve module pages and common browser assets without handling APIs, network access or persistence.
39
- * @returns {void} 响应已交给代理宿主 / Response delivered to the proxy host.
40
- */
41
- function run() {
42
- const request = globalThis.$request;
43
- let result;
44
- try {
45
- const url = new URL(request.url);
46
- if (/^\/settings\/[a-zA-Z0-9_-]+\/?$/.test(url.pathname)) {
47
- if (!["GET", "HEAD"].includes(request.method)) result = response(request, 405, { error: "Method not allowed" });
48
- else {
49
- const header = Object.entries(request.headers ?? {}).find(([name]) => name.toLowerCase() === "x-preferencepanes-css");
50
- const source = (header ? header[1] : url.searchParams.get("css"))?.trim();
51
- let stylesheet = "";
52
- if (source) {
53
- const resource = stylesheetURL(source, url);
54
- const href = resource.href.replaceAll("&", "&").replaceAll('"', """);
55
- stylesheet = `<link data-preference-panes-stylesheet rel="stylesheet" href="${href}">`;
56
- }
57
- result = response(request, 200, assets.page.body.replace("<!--__PREFERENCE_PANES_STYLESHEET__-->", stylesheet), "text/html");
58
- }
59
- } else {
60
- const asset = assets[url.pathname];
61
- if (asset) result = ["GET", "HEAD"].includes(request.method) ? response(request, 200, asset.body, asset.type) : response(request, 405, { error: "Method not allowed" });
62
- }
63
- } catch (error) {
64
- console.error(`PreferencePanes Web: ${error.message}`);
65
- result = response(request, 500, { error: error.message });
66
- }
67
- if (!result) done({});
68
- else done($app === "Quantumult X" ? result : { response: result });
69
- }
70
-
71
- /**
72
- * 构造静态资源响应,HEAD 请求不返回正文。
73
- * Build a static resource response without a body for HEAD requests.
74
- * @param {import("./index.js").SettingsRequest} request 代理请求 / Proxy request.
75
- * @param {number} status HTTP 状态 / HTTP status.
76
- * @param {unknown} body 响应正文 / Response body.
77
- * @param {string} [type] 媒体类型 / Media type.
78
- * @returns {import("./index.js").SettingsResponse} 静态资源响应 / Static resource response.
79
- */
80
- function response(request, status, body, type = "application/json") {
81
- return {
82
- status,
83
- headers: { "Content-Type": `${type}; charset=utf-8`, "Cache-Control": "no-store", "X-Content-Type-Options": "nosniff" },
84
- body: request.method === "HEAD" ? "" : type === "application/json" ? JSON.stringify(body) : body,
85
- };
86
- }
87
-
88
- run();