@yunzai-ng/core 0.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/LICENSE +661 -0
- package/README.md +51 -0
- package/dist/adapter/accounts.d.ts +174 -0
- package/dist/adapter/accounts.d.ts.map +1 -0
- package/dist/adapter/accounts.js +653 -0
- package/dist/adapter/accounts.js.map +1 -0
- package/dist/adapter/bots.d.ts +142 -0
- package/dist/adapter/bots.d.ts.map +1 -0
- package/dist/adapter/bots.js +454 -0
- package/dist/adapter/bots.js.map +1 -0
- package/dist/adapter/host.d.ts +114 -0
- package/dist/adapter/host.d.ts.map +1 -0
- package/dist/adapter/host.js +90 -0
- package/dist/adapter/host.js.map +1 -0
- package/dist/adapter/login.d.ts +174 -0
- package/dist/adapter/login.d.ts.map +1 -0
- package/dist/adapter/login.js +345 -0
- package/dist/adapter/login.js.map +1 -0
- package/dist/adapter/registry.d.ts +102 -0
- package/dist/adapter/registry.d.ts.map +1 -0
- package/dist/adapter/registry.js +150 -0
- package/dist/adapter/registry.js.map +1 -0
- package/dist/config/core-config.d.ts +151 -0
- package/dist/config/core-config.d.ts.map +1 -0
- package/dist/config/core-config.js +338 -0
- package/dist/config/core-config.js.map +1 -0
- package/dist/config/schema.d.ts +449 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +871 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/store.d.ts +184 -0
- package/dist/config/store.d.ts.map +1 -0
- package/dist/config/store.js +428 -0
- package/dist/config/store.js.map +1 -0
- package/dist/config/yaml.d.ts +23 -0
- package/dist/config/yaml.d.ts.map +1 -0
- package/dist/config/yaml.js +108 -0
- package/dist/config/yaml.js.map +1 -0
- package/dist/http/client.d.ts +82 -0
- package/dist/http/client.d.ts.map +1 -0
- package/dist/http/client.js +658 -0
- package/dist/http/client.js.map +1 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/app.d.ts +244 -0
- package/dist/kernel/app.d.ts.map +1 -0
- package/dist/kernel/app.js +654 -0
- package/dist/kernel/app.js.map +1 -0
- package/dist/kernel/kv-sink.d.ts +34 -0
- package/dist/kernel/kv-sink.d.ts.map +1 -0
- package/dist/kernel/kv-sink.js +25 -0
- package/dist/kernel/kv-sink.js.map +1 -0
- package/dist/kernel/policy.d.ts +77 -0
- package/dist/kernel/policy.d.ts.map +1 -0
- package/dist/kernel/policy.js +99 -0
- package/dist/kernel/policy.js.map +1 -0
- package/dist/kernel/runtime.d.ts +117 -0
- package/dist/kernel/runtime.d.ts.map +1 -0
- package/dist/kernel/runtime.js +197 -0
- package/dist/kernel/runtime.js.map +1 -0
- package/dist/kernel/sql-sink.d.ts +36 -0
- package/dist/kernel/sql-sink.d.ts.map +1 -0
- package/dist/kernel/sql-sink.js +114 -0
- package/dist/kernel/sql-sink.js.map +1 -0
- package/dist/logger/format.d.ts +67 -0
- package/dist/logger/format.d.ts.map +1 -0
- package/dist/logger/format.js +218 -0
- package/dist/logger/format.js.map +1 -0
- package/dist/logger/index.d.ts +97 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +363 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/rotate.d.ts +47 -0
- package/dist/logger/rotate.d.ts.map +1 -0
- package/dist/logger/rotate.js +242 -0
- package/dist/logger/rotate.js.map +1 -0
- package/dist/message/segment.d.ts +255 -0
- package/dist/message/segment.d.ts.map +1 -0
- package/dist/message/segment.js +510 -0
- package/dist/message/segment.js.map +1 -0
- package/dist/message/split.d.ts +34 -0
- package/dist/message/split.d.ts.map +1 -0
- package/dist/message/split.js +79 -0
- package/dist/message/split.js.map +1 -0
- package/dist/message/target.d.ts +29 -0
- package/dist/message/target.d.ts.map +1 -0
- package/dist/message/target.js +34 -0
- package/dist/message/target.js.map +1 -0
- package/dist/pipeline/cooldown.d.ts +84 -0
- package/dist/pipeline/cooldown.d.ts.map +1 -0
- package/dist/pipeline/cooldown.js +94 -0
- package/dist/pipeline/cooldown.js.map +1 -0
- package/dist/pipeline/dispatch.d.ts +98 -0
- package/dist/pipeline/dispatch.d.ts.map +1 -0
- package/dist/pipeline/dispatch.js +323 -0
- package/dist/pipeline/dispatch.js.map +1 -0
- package/dist/pipeline/event.d.ts +130 -0
- package/dist/pipeline/event.d.ts.map +1 -0
- package/dist/pipeline/event.js +538 -0
- package/dist/pipeline/event.js.map +1 -0
- package/dist/pipeline/middleware.d.ts +63 -0
- package/dist/pipeline/middleware.d.ts.map +1 -0
- package/dist/pipeline/middleware.js +174 -0
- package/dist/pipeline/middleware.js.map +1 -0
- package/dist/pipeline/prompt.d.ts +80 -0
- package/dist/pipeline/prompt.d.ts.map +1 -0
- package/dist/pipeline/prompt.js +155 -0
- package/dist/pipeline/prompt.js.map +1 -0
- package/dist/pipeline/router.d.ts +98 -0
- package/dist/pipeline/router.d.ts.map +1 -0
- package/dist/pipeline/router.js +489 -0
- package/dist/pipeline/router.js.map +1 -0
- package/dist/platform/detect.d.ts +24 -0
- package/dist/platform/detect.d.ts.map +1 -0
- package/dist/platform/detect.js +178 -0
- package/dist/platform/detect.js.map +1 -0
- package/dist/platform/paths.d.ts +38 -0
- package/dist/platform/paths.d.ts.map +1 -0
- package/dist/platform/paths.js +129 -0
- package/dist/platform/paths.js.map +1 -0
- package/dist/platform/system.d.ts +71 -0
- package/dist/platform/system.d.ts.map +1 -0
- package/dist/platform/system.js +242 -0
- package/dist/platform/system.js.map +1 -0
- package/dist/plugin/context.d.ts +92 -0
- package/dist/plugin/context.d.ts.map +1 -0
- package/dist/plugin/context.js +573 -0
- package/dist/plugin/context.js.map +1 -0
- package/dist/plugin/define.d.ts +92 -0
- package/dist/plugin/define.d.ts.map +1 -0
- package/dist/plugin/define.js +82 -0
- package/dist/plugin/define.js.map +1 -0
- package/dist/plugin/discover.d.ts +106 -0
- package/dist/plugin/discover.d.ts.map +1 -0
- package/dist/plugin/discover.js +254 -0
- package/dist/plugin/discover.js.map +1 -0
- package/dist/plugin/events.d.ts +109 -0
- package/dist/plugin/events.d.ts.map +1 -0
- package/dist/plugin/events.js +209 -0
- package/dist/plugin/events.js.map +1 -0
- package/dist/plugin/hooks.d.ts +266 -0
- package/dist/plugin/hooks.d.ts.map +1 -0
- package/dist/plugin/hooks.js +84 -0
- package/dist/plugin/hooks.js.map +1 -0
- package/dist/plugin/host.d.ts +160 -0
- package/dist/plugin/host.d.ts.map +1 -0
- package/dist/plugin/host.js +546 -0
- package/dist/plugin/host.js.map +1 -0
- package/dist/plugin/market.d.ts +264 -0
- package/dist/plugin/market.d.ts.map +1 -0
- package/dist/plugin/market.js +700 -0
- package/dist/plugin/market.js.map +1 -0
- package/dist/plugin/services.d.ts +116 -0
- package/dist/plugin/services.d.ts.map +1 -0
- package/dist/plugin/services.js +213 -0
- package/dist/plugin/services.js.map +1 -0
- package/dist/plugin/tar.d.ts +65 -0
- package/dist/plugin/tar.d.ts.map +1 -0
- package/dist/plugin/tar.js +277 -0
- package/dist/plugin/tar.js.map +1 -0
- package/dist/render/registry.d.ts +127 -0
- package/dist/render/registry.d.ts.map +1 -0
- package/dist/render/registry.js +306 -0
- package/dist/render/registry.js.map +1 -0
- package/dist/scheduler/index.d.ts +67 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +279 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/server/api.d.ts +179 -0
- package/dist/server/api.d.ts.map +1 -0
- package/dist/server/api.js +602 -0
- package/dist/server/api.js.map +1 -0
- package/dist/server/auth.d.ts +83 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/auth.js +178 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/browse.d.ts +60 -0
- package/dist/server/browse.d.ts.map +1 -0
- package/dist/server/browse.js +187 -0
- package/dist/server/browse.js.map +1 -0
- package/dist/server/files.d.ts +27 -0
- package/dist/server/files.d.ts.map +1 -0
- package/dist/server/files.js +76 -0
- package/dist/server/files.js.map +1 -0
- package/dist/server/index.d.ts +189 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +1123 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/table.d.ts +105 -0
- package/dist/server/table.d.ts.map +1 -0
- package/dist/server/table.js +289 -0
- package/dist/server/table.js.map +1 -0
- package/dist/store/index.d.ts +50 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +120 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/json.d.ts +73 -0
- package/dist/store/json.d.ts.map +1 -0
- package/dist/store/json.js +174 -0
- package/dist/store/json.js.map +1 -0
- package/dist/store/kv.d.ts +126 -0
- package/dist/store/kv.d.ts.map +1 -0
- package/dist/store/kv.js +232 -0
- package/dist/store/kv.js.map +1 -0
- package/dist/store/level.d.ts +103 -0
- package/dist/store/level.d.ts.map +1 -0
- package/dist/store/level.js +119 -0
- package/dist/store/level.js.map +1 -0
- package/dist/store/memory.d.ts +61 -0
- package/dist/store/memory.d.ts.map +1 -0
- package/dist/store/memory.js +94 -0
- package/dist/store/memory.js.map +1 -0
- package/dist/store/sql.d.ts +142 -0
- package/dist/store/sql.d.ts.map +1 -0
- package/dist/store/sql.js +246 -0
- package/dist/store/sql.js.map +1 -0
- package/dist/testing/fake.d.ts +109 -0
- package/dist/testing/fake.d.ts.map +1 -0
- package/dist/testing/fake.js +196 -0
- package/dist/testing/fake.js.map +1 -0
- package/dist/testing/index.d.ts +16 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +16 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-adapter.d.ts +205 -0
- package/dist/testing/mock-adapter.d.ts.map +1 -0
- package/dist/testing/mock-adapter.js +309 -0
- package/dist/testing/mock-adapter.js.map +1 -0
- package/dist/util/deep.d.ts +108 -0
- package/dist/util/deep.d.ts.map +1 -0
- package/dist/util/deep.js +275 -0
- package/dist/util/deep.js.map +1 -0
- package/dist/util/defer.d.ts +107 -0
- package/dist/util/defer.d.ts.map +1 -0
- package/dist/util/defer.js +163 -0
- package/dist/util/defer.js.map +1 -0
- package/dist/util/dispose.d.ts +88 -0
- package/dist/util/dispose.d.ts.map +1 -0
- package/dist/util/dispose.js +143 -0
- package/dist/util/dispose.js.map +1 -0
- package/dist/util/duration.d.ts +28 -0
- package/dist/util/duration.d.ts.map +1 -0
- package/dist/util/duration.js +77 -0
- package/dist/util/duration.js.map +1 -0
- package/dist/util/fs.d.ts +110 -0
- package/dist/util/fs.d.ts.map +1 -0
- package/dist/util/fs.js +269 -0
- package/dist/util/fs.js.map +1 -0
- package/dist/util/id.d.ts +49 -0
- package/dist/util/id.d.ts.map +1 -0
- package/dist/util/id.js +87 -0
- package/dist/util/id.js.map +1 -0
- package/dist/util/lru.d.ts +74 -0
- package/dist/util/lru.d.ts.map +1 -0
- package/dist/util/lru.js +156 -0
- package/dist/util/lru.js.map +1 -0
- package/dist/util/queue.d.ts +64 -0
- package/dist/util/queue.d.ts.map +1 -0
- package/dist/util/queue.js +147 -0
- package/dist/util/queue.js.map +1 -0
- package/dist/util/text.d.ts +86 -0
- package/dist/util/text.d.ts.map +1 -0
- package/dist/util/text.js +182 -0
- package/dist/util/text.js.map +1 -0
- package/package.json +44 -0
- package/src/adapter/accounts.ts +758 -0
- package/src/adapter/bots.ts +582 -0
- package/src/adapter/host.ts +224 -0
- package/src/adapter/login.ts +481 -0
- package/src/adapter/registry.ts +202 -0
- package/src/config/core-config.test.ts +60 -0
- package/src/config/core-config.ts +401 -0
- package/src/config/schema.test.ts +179 -0
- package/src/config/schema.ts +1036 -0
- package/src/config/store.test.ts +245 -0
- package/src/config/store.ts +506 -0
- package/src/config/yaml.ts +119 -0
- package/src/http/client.test.ts +568 -0
- package/src/http/client.ts +777 -0
- package/src/index.ts +106 -0
- package/src/kernel/app.test.ts +267 -0
- package/src/kernel/app.ts +843 -0
- package/src/kernel/kv-sink.ts +58 -0
- package/src/kernel/policy.ts +120 -0
- package/src/kernel/runtime.test.ts +542 -0
- package/src/kernel/runtime.ts +307 -0
- package/src/kernel/sql-sink.ts +154 -0
- package/src/logger/format.ts +259 -0
- package/src/logger/index.ts +427 -0
- package/src/logger/rotate.ts +265 -0
- package/src/message/segment.test.ts +335 -0
- package/src/message/segment.ts +569 -0
- package/src/message/split.ts +97 -0
- package/src/message/target.ts +48 -0
- package/src/pipeline/cooldown.ts +136 -0
- package/src/pipeline/dispatch.ts +419 -0
- package/src/pipeline/event.ts +735 -0
- package/src/pipeline/middleware.test.ts +426 -0
- package/src/pipeline/middleware.ts +199 -0
- package/src/pipeline/prompt.ts +212 -0
- package/src/pipeline/router.test.ts +432 -0
- package/src/pipeline/router.ts +575 -0
- package/src/platform/detect.ts +178 -0
- package/src/platform/paths.ts +147 -0
- package/src/platform/system.test.ts +102 -0
- package/src/platform/system.ts +289 -0
- package/src/plugin/context.test.ts +459 -0
- package/src/plugin/context.ts +757 -0
- package/src/plugin/define.test.ts +120 -0
- package/src/plugin/define.ts +142 -0
- package/src/plugin/discover.test.ts +253 -0
- package/src/plugin/discover.ts +353 -0
- package/src/plugin/events.test.ts +162 -0
- package/src/plugin/events.ts +266 -0
- package/src/plugin/hooks.ts +373 -0
- package/src/plugin/host.test.ts +696 -0
- package/src/plugin/host.ts +738 -0
- package/src/plugin/market.test.ts +781 -0
- package/src/plugin/market.ts +870 -0
- package/src/plugin/services.test.ts +135 -0
- package/src/plugin/services.ts +261 -0
- package/src/plugin/tar.test.ts +158 -0
- package/src/plugin/tar.ts +309 -0
- package/src/render/registry.test.ts +127 -0
- package/src/render/registry.ts +439 -0
- package/src/scheduler/index.ts +357 -0
- package/src/server/api.test.ts +802 -0
- package/src/server/api.ts +869 -0
- package/src/server/auth.ts +201 -0
- package/src/server/browse.test.ts +193 -0
- package/src/server/browse.ts +240 -0
- package/src/server/files.ts +97 -0
- package/src/server/index.test.ts +566 -0
- package/src/server/index.ts +1386 -0
- package/src/server/table.ts +351 -0
- package/src/store/index.ts +156 -0
- package/src/store/json.ts +198 -0
- package/src/store/kv.test.ts +307 -0
- package/src/store/kv.ts +256 -0
- package/src/store/level.ts +167 -0
- package/src/store/memory.ts +109 -0
- package/src/store/sql.test.ts +204 -0
- package/src/store/sql.ts +324 -0
- package/src/testing/fake.ts +297 -0
- package/src/testing/index.ts +15 -0
- package/src/testing/mock-adapter.ts +588 -0
- package/src/util/deep.ts +272 -0
- package/src/util/defer.ts +211 -0
- package/src/util/dispose.ts +169 -0
- package/src/util/duration.ts +82 -0
- package/src/util/fs.ts +279 -0
- package/src/util/id.ts +94 -0
- package/src/util/lru.ts +185 -0
- package/src/util/queue.ts +167 -0
- package/src/util/text.ts +189 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模块职责:tar.gz 解包 —— 把内存中的归档解到目标目录,并在解包阶段执行路径与体积校验
|
|
3
|
+
* 依赖方向:仅依赖 node 标准库与 `util/fs` 的越界校验;不认识插件市场,也不发起网络请求
|
|
4
|
+
* 生命周期:纯函数,无状态
|
|
5
|
+
* 注意事项:该实现不引入第三方解包库。插件市场需要在 Windows 与 Termux 上以相同方式
|
|
6
|
+
* 解包 GitHub 归档,而现有的 tar 实现均带原生模块或较大的依赖树;
|
|
7
|
+
* 归档格式本身只有 512 字节定长头部一种结构,自行解析的成本低于引入依赖。
|
|
8
|
+
*
|
|
9
|
+
* 解包被视为处理不可信输入。三项校验在写盘之前完成:
|
|
10
|
+
* 1) 每个条目的目标路径经 `safeJoin` 求值,越出目标目录即丢弃该条目;
|
|
11
|
+
* 2) 符号链接与硬链接条目一律丢弃 —— 归档可借链接把后续写入导向目录之外,
|
|
12
|
+
* 而插件分发不需要链接;
|
|
13
|
+
* 3) 解包后总字节数与条目数均设上限,避免高压缩比归档耗尽磁盘。
|
|
14
|
+
*/
|
|
15
|
+
import { gunzipSync, gzipSync } from "node:zlib";
|
|
16
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
17
|
+
import { dirname } from "node:path";
|
|
18
|
+
import { safeJoin } from "../util/fs.js";
|
|
19
|
+
/** tar 块大小 */
|
|
20
|
+
const BLOCK = 512;
|
|
21
|
+
/** 头部各字段的偏移与长度 */
|
|
22
|
+
const FIELD = {
|
|
23
|
+
name: [0, 100],
|
|
24
|
+
size: [124, 12],
|
|
25
|
+
typeflag: [156, 1],
|
|
26
|
+
prefix: [345, 155]
|
|
27
|
+
};
|
|
28
|
+
/** 解包后总字节数的缺省上限 */
|
|
29
|
+
const DEFAULT_MAX_BYTES = 256 * 1024 * 1024;
|
|
30
|
+
/** 条目数的缺省上限 */
|
|
31
|
+
const DEFAULT_MAX_ENTRIES = 20_000;
|
|
32
|
+
/**
|
|
33
|
+
* 按 NUL 截断并去除首尾空白
|
|
34
|
+
* @param buf 归档缓冲
|
|
35
|
+
* @param offset 起始偏移
|
|
36
|
+
* @param length 字段长度
|
|
37
|
+
* @returns 字段文本
|
|
38
|
+
*/
|
|
39
|
+
function textAt(buf, offset, length) {
|
|
40
|
+
const slice = buf.subarray(offset, offset + length);
|
|
41
|
+
const end = slice.indexOf(0);
|
|
42
|
+
return Buffer.from(end === -1 ? slice : slice.subarray(0, end))
|
|
43
|
+
.toString("utf8")
|
|
44
|
+
.trim();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 读取一个八进制数值字段
|
|
48
|
+
*
|
|
49
|
+
* 体积字段在超过 8GiB 时会改用 base-256 编码(首字节最高位置 1)。插件归档不会
|
|
50
|
+
* 触及该量级,因此这里遇到 base-256 直接判为非法,而不是实现一段无从验证的分支。
|
|
51
|
+
* @param buf 归档缓冲
|
|
52
|
+
* @param offset 起始偏移
|
|
53
|
+
* @param length 字段长度
|
|
54
|
+
* @returns 数值
|
|
55
|
+
* @throws 字段为 base-256 编码或不是合法八进制时
|
|
56
|
+
*/
|
|
57
|
+
function octalAt(buf, offset, length) {
|
|
58
|
+
const first = buf[offset] ?? 0;
|
|
59
|
+
if ((first & 0x80) !== 0)
|
|
60
|
+
throw new Error("归档使用了 base-256 数值字段,超出支持范围");
|
|
61
|
+
const text = textAt(buf, offset, length);
|
|
62
|
+
if (text === "")
|
|
63
|
+
return 0;
|
|
64
|
+
const value = Number.parseInt(text, 8);
|
|
65
|
+
if (!Number.isFinite(value) || value < 0)
|
|
66
|
+
throw new Error(`归档头部的数值字段非法:${text}`);
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 判断一个块是否全为零字节
|
|
71
|
+
* @param buf 归档缓冲
|
|
72
|
+
* @param offset 块起始偏移
|
|
73
|
+
* @returns 是否为结束块
|
|
74
|
+
*/
|
|
75
|
+
function isZeroBlock(buf, offset) {
|
|
76
|
+
for (let i = offset; i < offset + BLOCK; i++)
|
|
77
|
+
if (buf[i] !== 0)
|
|
78
|
+
return false;
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 解析一个头部块
|
|
83
|
+
* @param buf 归档缓冲
|
|
84
|
+
* @param offset 块起始偏移
|
|
85
|
+
* @returns 头部信息
|
|
86
|
+
*/
|
|
87
|
+
function readHeader(buf, offset) {
|
|
88
|
+
const name = textAt(buf, offset + FIELD.name[0], FIELD.name[1]);
|
|
89
|
+
const prefix = textAt(buf, offset + FIELD.prefix[0], FIELD.prefix[1]);
|
|
90
|
+
return {
|
|
91
|
+
path: prefix === "" ? name : `${prefix}/${name}`,
|
|
92
|
+
size: octalAt(buf, offset + FIELD.size[0], FIELD.size[1]),
|
|
93
|
+
type: textAt(buf, offset + FIELD.typeflag[0], FIELD.typeflag[1]) || "0"
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 从 pax 扩展头部中取出 `path` 记录
|
|
98
|
+
*
|
|
99
|
+
* 记录格式为 `长度 键=值\n`,长度含自身。仅取 `path`,其余记录(权限、时间)
|
|
100
|
+
* 与插件分发无关。
|
|
101
|
+
* @param block 扩展头部的内容
|
|
102
|
+
* @returns 路径;未声明时 undefined
|
|
103
|
+
*/
|
|
104
|
+
function paxPath(block) {
|
|
105
|
+
const text = Buffer.from(block).toString("utf8");
|
|
106
|
+
const match = /\d+ path=([^\n]*)\n/.exec(text);
|
|
107
|
+
return match?.[1];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 剥离路径的前若干层
|
|
111
|
+
* @param path 归档内路径
|
|
112
|
+
* @param strip 剥离层数
|
|
113
|
+
* @returns 剥离后的相对路径;剥空时为空串
|
|
114
|
+
*/
|
|
115
|
+
function stripPath(path, strip) {
|
|
116
|
+
if (strip <= 0)
|
|
117
|
+
return path;
|
|
118
|
+
const parts = path.split("/").filter(part => part !== "");
|
|
119
|
+
return parts.slice(strip).join("/");
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 把归档条目写入目标目录
|
|
123
|
+
*
|
|
124
|
+
* 目标目录会被按需创建。返回值为实际写入的相对路径列表,供调用方在日志中说明
|
|
125
|
+
* 安装内容,也便于单元测试断言。
|
|
126
|
+
* @param archive gzip 压缩后的 tar 归档
|
|
127
|
+
* @param dest 目标目录绝对路径
|
|
128
|
+
* @param opts 解包选项
|
|
129
|
+
* @returns 实际写入的相对路径列表
|
|
130
|
+
* @throws 归档结构非法、超出体积或条目上限时
|
|
131
|
+
*/
|
|
132
|
+
export async function extractTarGz(archive, dest, opts = {}) {
|
|
133
|
+
const buf = gunzipSync(archive);
|
|
134
|
+
const strip = opts.strip ?? 0;
|
|
135
|
+
const maxBytes = opts.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
136
|
+
const maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
137
|
+
const written = [];
|
|
138
|
+
let total = 0;
|
|
139
|
+
let entries = 0;
|
|
140
|
+
/** 由 pax 或 GNU 长名头部预告的下一条目路径 */
|
|
141
|
+
let pendingPath;
|
|
142
|
+
let offset = 0;
|
|
143
|
+
while (offset + BLOCK <= buf.length) {
|
|
144
|
+
if (isZeroBlock(buf, offset))
|
|
145
|
+
break;
|
|
146
|
+
const header = readHeader(buf, offset);
|
|
147
|
+
offset += BLOCK;
|
|
148
|
+
const contentBlocks = Math.ceil(header.size / BLOCK);
|
|
149
|
+
const content = buf.subarray(offset, offset + header.size);
|
|
150
|
+
offset += contentBlocks * BLOCK;
|
|
151
|
+
// 扩展头部本身不落盘,只影响下一个条目的路径
|
|
152
|
+
if (header.type === "x" || header.type === "X") {
|
|
153
|
+
pendingPath = paxPath(content);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (header.type === "L") {
|
|
157
|
+
pendingPath = Buffer.from(content).toString("utf8").replace(/\0+$/, "");
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
// 全局头部与链接条目一律丢弃,理由见文件头
|
|
161
|
+
if (header.type === "g" || header.type === "1" || header.type === "2") {
|
|
162
|
+
pendingPath = undefined;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const rawPath = pendingPath ?? header.path;
|
|
166
|
+
pendingPath = undefined;
|
|
167
|
+
const rel = stripPath(rawPath, strip);
|
|
168
|
+
if (rel === "")
|
|
169
|
+
continue;
|
|
170
|
+
if (++entries > maxEntries)
|
|
171
|
+
throw new Error(`归档条目数超过上限 ${maxEntries}`);
|
|
172
|
+
total += header.size;
|
|
173
|
+
if (total > maxBytes)
|
|
174
|
+
throw new Error(`归档解包后体积超过上限 ${maxBytes} 字节`);
|
|
175
|
+
let target;
|
|
176
|
+
try {
|
|
177
|
+
target = safeJoin(dest, rel);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// 越界条目直接跳过:归档由第三方提供,不应因其内容异常而中断整次安装,
|
|
181
|
+
// 但也绝不能按其要求写到目标目录之外
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (header.type === "5") {
|
|
185
|
+
await mkdir(target, { recursive: true });
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (header.type !== "0")
|
|
189
|
+
continue;
|
|
190
|
+
await mkdir(dirname(target), { recursive: true });
|
|
191
|
+
await writeFile(target, content);
|
|
192
|
+
written.push(rel);
|
|
193
|
+
}
|
|
194
|
+
return written;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 判断目录内是否只有一个顶层目录
|
|
198
|
+
*
|
|
199
|
+
* GitHub 的归档统一带一层 `仓库名-提交号/` 包装,而用户自建的归档可能没有。
|
|
200
|
+
* 调用方据此决定 `strip` 取 0 还是 1。
|
|
201
|
+
* @param paths 归档内的相对路径列表
|
|
202
|
+
* @returns 唯一的顶层目录名;不唯一或存在顶层文件时 undefined
|
|
203
|
+
*/
|
|
204
|
+
export function singleRoot(paths) {
|
|
205
|
+
const roots = new Set();
|
|
206
|
+
for (const path of paths) {
|
|
207
|
+
const first = path.split("/")[0] ?? "";
|
|
208
|
+
if (first === path)
|
|
209
|
+
return undefined;
|
|
210
|
+
roots.add(first);
|
|
211
|
+
}
|
|
212
|
+
return roots.size === 1 ? [...roots][0] : undefined;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* 拼一个位于目标目录内的路径,越界时抛错
|
|
216
|
+
*
|
|
217
|
+
* 供插件市场在删除前复核目标路径,语义与解包阶段一致。
|
|
218
|
+
* @param base 基准目录
|
|
219
|
+
* @param name 名称
|
|
220
|
+
* @returns 绝对路径
|
|
221
|
+
* @throws 越界时
|
|
222
|
+
*/
|
|
223
|
+
export function joinWithin(base, name) {
|
|
224
|
+
return safeJoin(base, name);
|
|
225
|
+
}
|
|
226
|
+
/** 供测试与调用方复用的块大小 */
|
|
227
|
+
export const TAR_BLOCK_SIZE = BLOCK;
|
|
228
|
+
/**
|
|
229
|
+
* 构造一个 tar 头部块
|
|
230
|
+
*
|
|
231
|
+
* 该函数只在测试与自建归档时使用;生产路径只解包不打包。之所以放在本文件而不是
|
|
232
|
+
* 测试文件里,是为了让头部字段的偏移只有一份定义 —— 打包与解包共用 `FIELD`,
|
|
233
|
+
* 偏移写错时两侧同时失败,不会出现"测试自己造的归档能解、真实归档不能解"。
|
|
234
|
+
* @param path 条目路径
|
|
235
|
+
* @param size 内容字节数
|
|
236
|
+
* @param type 类型标记
|
|
237
|
+
* @returns 512 字节头部
|
|
238
|
+
*/
|
|
239
|
+
export function buildTarHeader(path, size, type) {
|
|
240
|
+
const block = Buffer.alloc(BLOCK);
|
|
241
|
+
block.write(path.slice(0, FIELD.name[1]), FIELD.name[0], "utf8");
|
|
242
|
+
block.write(`${size.toString(8).padStart(11, "0")}\0`, FIELD.size[0], "ascii");
|
|
243
|
+
block.write("0000644\0", 100, "ascii");
|
|
244
|
+
block.write("0000000\0", 108, "ascii");
|
|
245
|
+
block.write("0000000\0", 116, "ascii");
|
|
246
|
+
block.write(`${Math.floor(Date.now() / 1000).toString(8).padStart(11, "0")}\0`, 136, "ascii");
|
|
247
|
+
block.write(type, FIELD.typeflag[0], "ascii");
|
|
248
|
+
block.write("ustar\0" + "00", 257, "ascii");
|
|
249
|
+
// 校验和字段先填空格再求和,这是格式规定的计算方式
|
|
250
|
+
block.write(" ", 148, "ascii");
|
|
251
|
+
let sum = 0;
|
|
252
|
+
for (const byte of block)
|
|
253
|
+
sum += byte;
|
|
254
|
+
block.write(`${sum.toString(8).padStart(6, "0")}\0 `, 148, "ascii");
|
|
255
|
+
return block;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* 把若干文件打成 gzip 压缩的 tar 归档
|
|
259
|
+
* @param files 条目列表,路径使用正斜杠
|
|
260
|
+
* @returns 压缩后的归档
|
|
261
|
+
*/
|
|
262
|
+
export function buildTarGz(files) {
|
|
263
|
+
const parts = [];
|
|
264
|
+
for (const file of files) {
|
|
265
|
+
const content = typeof file.content === "string" ? Buffer.from(file.content, "utf8") : Buffer.from(file.content);
|
|
266
|
+
const type = file.type ?? "0";
|
|
267
|
+
parts.push(buildTarHeader(file.path, type === "5" ? 0 : content.length, type));
|
|
268
|
+
if (type !== "5" && content.length > 0) {
|
|
269
|
+
const padded = Buffer.alloc(Math.ceil(content.length / BLOCK) * BLOCK);
|
|
270
|
+
content.copy(padded);
|
|
271
|
+
parts.push(padded);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
parts.push(Buffer.alloc(BLOCK * 2));
|
|
275
|
+
return gzipSync(Buffer.concat(parts));
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=tar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tar.js","sourceRoot":"","sources":["../../src/plugin/tar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模块职责:渲染注册表 —— 实现 `RenderSink`,管理渲染器插件并择一执行渲染
|
|
3
|
+
* 依赖方向:依赖类型包、plugin/hooks 的接缝定义、util/*;**不认识 puppeteer**
|
|
4
|
+
* 生命周期:随内核创建;每个渲染器随提供方插件卸载而摘除;`stop()` 关闭全部渲染器
|
|
5
|
+
* 注意事项:内核对「怎么把 HTML 变成图片」零认知,只做三件事:择一可用者、补齐全局默认值、
|
|
6
|
+
* 失败时指明失败方。四项刻意的选择:
|
|
7
|
+
*
|
|
8
|
+
* **`available()` 的结果要缓存。** 它的实现可能是探测 Chromium 是否存在这类几十毫秒的
|
|
9
|
+
* 磁盘操作,每渲染一张图探一次会计进每条消息的响应时间。故按 TTL 缓存,且**探测本身
|
|
10
|
+
* 单例化** —— 十条消息同时请求渲染不该产生十次并发探测。
|
|
11
|
+
*
|
|
12
|
+
* **失败后立即让可用性缓存作废。** 浏览器崩溃这件事必须在下一次渲染时被发现。不可用
|
|
13
|
+
* 状态的 TTL 更短:使用者刚装好 Chromium,不该再等一分钟。
|
|
14
|
+
*
|
|
15
|
+
* **只在「该渲染器整体不可用」时切换**,此前先重试同一个。`render.retry` 的语义是本次
|
|
16
|
+
* 渲染重试几次(浏览器繁忙、页面偶发超时)。全部失败时把每个渲染器的原因**逐条**汇总
|
|
17
|
+
* 抛出 —— 只报最后一个的话,真实原因常在第一个里。
|
|
18
|
+
*
|
|
19
|
+
* **此处不限并发。** 同时渲染多张图会不会耗尽内存,取决于渲染器自己页面池的大小,
|
|
20
|
+
* 只有渲染器插件知道那个数。内核再加一层信号量只会与插件内部的池互相干扰。
|
|
21
|
+
*/
|
|
22
|
+
import type { Disposer, Logger, RenderDoneInfo, RenderRequest, RenderResult, RendererProvider } from "@yunzai-ng/types";
|
|
23
|
+
import type { RenderSink } from "../plugin/hooks.js";
|
|
24
|
+
/** 渲染相关的配置视图(对应配置项 `render.*`) */
|
|
25
|
+
export interface RenderPolicy {
|
|
26
|
+
/** 首选渲染器 id,对应 `render.default` */
|
|
27
|
+
readonly default: string;
|
|
28
|
+
/** 单次渲染超时(毫秒) */
|
|
29
|
+
readonly timeout: number;
|
|
30
|
+
/** 渲染失败重试次数 */
|
|
31
|
+
readonly retry: number;
|
|
32
|
+
/** 图片质量 0-100 */
|
|
33
|
+
readonly quality: number;
|
|
34
|
+
/** 缩放倍率 */
|
|
35
|
+
readonly scale: number;
|
|
36
|
+
}
|
|
37
|
+
/** 渲染器的对外描述(WebUI "渲染" 页面的数据来源) */
|
|
38
|
+
export interface RendererInfo {
|
|
39
|
+
/** 渲染器 id */
|
|
40
|
+
readonly id: string;
|
|
41
|
+
/** 展示名 */
|
|
42
|
+
readonly name: string;
|
|
43
|
+
/** 提供方插件名 */
|
|
44
|
+
readonly owner: string;
|
|
45
|
+
/** 是否为当前首选 */
|
|
46
|
+
readonly preferred: boolean;
|
|
47
|
+
/** 最近判定的可用性;从未判定过时 undefined */
|
|
48
|
+
readonly available: boolean | undefined;
|
|
49
|
+
/** 最近失败原因 */
|
|
50
|
+
readonly lastError: string | undefined;
|
|
51
|
+
/** 累计成功次数 */
|
|
52
|
+
readonly succeeded: number;
|
|
53
|
+
/** 累计失败次数 */
|
|
54
|
+
readonly failed: number;
|
|
55
|
+
}
|
|
56
|
+
/** 渲染注册表构造参数 */
|
|
57
|
+
export interface RenderRegistryOptions {
|
|
58
|
+
/** 基础日志器 */
|
|
59
|
+
readonly logger: Logger;
|
|
60
|
+
/**
|
|
61
|
+
* 取当前渲染配置
|
|
62
|
+
*
|
|
63
|
+
* 取函数而非直接传值:`render.*` 在 WebUI 里随时可改,配置存储会就地更新,
|
|
64
|
+
* 缓存一份快照就意味着"改了配置要重启才生效"。
|
|
65
|
+
*/
|
|
66
|
+
readonly policy: () => RenderPolicy;
|
|
67
|
+
/**
|
|
68
|
+
* 一次渲染结束后的通知(成功或全部渲染器失败)
|
|
69
|
+
*
|
|
70
|
+
* 取回调而非直接传 `CoreEventBus`:本文件对渲染实现零认知,认识事件总线
|
|
71
|
+
* 就等于认识插件系统。回调由 `installRuntime` 传入 —— 它本来就持有总线。
|
|
72
|
+
*
|
|
73
|
+
* 省略即不通知,现有调用方(含测试)因此无须改动。
|
|
74
|
+
*/
|
|
75
|
+
readonly onDone?: (info: RenderDoneInfo) => void;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 渲染注册表
|
|
79
|
+
*
|
|
80
|
+
* 既是 `ctx.registerRenderer()` 的落点,也是 `ctx.render()` / `e.render()` 的执行处。
|
|
81
|
+
*/
|
|
82
|
+
export declare class RenderRegistry implements RenderSink {
|
|
83
|
+
#private;
|
|
84
|
+
/**
|
|
85
|
+
* @param opts 构造参数
|
|
86
|
+
*/
|
|
87
|
+
constructor(opts: RenderRegistryOptions);
|
|
88
|
+
/** 已注册的渲染器数量 */
|
|
89
|
+
get size(): number;
|
|
90
|
+
/**
|
|
91
|
+
* 注册一个渲染器
|
|
92
|
+
* @param provider 渲染器实现
|
|
93
|
+
* @param owner 提供方插件名
|
|
94
|
+
* @returns 注销句柄
|
|
95
|
+
* @throws 该 id 已被别的插件占用时
|
|
96
|
+
*/
|
|
97
|
+
register(provider: RendererProvider, owner: string): Disposer;
|
|
98
|
+
/**
|
|
99
|
+
* 执行一次渲染
|
|
100
|
+
* @param req 渲染请求(模板根等已由插件上下文补全)
|
|
101
|
+
* @returns 渲染结果
|
|
102
|
+
* @throws 没有任何渲染器、没有可用渲染器、或全部渲染器都失败时
|
|
103
|
+
*/
|
|
104
|
+
render(req: RenderRequest): Promise<RenderResult>;
|
|
105
|
+
/**
|
|
106
|
+
* 列出已注册的渲染器
|
|
107
|
+
* @returns 渲染器描述数组,首选排在最前
|
|
108
|
+
*/
|
|
109
|
+
list(): RendererInfo[];
|
|
110
|
+
/**
|
|
111
|
+
* 摘除某插件注册的全部渲染器
|
|
112
|
+
*
|
|
113
|
+
* 兜底路径:插件上下文正常会逐条调用 Disposer,但插件 setup 中途抛错时
|
|
114
|
+
* 可能存在未经 ctx 的登记。
|
|
115
|
+
* @param owner 插件名
|
|
116
|
+
* @returns 摘除的条数
|
|
117
|
+
*/
|
|
118
|
+
removePlugin(owner: string): number;
|
|
119
|
+
/**
|
|
120
|
+
* 关闭全部渲染器(停机时调用)
|
|
121
|
+
*
|
|
122
|
+
* 会等待插件卸载时那些"发出去就不管"的 `dispose()` 收尾 —— 否则进程退出时
|
|
123
|
+
* 可能留下没杀掉的 Chromium 子进程。
|
|
124
|
+
*/
|
|
125
|
+
stop(): Promise<void>;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/render/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EACV,QAAQ,EACR,MAAM,EACN,cAAc,EACd,aAAa,EACb,YAAY,EACZ,gBAAgB,EACjB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAcpD,kCAAkC;AAClC,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,iBAAiB;IACjB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,eAAe;IACf,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,iBAAiB;IACjB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,WAAW;IACX,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAsBD,mCAAmC;AACnC,MAAM,WAAW,YAAY;IAC3B,aAAa;IACb,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,UAAU;IACV,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,aAAa;IACb,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,cAAc;IACd,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,CAAA;IACvC,aAAa;IACb,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,aAAa;IACb,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,aAAa;IACb,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,gBAAgB;AAChB,MAAM,WAAW,qBAAqB;IACpC,YAAY;IACZ,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,YAAY,CAAA;IACnC;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAA;CACjD;AAWD;;;;GAIG;AACH,qBAAa,cAAe,YAAW,UAAU;;IAY/C;;OAEG;gBACS,IAAI,EAAE,qBAAqB;IAMvC,gBAAgB;IAChB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ;IA0B7D;;;;;OAKG;IACG,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAqFvD;;;OAGG;IACH,IAAI,IAAI,YAAY,EAAE;IActB;;;;;;;OAOG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAWnC;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAgH5B"}
|