@sfmc-bds/bds-tools 0.2.0-beta.9 → 0.2.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.
Files changed (66) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +1 -1
  3. package/dist/bds-manager.d.ts +16 -6
  4. package/dist/bds-manager.d.ts.map +1 -1
  5. package/dist/bds-manager.js +19 -1
  6. package/dist/bds-manager.js.map +2 -2
  7. package/dist/changelog.d.ts +11 -7
  8. package/dist/changelog.d.ts.map +1 -1
  9. package/dist/changelog.js +60 -34
  10. package/dist/changelog.js.map +2 -2
  11. package/dist/check-update.d.ts.map +1 -1
  12. package/dist/check-update.js +55 -17
  13. package/dist/check-update.js.map +2 -2
  14. package/dist/cli-pack-manager.js +11 -1
  15. package/dist/cli-pack-manager.js.map +2 -2
  16. package/dist/dependency-negotiator.d.ts +73 -0
  17. package/dist/dependency-negotiator.d.ts.map +1 -0
  18. package/dist/dependency-negotiator.js +151 -0
  19. package/dist/dependency-negotiator.js.map +7 -0
  20. package/dist/fsx.d.ts +15 -7
  21. package/dist/fsx.d.ts.map +1 -1
  22. package/dist/fsx.js +67 -8
  23. package/dist/fsx.js.map +2 -2
  24. package/dist/http.d.ts +49 -11
  25. package/dist/http.d.ts.map +1 -1
  26. package/dist/http.js.map +2 -2
  27. package/dist/level-dat.d.ts +105 -0
  28. package/dist/level-dat.d.ts.map +1 -0
  29. package/dist/level-dat.js +490 -0
  30. package/dist/level-dat.js.map +7 -0
  31. package/dist/pack-manager.d.ts +41 -34
  32. package/dist/pack-manager.d.ts.map +1 -1
  33. package/dist/pack-manager.js +73 -24
  34. package/dist/pack-manager.js.map +2 -2
  35. package/dist/qq-events-notify.d.ts +1 -1
  36. package/dist/qq-events-notify.d.ts.map +1 -1
  37. package/dist/qq-events-notify.js.map +1 -1
  38. package/dist/qqutil.d.ts +10 -6
  39. package/dist/qqutil.d.ts.map +1 -1
  40. package/dist/qqutil.js +14 -12
  41. package/dist/qqutil.js.map +2 -2
  42. package/dist/rollback.d.ts.map +1 -1
  43. package/dist/rollback.js +2 -2
  44. package/dist/rollback.js.map +2 -2
  45. package/dist/server-properties-i18n.d.ts +17 -0
  46. package/dist/server-properties-i18n.d.ts.map +1 -0
  47. package/dist/server-properties-i18n.js +201 -0
  48. package/dist/server-properties-i18n.js.map +7 -0
  49. package/dist/server-properties.d.ts +25 -0
  50. package/dist/server-properties.d.ts.map +1 -1
  51. package/dist/server-properties.js +141 -1
  52. package/dist/server-properties.js.map +2 -2
  53. package/dist/types.d.ts +1 -0
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/upstream.d.ts +14 -6
  56. package/dist/upstream.d.ts.map +1 -1
  57. package/dist/upstream.js.map +2 -2
  58. package/dist/world-packs.d.ts +106 -3
  59. package/dist/world-packs.d.ts.map +1 -1
  60. package/dist/world-packs.js +245 -10
  61. package/dist/world-packs.js.map +3 -3
  62. package/package.json +19 -14
  63. package/dist/qq-events-notify.test.d.ts +0 -5
  64. package/dist/qq-events-notify.test.d.ts.map +0 -1
  65. package/dist/qq-events-notify.test.js +0 -41
  66. package/dist/qq-events-notify.test.js.map +0 -7
@@ -1,53 +1,52 @@
1
1
  /**
2
- * pack-manager.ts — Bedrock 行为包/资源包 装配 + 部署到 BDS 根。
2
+ * pack-manager.ts — Bedrock 行为包(BP)与资源包(RP)组装及部署引擎
3
3
  *
4
- * 纯函数库,两条消费路径:
4
+ * 核心设计与调用路径:
5
+ * - 进程内直连(推荐):`@sfmc-bds/bds-tools/pack-manager-lib` 供 CLI 编排与生命周期管理直接调用(遵循依赖倒置原则)
6
+ * - 独立 CLI:由 `cli-pack-manager.ts` 暴露命令行子命令供脚本与手工调试使用
5
7
  *
6
- * - 同进程(推荐): sfmc/pack-lifecycle 经 `@sfmc-bds/bds-tools/pack-manager-lib`
7
- * 直连本模块(DIP);world-packs 等同理。
8
- * - CLI: `cli-pack-manager.js` 仍暴露相同动词,供外部脚本/手工调试;
9
- * CLI 只是本库的薄适配,不再是 sfmc 主路径。
10
- *
11
- * 约束:本文件不引入 esbuild / 重型 npm-only 包,保持可被 Node 子进程直接加载。
12
- *
13
- * 已有依赖 (bds-tools/package.json):
14
- * - @sfmc-bds/sdk/logs createTerminalProgress: 进度条(BDS 更新等)
15
- * - node-html-parser: changelog 抓取 (本文件用不到)
16
- * - jszip: zip 解压(模块 zip / BDS server.zip)
8
+ * 核心能力:
9
+ * - 行为包组装:将 esbuild 打包后的 `scripts/main.js`、元数据 manifest 与图标封装为 BDS 行为包结构
10
+ * - 资源包聚合:将各模块私有的 `resource_pack` 目录无冲突递归合并为聚合资源包
11
+ * - 世界部署与清单激活:将包部署至 BDS `<level>/behavior_packs` 与 `resource_packs`,并同步维护 `world_behavior_packs.json`
17
12
  */
18
13
  import { copyDirAsync, copyFileAsync } from "./fsx.js";
14
+ import { type PackManifestDependency } from "./dependency-negotiator.js";
15
+ export * from "./dependency-negotiator.js";
19
16
  export interface AssembleBehaviorPackOpts {
20
- /** Where the bundled scripts/main.js already exists (esbuild output dir) */
17
+ /** 已完成打包的 `scripts/main.js` 所在源码目录(即 esbuild 输出目录)。 */
21
18
  srcDir: string;
22
- /** Output behavior pack directory (created if missing) */
19
+ /** 行为包目标输出目录(若不存在则自动创建)。 */
23
20
  outDir: string;
24
- /** BP 目录名 — 默认 'sfmc-modules' */
21
+ /** BP 项目/目录名(默认为 `'sfmc-modules'`)。 */
25
22
  projectName: string;
26
- /** manifest.json 的 header.version [major, minor, patch]; 默认 [1, 0, 0] */
23
+ /** `manifest.json` 中的 `header.version` `[major, minor, patch]`(默认为 `[1, 0, 0]`)。 */
27
24
  version?: [number, number, number] | undefined;
28
- /** manifest.json 的 description */
25
+ /** `manifest.json` 中的包描述信息。 */
29
26
  description?: string | undefined;
30
- /** pack_icon.png 源文件 (optional, 不提供则跳过) */
27
+ /** `pack_icon.png` 图标源文件路径(可选,未提供则跳过)。 */
31
28
  iconSrc?: string | undefined;
32
- /** 稳定 header.uuid;省略则随机生成(首次装配) */
29
+ /** 稳定的 `header.uuid`(缺省时将在首次装配时随机生成)。 */
33
30
  uuid?: string | undefined;
34
- /** 稳定 script module uuid;省略则随机 */
31
+ /** 稳定的 `script module uuid`(缺省时随机生成)。 */
35
32
  moduleUuid?: string | undefined;
33
+ /** 自定义/动态协商后的 dependencies(缺省使用 BASELINE_BEDROCK_DEPENDENCIES)。 */
34
+ dependencies?: PackManifestDependency[] | undefined;
36
35
  }
37
36
  export interface AssembleResourcePackOpts {
38
- /** Modules whose resource_pack/** should be merged. Map<moduleId, resourcePackDir>. */
37
+ /** 需合并资源包目录的模块映射字典(`Record<moduleId, resourcePackDir>`)。 */
39
38
  moduleResourceDirs: Record<string, string>;
40
- /** Output resource pack directory (created if missing) */
39
+ /** 资源包目标输出目录(若不存在则自动创建)。 */
41
40
  outDir: string;
42
- /** RP 目录名 */
41
+ /** RP 项目/目录名。 */
43
42
  projectName: string;
44
- /** manifest.json 的 header.version [major, minor, patch]; 默认 [1, 0, 0] */
43
+ /** `manifest.json` 中的 `header.version` `[major, minor, patch]`(默认为 `[1, 0, 0]`)。 */
45
44
  version?: [number, number, number] | undefined;
46
- /** manifest.json 的 description */
45
+ /** `manifest.json` 中的包描述信息。 */
47
46
  description?: string | undefined;
48
- /** 稳定 header.uuid;省略则随机生成(首次装配) */
47
+ /** 稳定的 `header.uuid`(缺省时随机生成)。 */
49
48
  uuid?: string | undefined;
50
- /** 稳定 resources module uuid;省略则随机 */
49
+ /** 稳定的 `resources module uuid`(缺省时随机生成)。 */
51
50
  moduleUuid?: string | undefined;
52
51
  }
53
52
  export interface AssembleResult {
@@ -90,11 +89,15 @@ export declare function serverPropertiesPath(bdsRoot: string): string;
90
89
  export declare function bdsWorldsDir(bdsRoot: string): string;
91
90
  /** `<bdsRoot>/worlds/<level>` */
92
91
  export declare function bdsWorldLevelDir(bdsRoot: string, levelName: string): string;
92
+ /** `<bdsRoot>/worlds/<level>/level.dat` — 世界存档权威路径 */
93
+ export declare function levelDatPath(bdsRoot: string, levelName: string): string;
93
94
  /** 世界 enable-list JSON 绝对路径(单一权威,供读写两侧) */
94
95
  export declare function worldPackListFile(worldsDir: string, levelName: string, kind: "behavior" | "resource"): string;
95
96
  /** `<bdsRoot>/config/<bpUuid>/permission.json` — Script API 权限文件权威路径 */
96
97
  export declare function configPermissionPath(bdsRoot: string, bpUuid: string): string;
97
- /** 是否已有 Script API permission.json(只读,供 preflight/status) */
98
+ /** `<bdsRoot>/config/<bpUuid>/permissions.json` — BDS 官方规范复数权限文件路径 */
99
+ export declare function configPermissionsPath(bdsRoot: string, bpUuid: string): string;
100
+ /** 是否已有 Script API permission.json 或 permissions.json(只读,供 preflight/status) */
98
101
  export declare function hasConfigPermission(bdsRoot: string, bpUuid: string): boolean;
99
102
  /** 随机生成 BP/RP manifest.json header.uuid (RFC 4122 v4) */
100
103
  export declare function randomUuid(): string;
@@ -126,17 +129,21 @@ export declare function readLevelName(bdsRoot: string): Promise<string>;
126
129
  */
127
130
  export declare function deployToBDS(opts: DeployOpts): Promise<DeployResult>;
128
131
  /**
129
- * 确保 BDS Script API 侧 `<bdsRoot>/config/<bpUuid>/permission.json` 存在。
130
- * 已存在则跳过(不覆盖用户手工改动)。
131
- * @returns true = 新写入; false = 已存在跳过
132
+ * 确保 BDS Script API 侧权限文件存在并包含完整的 SFMC 所需模块权限。
133
+ * - 自动增量合并现有 allowed_modules,自动补齐新增权限(如 @minecraft/diagnostics)
134
+ * - 同时维护 BDS 官方规范的 permissions.json 与历史兼容的 permission.json
135
+ * - 同时更新 moduleUuid(若提供)与 config/default/permissions.json 兜底权限
136
+ * @returns true = 有新增/更新; false = 已是最新无需修改
132
137
  */
133
- export declare function ensureConfigPermission(bdsRoot: string, bpUuid: string): Promise<boolean>;
138
+ export declare function ensureConfigPermission(bdsRoot: string, bpUuid: string, moduleUuid?: string): Promise<boolean>;
134
139
  /** 从已装配 BP/RP 目录读取 header.uuid + version;失败返回 null。 */
135
140
  export declare function readPackManifestHeader(packDir: string): {
136
141
  uuid: string;
137
142
  version: [number, number, number];
138
143
  moduleUuid?: string;
139
144
  } | null;
145
+ /** 从已装配 BP/RP 目录读取 dependencies 列表;若无或失败返回 []。 */
146
+ export declare function readPackManifestDependencies(packDir: string): PackManifestDependency[];
140
147
  /**
141
148
  * Write `@minecraft/*` allowed_modules into a behavior pack's
142
149
  * `permissions.json`. Idempotent: rewrites any pre-existing file.
@@ -156,7 +163,7 @@ export declare function writeBehaviorPackManifest(outDir: string, header: {
156
163
  version: [number, number, number];
157
164
  description?: string | undefined;
158
165
  moduleUuid?: string | undefined;
159
- }): Promise<void>;
166
+ }, dependencies?: PackManifestDependency[] | undefined): Promise<void>;
160
167
  export declare function writeResourcePackManifest(outDir: string, header: {
161
168
  name: string;
162
169
  uuid: string;
@@ -1 +1 @@
1
- {"version":3,"file":"pack-manager.d.ts","sourceRoot":"","sources":["../src/pack-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pack-manager.d.ts","sourceRoot":"","sources":["../src/pack-manager.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,10 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { copyDirAsync, copyFileAsync, readJsonFile } from "./fsx.js";
4
+ import {
5
+ BASELINE_BEDROCK_DEPENDENCIES
6
+ } from "./dependency-negotiator.js";
7
+ export * from "./dependency-negotiator.js";
4
8
  const SFMC_PERMISSIONS = [
5
9
  "@minecraft/server",
6
10
  "@minecraft/server-ui",
@@ -19,6 +23,9 @@ function bdsWorldsDir(bdsRoot) {
19
23
  function bdsWorldLevelDir(bdsRoot, levelName) {
20
24
  return path.join(bdsWorldsDir(bdsRoot), levelName);
21
25
  }
26
+ function levelDatPath(bdsRoot, levelName) {
27
+ return path.join(bdsWorldLevelDir(bdsRoot, levelName), "level.dat");
28
+ }
22
29
  function worldPackListFile(worldsDir, levelName, kind) {
23
30
  const name = kind === "behavior" ? "world_behavior_packs.json" : "world_resource_packs.json";
24
31
  return path.join(worldsDir, levelName, name);
@@ -26,8 +33,11 @@ function worldPackListFile(worldsDir, levelName, kind) {
26
33
  function configPermissionPath(bdsRoot, bpUuid) {
27
34
  return path.join(bdsRoot, "config", bpUuid, "permission.json");
28
35
  }
36
+ function configPermissionsPath(bdsRoot, bpUuid) {
37
+ return path.join(bdsRoot, "config", bpUuid, "permissions.json");
38
+ }
29
39
  function hasConfigPermission(bdsRoot, bpUuid) {
30
- return fs.existsSync(configPermissionPath(bdsRoot, bpUuid));
40
+ return fs.existsSync(configPermissionsPath(bdsRoot, bpUuid)) || fs.existsSync(configPermissionPath(bdsRoot, bpUuid));
31
41
  }
32
42
  function randomUuid() {
33
43
  return crypto.randomUUID();
@@ -43,13 +53,17 @@ async function assembleBehaviorPack(opts) {
43
53
  await fs.promises.mkdir(path.join(opts.outDir, "scripts"), { recursive: true });
44
54
  await fs.promises.writeFile(path.join(opts.outDir, "scripts", "main.js"), "/* no scripts */\n", "utf8");
45
55
  }
46
- await writeBehaviorPackManifest(opts.outDir, {
47
- name: opts.projectName,
48
- uuid: bpUuid,
49
- version,
50
- description: opts.description,
51
- moduleUuid: opts.moduleUuid
52
- });
56
+ await writeBehaviorPackManifest(
57
+ opts.outDir,
58
+ {
59
+ name: opts.projectName,
60
+ uuid: bpUuid,
61
+ version,
62
+ description: opts.description,
63
+ moduleUuid: opts.moduleUuid
64
+ },
65
+ opts.dependencies
66
+ );
53
67
  if (opts.iconSrc && fs.existsSync(opts.iconSrc)) {
54
68
  await copyFileAsync(opts.iconSrc, path.join(opts.outDir, "pack_icon.png"));
55
69
  }
@@ -109,16 +123,42 @@ async function deployToBDS(opts) {
109
123
  }
110
124
  return { bpDir: bpDst, rpDir };
111
125
  }
112
- async function ensureConfigPermission(bdsRoot, bpUuid) {
113
- const file = configPermissionPath(bdsRoot, bpUuid);
114
- if (fs.existsSync(file)) return false;
115
- const dir = path.dirname(file);
116
- await fs.promises.mkdir(dir, { recursive: true });
117
- const payload = { allowed_modules: [...SFMC_PERMISSIONS] };
118
- const tmp = path.join(dir, `.permission.${process.pid}.tmp`);
119
- await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + "\n", "utf8");
120
- await fs.promises.rename(tmp, file);
121
- return true;
126
+ async function ensureConfigPermission(bdsRoot, bpUuid, moduleUuid) {
127
+ let changed = false;
128
+ const updateFile = async (filePath) => {
129
+ let currentModules = [];
130
+ let restConfig = {};
131
+ if (fs.existsSync(filePath)) {
132
+ try {
133
+ const raw = readJsonFile(filePath);
134
+ if (Array.isArray(raw.allowed_modules)) {
135
+ currentModules = raw.allowed_modules;
136
+ }
137
+ const { allowed_modules: _, ...rest } = raw;
138
+ restConfig = rest;
139
+ } catch {
140
+ }
141
+ }
142
+ const merged = Array.from(/* @__PURE__ */ new Set([...currentModules, ...SFMC_PERMISSIONS]));
143
+ if (merged.length === currentModules.length && fs.existsSync(filePath)) {
144
+ return false;
145
+ }
146
+ const dir = path.dirname(filePath);
147
+ await fs.promises.mkdir(dir, { recursive: true });
148
+ const payload = { allowed_modules: merged, ...restConfig };
149
+ const tmp = path.join(dir, `.permission.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`);
150
+ await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + "\n", "utf8");
151
+ await fs.promises.rename(tmp, filePath);
152
+ return true;
153
+ };
154
+ const uuids = Array.from(/* @__PURE__ */ new Set([bpUuid, ...moduleUuid ? [moduleUuid] : []]));
155
+ for (const u of uuids) {
156
+ if (await updateFile(configPermissionsPath(bdsRoot, u))) changed = true;
157
+ if (await updateFile(configPermissionPath(bdsRoot, u))) changed = true;
158
+ }
159
+ const defaultFile = path.join(bdsRoot, "config", "default", "permissions.json");
160
+ if (await updateFile(defaultFile)) changed = true;
161
+ return changed;
122
162
  }
123
163
  function readPackManifestHeader(packDir) {
124
164
  const file = path.join(packDir, "manifest.json");
@@ -135,6 +175,16 @@ function readPackManifestHeader(packDir) {
135
175
  return null;
136
176
  }
137
177
  }
178
+ function readPackManifestDependencies(packDir) {
179
+ const file = path.join(packDir, "manifest.json");
180
+ if (!fs.existsSync(file)) return [];
181
+ try {
182
+ const raw = readJsonFile(file);
183
+ return Array.isArray(raw.dependencies) ? raw.dependencies : [];
184
+ } catch {
185
+ return [];
186
+ }
187
+ }
138
188
  async function writePermissionsJson(bpDir) {
139
189
  const payload = { allowed_modules: [...SFMC_PERMISSIONS] };
140
190
  await fs.promises.mkdir(bpDir, { recursive: true });
@@ -164,7 +214,7 @@ async function editWorldPackList(opts, mode) {
164
214
  await fs.promises.writeFile(tmp, JSON.stringify(entries, null, 2) + "\n", "utf8");
165
215
  await fs.promises.rename(tmp, file);
166
216
  }
167
- async function writeBehaviorPackManifest(outDir, header) {
217
+ async function writeBehaviorPackManifest(outDir, header, dependencies) {
168
218
  const manifest = {
169
219
  format_version: 2,
170
220
  header: {
@@ -183,11 +233,7 @@ async function writeBehaviorPackManifest(outDir, header) {
183
233
  version: header.version
184
234
  }
185
235
  ],
186
- dependencies: [
187
- { module_name: "@minecraft/server", version: "1.18.0" },
188
- { module_name: "@minecraft/server-admin", version: "1.0.0-beta" },
189
- { module_name: "@minecraft/diagnostics", version: "1.0.0-beta" }
190
- ]
236
+ dependencies: dependencies && dependencies.length > 0 ? dependencies : BASELINE_BEDROCK_DEPENDENCIES
191
237
  };
192
238
  const file = path.join(outDir, "manifest.json");
193
239
  await fs.promises.mkdir(outDir, { recursive: true });
@@ -281,6 +327,7 @@ export {
281
327
  bdsWorldLevelDir,
282
328
  bdsWorldsDir,
283
329
  configPermissionPath,
330
+ configPermissionsPath,
284
331
  copyDirAsync,
285
332
  copyFileAsync,
286
333
  deployToBDS,
@@ -288,10 +335,12 @@ export {
288
335
  enablePackInWorld,
289
336
  ensureConfigPermission,
290
337
  hasConfigPermission,
338
+ levelDatPath,
291
339
  loadModuleResourcePackMap,
292
340
  randomUuid,
293
341
  readLevelName,
294
342
  readLevelNameSync,
343
+ readPackManifestDependencies,
295
344
  readPackManifestHeader,
296
345
  readWorldPackList,
297
346
  readWorldPackListResult,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/pack-manager.ts"],
4
- "sourcesContent": ["/**\n * pack-manager.ts \u2014 Bedrock \u884C\u4E3A\u5305/\u8D44\u6E90\u5305 \u88C5\u914D + \u90E8\u7F72\u5230 BDS \u6839\u3002\n *\n * \u7EAF\u51FD\u6570\u5E93,\u4E24\u6761\u6D88\u8D39\u8DEF\u5F84:\n *\n * - \u540C\u8FDB\u7A0B(\u63A8\u8350): sfmc/pack-lifecycle \u7ECF `@sfmc-bds/bds-tools/pack-manager-lib`\n * \u76F4\u8FDE\u672C\u6A21\u5757\uFF08DIP\uFF09\uFF1Bworld-packs \u7B49\u540C\u7406\u3002\n * - CLI: `cli-pack-manager.js` \u4ECD\u66B4\u9732\u76F8\u540C\u52A8\u8BCD\uFF0C\u4F9B\u5916\u90E8\u811A\u672C/\u624B\u5DE5\u8C03\u8BD5\uFF1B\n * CLI \u53EA\u662F\u672C\u5E93\u7684\u8584\u9002\u914D\uFF0C\u4E0D\u518D\u662F sfmc \u4E3B\u8DEF\u5F84\u3002\n *\n * \u7EA6\u675F:\u672C\u6587\u4EF6\u4E0D\u5F15\u5165 esbuild / \u91CD\u578B npm-only \u5305\uFF0C\u4FDD\u6301\u53EF\u88AB Node \u5B50\u8FDB\u7A0B\u76F4\u63A5\u52A0\u8F7D\u3002\n *\n * \u5DF2\u6709\u4F9D\u8D56 (bds-tools/package.json):\n * - @sfmc-bds/sdk/logs createTerminalProgress: \u8FDB\u5EA6\u6761\uFF08BDS \u66F4\u65B0\u7B49\uFF09\n * - node-html-parser: changelog \u6293\u53D6 (\u672C\u6587\u4EF6\u7528\u4E0D\u5230)\n * - jszip: zip \u89E3\u538B(\u6A21\u5757 zip / BDS server.zip)\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { copyDirAsync, copyFileAsync, readJsonFile } from \"./fsx.js\";\n\n/* \u2500\u2500 \u7C7B\u578B \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface AssembleBehaviorPackOpts {\n /** Where the bundled scripts/main.js already exists (esbuild output dir) */\n srcDir: string;\n /** Output behavior pack directory (created if missing) */\n outDir: string;\n /** BP \u76EE\u5F55\u540D \u2014 \u9ED8\u8BA4 'sfmc-modules' */\n projectName: string;\n /** manifest.json \u7684 header.version [major, minor, patch]; \u9ED8\u8BA4 [1, 0, 0] */\n version?: [number, number, number] | undefined;\n /** manifest.json \u7684 description */\n description?: string | undefined;\n /** pack_icon.png \u6E90\u6587\u4EF6 (optional, \u4E0D\u63D0\u4F9B\u5219\u8DF3\u8FC7) */\n iconSrc?: string | undefined;\n /** \u7A33\u5B9A header.uuid;\u7701\u7565\u5219\u968F\u673A\u751F\u6210(\u9996\u6B21\u88C5\u914D) */\n uuid?: string | undefined;\n /** \u7A33\u5B9A script module uuid;\u7701\u7565\u5219\u968F\u673A */\n moduleUuid?: string | undefined;\n}\n\nexport interface AssembleResourcePackOpts {\n /** Modules whose resource_pack/** should be merged. Map<moduleId, resourcePackDir>. */\n moduleResourceDirs: Record<string, string>;\n /** Output resource pack directory (created if missing) */\n outDir: string;\n /** RP \u76EE\u5F55\u540D */\n projectName: string;\n /** manifest.json \u7684 header.version [major, minor, patch]; \u9ED8\u8BA4 [1, 0, 0] */\n version?: [number, number, number] | undefined;\n /** manifest.json \u7684 description */\n description?: string | undefined;\n /** \u7A33\u5B9A header.uuid;\u7701\u7565\u5219\u968F\u673A\u751F\u6210(\u9996\u6B21\u88C5\u914D) */\n uuid?: string | undefined;\n /** \u7A33\u5B9A resources module uuid;\u7701\u7565\u5219\u968F\u673A */\n moduleUuid?: string | undefined;\n}\n\nexport interface AssembleResult {\n uuid: string;\n version: [number, number, number];\n}\n\nexport interface DeployOpts {\n bdsRoot: string;\n levelName: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 BP \u6E90\u76EE\u5F55 */\n behaviorPackSrc: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 RP \u6E90\u76EE\u5F55 (\u53EF\u7701\u7565,\u53EA\u7528 BP \u4E5F\u5408\u6CD5) */\n resourcePackSrc?: string;\n /** BP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/behavior_packs/<bpName>) */\n bpName: string;\n /** RP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/resource_packs/<rpName>);\u7701\u7565\u65F6\u590D\u7528 bpName + '-rp' */\n rpName?: string;\n /**\n * \u65E0 resourcePackSrc \u65F6\u662F\u5426\u5220\u9664\u4E16\u754C\u5185\u5DF2\u6709 RP \u76EE\u5F55\u3002\n * \u7528\u4E8E\u6A21\u5757\u4E0D\u518D\u63D0\u4F9B RP \u65F6\u6E05\u7406\u805A\u5408\u5305\u6B8B\u7559(\u9ED8\u8BA4 false,\u907F\u514D\u8BEF\u5220\u672A\u58F0\u660E\u7684 RP)\u3002\n */\n clearResourcePack?: boolean;\n}\n\nexport interface DeployResult {\n bpDir: string;\n rpDir: string | null;\n}\n\nexport interface EnablePackOpts {\n worldsDir: string;\n levelName: string;\n kind: \"behavior\" | \"resource\";\n packUuid: string;\n version: [number, number, number];\n}\n\n/* \u2500\u2500 \u8DEF\u5F84\u5E38\u91CF \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/** SFMC \u5408\u6210 BP \u7684\u56FA\u5B9A @minecraft/* permissions,\u6240\u6709\u7528\u5230\u7684\u547D\u540D\u7A7A\u95F4\u90FD\u6253\u5F00\u3002 */\nexport const SFMC_PERMISSIONS = [\n \"@minecraft/server\",\n \"@minecraft/server-ui\",\n \"@minecraft/server-admin\",\n \"@minecraft/server-gametest\",\n \"@minecraft/server-net\",\n \"@minecraft/server-editor\",\n \"@minecraft/diagnostics\",\n] as const;\n\n/** `<bdsRoot>/server.properties` \u2014 level-name / telemetry \u7B49\u5171\u7528\uFF08DRY\uFF09 */\nexport function serverPropertiesPath(bdsRoot: string): string {\n return path.join(bdsRoot, \"server.properties\");\n}\n\n/** `<bdsRoot>/worlds` \u2014 enable-list / \u90E8\u7F72\u8C03\u7528\u65B9\u52FF\u518D\u786C\u62FC\uFF08Demeter\uFF09 */\nexport function bdsWorldsDir(bdsRoot: string): string {\n return path.join(bdsRoot, \"worlds\");\n}\n\n/** `<bdsRoot>/worlds/<level>` */\nexport function bdsWorldLevelDir(bdsRoot: string, levelName: string): string {\n return path.join(bdsWorldsDir(bdsRoot), levelName);\n}\n\n/** \u4E16\u754C enable-list JSON \u7EDD\u5BF9\u8DEF\u5F84\uFF08\u5355\u4E00\u6743\u5A01\uFF0C\u4F9B\u8BFB\u5199\u4E24\u4FA7\uFF09 */\nexport function worldPackListFile(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): string {\n const name = kind === \"behavior\" ? \"world_behavior_packs.json\" : \"world_resource_packs.json\";\n return path.join(worldsDir, levelName, name);\n}\n\n/** `<bdsRoot>/config/<bpUuid>/permission.json` \u2014 Script API \u6743\u9650\u6587\u4EF6\u6743\u5A01\u8DEF\u5F84 */\nexport function configPermissionPath(bdsRoot: string, bpUuid: string): string {\n return path.join(bdsRoot, \"config\", bpUuid, \"permission.json\");\n}\n\n/** \u662F\u5426\u5DF2\u6709 Script API permission.json\uFF08\u53EA\u8BFB\uFF0C\u4F9B preflight/status\uFF09 */\nexport function hasConfigPermission(bdsRoot: string, bpUuid: string): boolean {\n return fs.existsSync(configPermissionPath(bdsRoot, bpUuid));\n}\n\n/** \u968F\u673A\u751F\u6210 BP/RP manifest.json header.uuid (RFC 4122 v4) */\nexport function randomUuid(): string {\n /* crypto.randomUUID \u662F Node 19+ \u5185\u7F6E,\u8FD9\u91CC\u76F4\u63A5\u7528 */\n return crypto.randomUUID();\n}\n\n/* \u2500\u2500 \u9AA8\u67B6\u51FD\u6570 (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Assemble a Bedrock behavior pack directory at `outDir` from a prebuilt\n * `srcDir` (which must already contain `scripts/main.js` plus whatever else\n * was bundled by esbuild) and write a fresh `manifest.json` + `permissions.json`.\n *\n * The caller is responsible for running esbuild first; pack-manager does not\n * bundle scripts. That decoupling keeps pack assembly independent of the bundler.\n */\nexport async function assembleBehaviorPack(opts: AssembleBehaviorPackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const bpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n if (fs.existsSync(opts.srcDir)) {\n await copyDirAsync(opts.srcDir, opts.outDir);\n } else {\n await fs.promises.mkdir(path.join(opts.outDir, \"scripts\"), { recursive: true });\n await fs.promises.writeFile(path.join(opts.outDir, \"scripts\", \"main.js\"), \"/* no scripts */\\n\", \"utf8\");\n }\n await writeBehaviorPackManifest(opts.outDir, {\n name: opts.projectName,\n uuid: bpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n });\n if (opts.iconSrc && fs.existsSync(opts.iconSrc)) {\n await copyFileAsync(opts.iconSrc, path.join(opts.outDir, \"pack_icon.png\"));\n }\n await writePermissionsJson(opts.outDir);\n return { uuid: bpUuid, version };\n}\n\n/**\n * Merge every enabled module's `resource_pack/**` tree into one RP directory\n * at `outDir`, with a single fresh `manifest.json`. Per-module subfolders are\n * preserved so resource pack authors can disambiguate (e.g. `peace/textures/...`).\n */\nexport async function assembleResourcePack(opts: AssembleResourcePackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const rpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n for (const [moduleId, rpDir] of Object.entries(opts.moduleResourceDirs)) {\n if (!fs.existsSync(rpDir)) continue;\n const dst = path.join(opts.outDir, moduleId);\n await fs.promises.mkdir(dst, { recursive: true });\n await copyDirAsync(rpDir, dst);\n }\n await writeResourcePackManifest(opts.outDir, {\n name: opts.projectName,\n uuid: rpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n });\n return { uuid: rpUuid, version };\n}\n\n/**\n * Read the `level-name=` value from `<bdsRoot>/server.properties`.\n * Falls back to \"Bedrock level\" (BDS default) when the file is missing or\n * the key is absent.\n */\nfunction parseLevelNameFromProperties(text: string): string {\n for (const line of text.split(/\\r?\\n/)) {\n const m = /^\\s*level-name\\s*=\\s*(.+?)\\s*$/.exec(line);\n if (m && m[1]) return m[1];\n }\n return \"Bedrock level\";\n}\n\n/** \u540C\u6B65\u8BFB level-name\uFF08\u4F9B sfmc resolveBdsContext \u7B49\u540C\u8FDB\u7A0B\u8C03\u7528\u65B9\uFF0CDRY\uFF09\u3002 */\nexport function readLevelNameSync(bdsRoot: string): string {\n const file = serverPropertiesPath(bdsRoot);\n if (!fs.existsSync(file)) return \"Bedrock level\";\n return parseLevelNameFromProperties(fs.readFileSync(file, \"utf8\"));\n}\n\n/** \u4E0E sync \u540C\u5951\u7EA6\uFF1BCLI / async \u8C03\u7528\u65B9\u8D70\u6B64\u5165\u53E3\uFF08LSP\uFF09 */\nexport async function readLevelName(bdsRoot: string): Promise<string> {\n return readLevelNameSync(bdsRoot);\n}\n\n/**\n * Copy BP/RP source dirs into the world's behavior_packs/ + resource_packs/\n * folders, and write a fresh `permissions.json` into the BP target.\n *\n * Does NOT edit world_behavior_packs.json \u2014 that's a separate step the caller\n * must invoke after restart, because BDS only reads that file at startup.\n */\nexport async function deployToBDS(opts: DeployOpts): Promise<DeployResult> {\n /* levelDir = worlds/<level>\uFF1B\u4E0E EnablePackOpts.worldsDir(=worlds/) \u8BED\u4E49\u4E0D\u540C \u2014 \u52FF\u6DF7\u7528\uFF08LSP\uFF09 */\n const levelDir = bdsWorldLevelDir(opts.bdsRoot, opts.levelName);\n const bpDst = path.join(levelDir, \"behavior_packs\", opts.bpName);\n const rpDst = path.join(levelDir, \"resource_packs\", opts.rpName ?? `${opts.bpName}-rp`);\n await fs.promises.mkdir(levelDir, { recursive: true });\n await fs.promises.rm(bpDst, { recursive: true, force: true });\n await copyDirAsync(opts.behaviorPackSrc, bpDst);\n await writePermissionsJson(bpDst);\n let rpDir: string | null = null;\n if (opts.resourcePackSrc && fs.existsSync(opts.resourcePackSrc)) {\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n await copyDirAsync(opts.resourcePackSrc, rpDst);\n rpDir = rpDst;\n } else if (opts.clearResourcePack) {\n /* \u8C03\u7528\u65B9\u663E\u5F0F\u58F0\u660E\u4E0D\u518D\u90E8\u7F72 RP \u2014 \u6E05\u6389\u805A\u5408 RP \u76EE\u5F55\u6B8B\u7559 */\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n }\n return { bpDir: bpDst, rpDir };\n}\n\n/**\n * \u786E\u4FDD BDS Script API \u4FA7 `<bdsRoot>/config/<bpUuid>/permission.json` \u5B58\u5728\u3002\n * \u5DF2\u5B58\u5728\u5219\u8DF3\u8FC7(\u4E0D\u8986\u76D6\u7528\u6237\u624B\u5DE5\u6539\u52A8)\u3002\n * @returns true = \u65B0\u5199\u5165; false = \u5DF2\u5B58\u5728\u8DF3\u8FC7\n */\nexport async function ensureConfigPermission(bdsRoot: string, bpUuid: string): Promise<boolean> {\n const file = configPermissionPath(bdsRoot, bpUuid);\n if (fs.existsSync(file)) return false;\n const dir = path.dirname(file);\n await fs.promises.mkdir(dir, { recursive: true });\n const payload = { allowed_modules: [...SFMC_PERMISSIONS] };\n const tmp = path.join(dir, `.permission.${process.pid}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, file);\n return true;\n}\n\n/** \u4ECE\u5DF2\u88C5\u914D BP/RP \u76EE\u5F55\u8BFB\u53D6 header.uuid + version;\u5931\u8D25\u8FD4\u56DE null\u3002 */\nexport function readPackManifestHeader(\n packDir: string\n): { uuid: string; version: [number, number, number]; moduleUuid?: string } | null {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return null;\n try {\n const raw = readJsonFile<{\n header?: { uuid?: string; version?: number[] };\n modules?: Array<{ uuid?: string }>;\n }>(file);\n const uuid = raw.header?.uuid;\n const ver = raw.header?.version;\n if (typeof uuid !== \"string\" || !Array.isArray(ver) || ver.length < 3) return null;\n const version: [number, number, number] = [Number(ver[0]), Number(ver[1]), Number(ver[2])];\n const moduleUuid = raw.modules?.[0]?.uuid;\n return { uuid, version, ...(typeof moduleUuid === \"string\" ? { moduleUuid } : {}) };\n } catch {\n return null;\n }\n}\n\n/**\n * Write `@minecraft/*` allowed_modules into a behavior pack's\n * `permissions.json`. Idempotent: rewrites any pre-existing file.\n */\nexport async function writePermissionsJson(bpDir: string): Promise<void> {\n const payload = { allowed_modules: [...SFMC_PERMISSIONS] };\n await fs.promises.mkdir(bpDir, { recursive: true });\n const tmp = path.join(bpDir, `.permissions.${process.pid}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, path.join(bpDir, \"permissions.json\"));\n}\n\n/**\n * Add `{ pack_id, version }` to `worlds/<level>/world_behavior_packs.json`\n * (or `world_resource_packs.json`). If the pack_id already exists, replace its\n * version. File missing \u2192 initialize as `[]`.\n */\nexport async function enablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"enable\");\n}\n\n/** Remove a pack_id from the world's enable-list JSON. */\nexport async function disablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"disable\");\n}\n\ninterface WorldPackEntry {\n pack_id: string;\n version: [number, number, number];\n}\n\nasync function editWorldPackList(\n opts: EnablePackOpts,\n mode: \"enable\" | \"disable\"\n): Promise<void> {\n const file = worldPackListFile(opts.worldsDir, opts.levelName, opts.kind);\n /* \u4E0E readWorldPackList \u540C\u6E90\u89E3\u6790,\u518D\u5199\u56DE(DRY);\u5F02\u6B65\u5199\u8DEF\u5F84\u4FDD\u7559\u539F\u8BED\u4E49 */\n let entries: WorldPackEntry[] = readWorldPackList(opts.worldsDir, opts.levelName, opts.kind);\n const idx = entries.findIndex((e) => e.pack_id === opts.packUuid);\n if (mode === \"enable\") {\n const next: WorldPackEntry = { pack_id: opts.packUuid, version: opts.version };\n if (idx >= 0) entries[idx] = next;\n else entries.push(next);\n } else {\n if (idx >= 0) entries.splice(idx, 1);\n }\n await fs.promises.mkdir(path.dirname(file), { recursive: true });\n const tmp = `${file}.${process.pid}.tmp`;\n await fs.promises.writeFile(tmp, JSON.stringify(entries, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, file);\n}\n\n/* \u2500\u2500 \u4F4E\u5C42 helpers (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport async function writeBehaviorPackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n }\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (behavior pack)` : \"SFMC behavior pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"script\",\n language: \"javascript\",\n entry: \"scripts/main.js\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n dependencies: [\n { module_name: \"@minecraft/server\", version: \"1.18.0\" },\n { module_name: \"@minecraft/server-admin\", version: \"1.0.0-beta\" },\n { module_name: \"@minecraft/diagnostics\", version: \"1.0.0-beta\" },\n ],\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\nexport async function writeResourcePackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n }\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (resource pack)` : \"SFMC resource pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"resources\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\n/* Re-export copyFileAsync so callers can copy icon without\n * pulling in the full fsx surface area. */\nexport { copyFileAsync, copyDirAsync };\n\n/* \u2500\u2500 Discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Walk `<modulesDir>/<id>/resource_pack/` for every installed module and\n * return a map { id: absoluteDir }. Modules without a resource_pack folder\n * are silently skipped. Used by `assemble-rp` and the sfmc CLI to know which\n * modules to merge into the resource pack output.\n */\nexport function scanModuleResourcePacks(modulesDir: string): Record<string, string> {\n const out: Record<string, string> = {};\n if (!fs.existsSync(modulesDir)) return out;\n for (const entry of fs.readdirSync(modulesDir, { withFileTypes: true })) {\n if (entry.name.startsWith(\".\")) continue;\n // \u8DDF\u968F symlink\uFF08--link \u5B89\u88C5\uFF09\uFF1BDirent.isDirectory() \u5BF9\u94FE\u63A5\u76EE\u5F55\u4E3A false\n try {\n if (!fs.statSync(path.join(modulesDir, entry.name)).isDirectory()) continue;\n } catch {\n continue;\n }\n const rpDir = path.join(modulesDir, entry.name, \"resource_pack\");\n if (fs.existsSync(rpDir)) {\n out[entry.name] = rpDir;\n }\n }\n return out;\n}\n\n/**\n * \u4ECE JSON \u6587\u4EF6\u52A0\u8F7D\u663E\u5F0F moduleId \u2192 resource_pack \u76EE\u5F55\u6620\u5C04\u3002\n * \u4F9B assemble-rp --modules-json \u4F7F\u7528,\u907F\u514D\u8C03\u7528\u65B9\u518D\u505A\u4E34\u65F6\u76EE\u5F55\u955C\u50CF(OCP/DRY)\u3002\n */\nexport function loadModuleResourcePackMap(jsonPath: string): Record<string, string> {\n const raw = JSON.parse(fs.readFileSync(jsonPath, \"utf8\")) as unknown;\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n throw new Error(`modules-json must be an object: ${jsonPath}`);\n }\n const out: Record<string, string> = {};\n for (const [id, dir] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof id !== \"string\" || !id || typeof dir !== \"string\" || !dir) continue;\n const abs = path.resolve(dir);\n if (!fs.existsSync(abs)) {\n throw new Error(`modules-json entry missing: ${id} \u2192 ${abs}`);\n }\n out[id] = abs;\n }\n return out;\n}\n\n/**\n * \u8BFB\u53D6\u4E16\u754C enable-list(\u5355\u4E00\u6743\u5A01,\u4F9B has-pack / list-packs / \u8C03\u7528\u65B9\u590D\u7528 \u2014 DRY)\u3002\n * \u6587\u4EF6\u7F3A\u5931 \u2192 entries=[]\uFF1BJSON \u635F\u574F \u2192 entries=[] \u4E14 parseFailedFile \u6709\u503C\uFF08\u4F9B doctor \u533A\u5206\uFF09\u3002\n */\nexport type WorldPackListReadResult = {\n entries: Array<{ pack_id: string; version: [number, number, number] }>;\n /** \u6587\u4EF6\u5B58\u5728\u4F46\u89E3\u6790\u5931\u8D25\u65F6\u4E3A\u8BE5 JSON \u7EDD\u5BF9\u8DEF\u5F84 */\n parseFailedFile?: string;\n};\n\nexport function readWorldPackListResult(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): WorldPackListReadResult {\n const file = worldPackListFile(worldsDir, levelName, kind);\n if (!fs.existsSync(file)) return { entries: [] };\n try {\n const arr = JSON.parse(fs.readFileSync(file, \"utf8\")) as unknown;\n if (!Array.isArray(arr)) return { entries: [], parseFailedFile: file };\n const out: Array<{ pack_id: string; version: [number, number, number] }> = [];\n for (const e of arr) {\n if (!e || typeof e !== \"object\") continue;\n const packId = (e as { pack_id?: unknown }).pack_id;\n const ver = (e as { version?: unknown }).version;\n if (typeof packId !== \"string\" || !packId) continue;\n const version: [number, number, number] =\n Array.isArray(ver) && ver.length >= 3\n ? [Number(ver[0]), Number(ver[1]), Number(ver[2])]\n : [1, 0, 0];\n out.push({ pack_id: packId, version });\n }\n return { entries: out };\n } catch {\n return { entries: [], parseFailedFile: file };\n }\n}\n\n/** \u517C\u5BB9\u8BFB\u4FA7\uFF1A\u53EA\u8981 entries\uFF08\u635F\u574F\u65F6\u4E0E\u7F3A\u5931\u540C\u4E3A []\uFF09\u3002\u8BE6\u7EC6\u7ED3\u679C\u89C1 readWorldPackListResult\u3002 */\nexport function readWorldPackList(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): Array<{ pack_id: string; version: [number, number, number] }> {\n return readWorldPackListResult(worldsDir, levelName, kind).entries;\n}\n\n/** \u4E16\u754C enable-list \u662F\u5426\u5DF2\u542B\u6307\u5B9A pack_id(\u53EA\u8BFB,\u4F9B preflight \u590D\u7528)\u3002 */\nexport function worldPackListHas(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\",\n packUuid: string\n): boolean {\n return readWorldPackList(worldsDir, levelName, kind).some((e) => e.pack_id === packUuid);\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * pack-manager.ts \u2014 Bedrock \u884C\u4E3A\u5305\uFF08BP\uFF09\u4E0E\u8D44\u6E90\u5305\uFF08RP\uFF09\u7EC4\u88C5\u53CA\u90E8\u7F72\u5F15\u64CE\n *\n * \u6838\u5FC3\u8BBE\u8BA1\u4E0E\u8C03\u7528\u8DEF\u5F84\uFF1A\n * - \u8FDB\u7A0B\u5185\u76F4\u8FDE\uFF08\u63A8\u8350\uFF09\uFF1A`@sfmc-bds/bds-tools/pack-manager-lib` \u4F9B CLI \u7F16\u6392\u4E0E\u751F\u547D\u5468\u671F\u7BA1\u7406\u76F4\u63A5\u8C03\u7528\uFF08\u9075\u5FAA\u4F9D\u8D56\u5012\u7F6E\u539F\u5219\uFF09\n * - \u72EC\u7ACB CLI\uFF1A\u7531 `cli-pack-manager.ts` \u66B4\u9732\u547D\u4EE4\u884C\u5B50\u547D\u4EE4\u4F9B\u811A\u672C\u4E0E\u624B\u5DE5\u8C03\u8BD5\u4F7F\u7528\n *\n * \u6838\u5FC3\u80FD\u529B\uFF1A\n * - \u884C\u4E3A\u5305\u7EC4\u88C5\uFF1A\u5C06 esbuild \u6253\u5305\u540E\u7684 `scripts/main.js`\u3001\u5143\u6570\u636E manifest \u4E0E\u56FE\u6807\u5C01\u88C5\u4E3A BDS \u884C\u4E3A\u5305\u7ED3\u6784\n * - \u8D44\u6E90\u5305\u805A\u5408\uFF1A\u5C06\u5404\u6A21\u5757\u79C1\u6709\u7684 `resource_pack` \u76EE\u5F55\u65E0\u51B2\u7A81\u9012\u5F52\u5408\u5E76\u4E3A\u805A\u5408\u8D44\u6E90\u5305\n * - \u4E16\u754C\u90E8\u7F72\u4E0E\u6E05\u5355\u6FC0\u6D3B\uFF1A\u5C06\u5305\u90E8\u7F72\u81F3 BDS `<level>/behavior_packs` \u4E0E `resource_packs`\uFF0C\u5E76\u540C\u6B65\u7EF4\u62A4 `world_behavior_packs.json`\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { copyDirAsync, copyFileAsync, readJsonFile } from \"./fsx.js\";\nimport {\n BASELINE_BEDROCK_DEPENDENCIES,\n type PackManifestDependency,\n} from \"./dependency-negotiator.js\";\nexport * from \"./dependency-negotiator.js\";\n\n/* \u2500\u2500 \u7C7B\u578B\u5B9A\u4E49 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface AssembleBehaviorPackOpts {\n /** \u5DF2\u5B8C\u6210\u6253\u5305\u7684 `scripts/main.js` \u6240\u5728\u6E90\u7801\u76EE\u5F55\uFF08\u5373 esbuild \u8F93\u51FA\u76EE\u5F55\uFF09\u3002 */\n srcDir: string;\n /** \u884C\u4E3A\u5305\u76EE\u6807\u8F93\u51FA\u76EE\u5F55\uFF08\u82E5\u4E0D\u5B58\u5728\u5219\u81EA\u52A8\u521B\u5EFA\uFF09\u3002 */\n outDir: string;\n /** BP \u9879\u76EE/\u76EE\u5F55\u540D\uFF08\u9ED8\u8BA4\u4E3A `'sfmc-modules'`\uFF09\u3002 */\n projectName: string;\n /** `manifest.json` \u4E2D\u7684 `header.version` `[major, minor, patch]`\uFF08\u9ED8\u8BA4\u4E3A `[1, 0, 0]`\uFF09\u3002 */\n version?: [number, number, number] | undefined;\n /** `manifest.json` \u4E2D\u7684\u5305\u63CF\u8FF0\u4FE1\u606F\u3002 */\n description?: string | undefined;\n /** `pack_icon.png` \u56FE\u6807\u6E90\u6587\u4EF6\u8DEF\u5F84\uFF08\u53EF\u9009\uFF0C\u672A\u63D0\u4F9B\u5219\u8DF3\u8FC7\uFF09\u3002 */\n iconSrc?: string | undefined;\n /** \u7A33\u5B9A\u7684 `header.uuid`\uFF08\u7F3A\u7701\u65F6\u5C06\u5728\u9996\u6B21\u88C5\u914D\u65F6\u968F\u673A\u751F\u6210\uFF09\u3002 */\n uuid?: string | undefined;\n /** \u7A33\u5B9A\u7684 `script module uuid`\uFF08\u7F3A\u7701\u65F6\u968F\u673A\u751F\u6210\uFF09\u3002 */\n moduleUuid?: string | undefined;\n /** \u81EA\u5B9A\u4E49/\u52A8\u6001\u534F\u5546\u540E\u7684 dependencies\uFF08\u7F3A\u7701\u4F7F\u7528 BASELINE_BEDROCK_DEPENDENCIES\uFF09\u3002 */\n dependencies?: PackManifestDependency[] | undefined;\n}\n\nexport interface AssembleResourcePackOpts {\n /** \u9700\u5408\u5E76\u8D44\u6E90\u5305\u76EE\u5F55\u7684\u6A21\u5757\u6620\u5C04\u5B57\u5178\uFF08`Record<moduleId, resourcePackDir>`\uFF09\u3002 */\n moduleResourceDirs: Record<string, string>;\n /** \u8D44\u6E90\u5305\u76EE\u6807\u8F93\u51FA\u76EE\u5F55\uFF08\u82E5\u4E0D\u5B58\u5728\u5219\u81EA\u52A8\u521B\u5EFA\uFF09\u3002 */\n outDir: string;\n /** RP \u9879\u76EE/\u76EE\u5F55\u540D\u3002 */\n projectName: string;\n /** `manifest.json` \u4E2D\u7684 `header.version` `[major, minor, patch]`\uFF08\u9ED8\u8BA4\u4E3A `[1, 0, 0]`\uFF09\u3002 */\n version?: [number, number, number] | undefined;\n /** `manifest.json` \u4E2D\u7684\u5305\u63CF\u8FF0\u4FE1\u606F\u3002 */\n description?: string | undefined;\n /** \u7A33\u5B9A\u7684 `header.uuid`\uFF08\u7F3A\u7701\u65F6\u968F\u673A\u751F\u6210\uFF09\u3002 */\n uuid?: string | undefined;\n /** \u7A33\u5B9A\u7684 `resources module uuid`\uFF08\u7F3A\u7701\u65F6\u968F\u673A\u751F\u6210\uFF09\u3002 */\n moduleUuid?: string | undefined;\n}\n\n\nexport interface AssembleResult {\n uuid: string;\n version: [number, number, number];\n}\n\nexport interface DeployOpts {\n bdsRoot: string;\n levelName: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 BP \u6E90\u76EE\u5F55 */\n behaviorPackSrc: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 RP \u6E90\u76EE\u5F55 (\u53EF\u7701\u7565,\u53EA\u7528 BP \u4E5F\u5408\u6CD5) */\n resourcePackSrc?: string;\n /** BP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/behavior_packs/<bpName>) */\n bpName: string;\n /** RP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/resource_packs/<rpName>);\u7701\u7565\u65F6\u590D\u7528 bpName + '-rp' */\n rpName?: string;\n /**\n * \u65E0 resourcePackSrc \u65F6\u662F\u5426\u5220\u9664\u4E16\u754C\u5185\u5DF2\u6709 RP \u76EE\u5F55\u3002\n * \u7528\u4E8E\u6A21\u5757\u4E0D\u518D\u63D0\u4F9B RP \u65F6\u6E05\u7406\u805A\u5408\u5305\u6B8B\u7559(\u9ED8\u8BA4 false,\u907F\u514D\u8BEF\u5220\u672A\u58F0\u660E\u7684 RP)\u3002\n */\n clearResourcePack?: boolean;\n}\n\nexport interface DeployResult {\n bpDir: string;\n rpDir: string | null;\n}\n\nexport interface EnablePackOpts {\n worldsDir: string;\n levelName: string;\n kind: \"behavior\" | \"resource\";\n packUuid: string;\n version: [number, number, number];\n}\n\n/* \u2500\u2500 \u8DEF\u5F84\u5E38\u91CF \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/** SFMC \u5408\u6210 BP \u7684\u56FA\u5B9A @minecraft/* permissions,\u6240\u6709\u7528\u5230\u7684\u547D\u540D\u7A7A\u95F4\u90FD\u6253\u5F00\u3002 */\nexport const SFMC_PERMISSIONS = [\n \"@minecraft/server\",\n \"@minecraft/server-ui\",\n \"@minecraft/server-admin\",\n \"@minecraft/server-gametest\",\n \"@minecraft/server-net\",\n \"@minecraft/server-editor\",\n \"@minecraft/diagnostics\",\n] as const;\n\n/** `<bdsRoot>/server.properties` \u2014 level-name / telemetry \u7B49\u5171\u7528\uFF08DRY\uFF09 */\nexport function serverPropertiesPath(bdsRoot: string): string {\n return path.join(bdsRoot, \"server.properties\");\n}\n\n/** `<bdsRoot>/worlds` \u2014 enable-list / \u90E8\u7F72\u8C03\u7528\u65B9\u52FF\u518D\u786C\u62FC\uFF08Demeter\uFF09 */\nexport function bdsWorldsDir(bdsRoot: string): string {\n return path.join(bdsRoot, \"worlds\");\n}\n\n/** `<bdsRoot>/worlds/<level>` */\nexport function bdsWorldLevelDir(bdsRoot: string, levelName: string): string {\n return path.join(bdsWorldsDir(bdsRoot), levelName);\n}\n\n/** `<bdsRoot>/worlds/<level>/level.dat` \u2014 \u4E16\u754C\u5B58\u6863\u6743\u5A01\u8DEF\u5F84 */\nexport function levelDatPath(bdsRoot: string, levelName: string): string {\n return path.join(bdsWorldLevelDir(bdsRoot, levelName), \"level.dat\");\n}\n\n/** \u4E16\u754C enable-list JSON \u7EDD\u5BF9\u8DEF\u5F84\uFF08\u5355\u4E00\u6743\u5A01\uFF0C\u4F9B\u8BFB\u5199\u4E24\u4FA7\uFF09 */\nexport function worldPackListFile(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): string {\n const name = kind === \"behavior\" ? \"world_behavior_packs.json\" : \"world_resource_packs.json\";\n return path.join(worldsDir, levelName, name);\n}\n\n/** `<bdsRoot>/config/<bpUuid>/permission.json` \u2014 Script API \u6743\u9650\u6587\u4EF6\u6743\u5A01\u8DEF\u5F84 */\nexport function configPermissionPath(bdsRoot: string, bpUuid: string): string {\n return path.join(bdsRoot, \"config\", bpUuid, \"permission.json\");\n}\n\n/** `<bdsRoot>/config/<bpUuid>/permissions.json` \u2014 BDS \u5B98\u65B9\u89C4\u8303\u590D\u6570\u6743\u9650\u6587\u4EF6\u8DEF\u5F84 */\nexport function configPermissionsPath(bdsRoot: string, bpUuid: string): string {\n return path.join(bdsRoot, \"config\", bpUuid, \"permissions.json\");\n}\n\n/** \u662F\u5426\u5DF2\u6709 Script API permission.json \u6216 permissions.json\uFF08\u53EA\u8BFB\uFF0C\u4F9B preflight/status\uFF09 */\nexport function hasConfigPermission(bdsRoot: string, bpUuid: string): boolean {\n return fs.existsSync(configPermissionsPath(bdsRoot, bpUuid)) || fs.existsSync(configPermissionPath(bdsRoot, bpUuid));\n}\n\n/** \u968F\u673A\u751F\u6210 BP/RP manifest.json header.uuid (RFC 4122 v4) */\nexport function randomUuid(): string {\n /* crypto.randomUUID \u662F Node 19+ \u5185\u7F6E,\u8FD9\u91CC\u76F4\u63A5\u7528 */\n return crypto.randomUUID();\n}\n\n/* \u2500\u2500 \u9AA8\u67B6\u51FD\u6570 (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Assemble a Bedrock behavior pack directory at `outDir` from a prebuilt\n * `srcDir` (which must already contain `scripts/main.js` plus whatever else\n * was bundled by esbuild) and write a fresh `manifest.json` + `permissions.json`.\n *\n * The caller is responsible for running esbuild first; pack-manager does not\n * bundle scripts. That decoupling keeps pack assembly independent of the bundler.\n */\nexport async function assembleBehaviorPack(opts: AssembleBehaviorPackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const bpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n if (fs.existsSync(opts.srcDir)) {\n await copyDirAsync(opts.srcDir, opts.outDir);\n } else {\n await fs.promises.mkdir(path.join(opts.outDir, \"scripts\"), { recursive: true });\n await fs.promises.writeFile(path.join(opts.outDir, \"scripts\", \"main.js\"), \"/* no scripts */\\n\", \"utf8\");\n }\n await writeBehaviorPackManifest(\n opts.outDir,\n {\n name: opts.projectName,\n uuid: bpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n },\n opts.dependencies\n );\n if (opts.iconSrc && fs.existsSync(opts.iconSrc)) {\n await copyFileAsync(opts.iconSrc, path.join(opts.outDir, \"pack_icon.png\"));\n }\n await writePermissionsJson(opts.outDir);\n return { uuid: bpUuid, version };\n}\n\n/**\n * Merge every enabled module's `resource_pack/**` tree into one RP directory\n * at `outDir`, with a single fresh `manifest.json`. Per-module subfolders are\n * preserved so resource pack authors can disambiguate (e.g. `peace/textures/...`).\n */\nexport async function assembleResourcePack(opts: AssembleResourcePackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const rpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n for (const [moduleId, rpDir] of Object.entries(opts.moduleResourceDirs)) {\n if (!fs.existsSync(rpDir)) continue;\n const dst = path.join(opts.outDir, moduleId);\n await fs.promises.mkdir(dst, { recursive: true });\n await copyDirAsync(rpDir, dst);\n }\n await writeResourcePackManifest(opts.outDir, {\n name: opts.projectName,\n uuid: rpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n });\n return { uuid: rpUuid, version };\n}\n\n/**\n * Read the `level-name=` value from `<bdsRoot>/server.properties`.\n * Falls back to \"Bedrock level\" (BDS default) when the file is missing or\n * the key is absent.\n */\nfunction parseLevelNameFromProperties(text: string): string {\n for (const line of text.split(/\\r?\\n/)) {\n const m = /^\\s*level-name\\s*=\\s*(.+?)\\s*$/.exec(line);\n if (m && m[1]) return m[1];\n }\n return \"Bedrock level\";\n}\n\n/** \u540C\u6B65\u8BFB level-name\uFF08\u4F9B sfmc resolveBdsContext \u7B49\u540C\u8FDB\u7A0B\u8C03\u7528\u65B9\uFF0CDRY\uFF09\u3002 */\nexport function readLevelNameSync(bdsRoot: string): string {\n const file = serverPropertiesPath(bdsRoot);\n if (!fs.existsSync(file)) return \"Bedrock level\";\n return parseLevelNameFromProperties(fs.readFileSync(file, \"utf8\"));\n}\n\n/** \u4E0E sync \u540C\u5951\u7EA6\uFF1BCLI / async \u8C03\u7528\u65B9\u8D70\u6B64\u5165\u53E3\uFF08LSP\uFF09 */\nexport async function readLevelName(bdsRoot: string): Promise<string> {\n return readLevelNameSync(bdsRoot);\n}\n\n/**\n * Copy BP/RP source dirs into the world's behavior_packs/ + resource_packs/\n * folders, and write a fresh `permissions.json` into the BP target.\n *\n * Does NOT edit world_behavior_packs.json \u2014 that's a separate step the caller\n * must invoke after restart, because BDS only reads that file at startup.\n */\nexport async function deployToBDS(opts: DeployOpts): Promise<DeployResult> {\n /* levelDir = worlds/<level>\uFF1B\u4E0E EnablePackOpts.worldsDir(=worlds/) \u8BED\u4E49\u4E0D\u540C \u2014 \u52FF\u6DF7\u7528\uFF08LSP\uFF09 */\n const levelDir = bdsWorldLevelDir(opts.bdsRoot, opts.levelName);\n const bpDst = path.join(levelDir, \"behavior_packs\", opts.bpName);\n const rpDst = path.join(levelDir, \"resource_packs\", opts.rpName ?? `${opts.bpName}-rp`);\n await fs.promises.mkdir(levelDir, { recursive: true });\n await fs.promises.rm(bpDst, { recursive: true, force: true });\n await copyDirAsync(opts.behaviorPackSrc, bpDst);\n await writePermissionsJson(bpDst);\n let rpDir: string | null = null;\n if (opts.resourcePackSrc && fs.existsSync(opts.resourcePackSrc)) {\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n await copyDirAsync(opts.resourcePackSrc, rpDst);\n rpDir = rpDst;\n } else if (opts.clearResourcePack) {\n /* \u8C03\u7528\u65B9\u663E\u5F0F\u58F0\u660E\u4E0D\u518D\u90E8\u7F72 RP \u2014 \u6E05\u6389\u805A\u5408 RP \u76EE\u5F55\u6B8B\u7559 */\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n }\n return { bpDir: bpDst, rpDir };\n}\n\n/**\n * \u786E\u4FDD BDS Script API \u4FA7\u6743\u9650\u6587\u4EF6\u5B58\u5728\u5E76\u5305\u542B\u5B8C\u6574\u7684 SFMC \u6240\u9700\u6A21\u5757\u6743\u9650\u3002\n * - \u81EA\u52A8\u589E\u91CF\u5408\u5E76\u73B0\u6709 allowed_modules\uFF0C\u81EA\u52A8\u8865\u9F50\u65B0\u589E\u6743\u9650\uFF08\u5982 @minecraft/diagnostics\uFF09\n * - \u540C\u65F6\u7EF4\u62A4 BDS \u5B98\u65B9\u89C4\u8303\u7684 permissions.json \u4E0E\u5386\u53F2\u517C\u5BB9\u7684 permission.json\n * - \u540C\u65F6\u66F4\u65B0 moduleUuid\uFF08\u82E5\u63D0\u4F9B\uFF09\u4E0E config/default/permissions.json \u515C\u5E95\u6743\u9650\n * @returns true = \u6709\u65B0\u589E/\u66F4\u65B0; false = \u5DF2\u662F\u6700\u65B0\u65E0\u9700\u4FEE\u6539\n */\nexport async function ensureConfigPermission(\n bdsRoot: string,\n bpUuid: string,\n moduleUuid?: string\n): Promise<boolean> {\n let changed = false;\n\n const updateFile = async (filePath: string): Promise<boolean> => {\n let currentModules: string[] = [];\n let restConfig: Record<string, unknown> = {};\n if (fs.existsSync(filePath)) {\n try {\n const raw = readJsonFile<{ allowed_modules?: string[]; [k: string]: unknown }>(filePath);\n if (Array.isArray(raw.allowed_modules)) {\n currentModules = raw.allowed_modules;\n }\n const { allowed_modules: _, ...rest } = raw;\n restConfig = rest;\n } catch {\n // \u6587\u4EF6\u635F\u574F\u5219\u6309\u5168\u65B0\u5199\u5165\n }\n }\n const merged = Array.from(new Set([...currentModules, ...SFMC_PERMISSIONS]));\n if (merged.length === currentModules.length && fs.existsSync(filePath)) {\n return false;\n }\n const dir = path.dirname(filePath);\n await fs.promises.mkdir(dir, { recursive: true });\n const payload = { allowed_modules: merged, ...restConfig };\n const tmp = path.join(dir, `.permission.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, filePath);\n return true;\n };\n\n const uuids = Array.from(new Set([bpUuid, ...(moduleUuid ? [moduleUuid] : [])]));\n for (const u of uuids) {\n if (await updateFile(configPermissionsPath(bdsRoot, u))) changed = true;\n if (await updateFile(configPermissionPath(bdsRoot, u))) changed = true;\n }\n\n const defaultFile = path.join(bdsRoot, \"config\", \"default\", \"permissions.json\");\n if (await updateFile(defaultFile)) changed = true;\n\n return changed;\n}\n\n/** \u4ECE\u5DF2\u88C5\u914D BP/RP \u76EE\u5F55\u8BFB\u53D6 header.uuid + version;\u5931\u8D25\u8FD4\u56DE null\u3002 */\nexport function readPackManifestHeader(\n packDir: string\n): { uuid: string; version: [number, number, number]; moduleUuid?: string } | null {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return null;\n try {\n const raw = readJsonFile<{\n header?: { uuid?: string; version?: number[] };\n modules?: Array<{ uuid?: string }>;\n }>(file);\n const uuid = raw.header?.uuid;\n const ver = raw.header?.version;\n if (typeof uuid !== \"string\" || !Array.isArray(ver) || ver.length < 3) return null;\n const version: [number, number, number] = [Number(ver[0]), Number(ver[1]), Number(ver[2])];\n const moduleUuid = raw.modules?.[0]?.uuid;\n return { uuid, version, ...(typeof moduleUuid === \"string\" ? { moduleUuid } : {}) };\n } catch {\n return null;\n }\n}\n\n\n/** \u4ECE\u5DF2\u88C5\u914D BP/RP \u76EE\u5F55\u8BFB\u53D6 dependencies \u5217\u8868\uFF1B\u82E5\u65E0\u6216\u5931\u8D25\u8FD4\u56DE []\u3002 */\nexport function readPackManifestDependencies(packDir: string): PackManifestDependency[] {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return [];\n try {\n const raw = readJsonFile<{ dependencies?: PackManifestDependency[] }>(file);\n return Array.isArray(raw.dependencies) ? raw.dependencies : [];\n } catch {\n return [];\n }\n}\n\n/**\n * Write `@minecraft/*` allowed_modules into a behavior pack's\n * `permissions.json`. Idempotent: rewrites any pre-existing file.\n */\nexport async function writePermissionsJson(bpDir: string): Promise<void> {\n const payload = { allowed_modules: [...SFMC_PERMISSIONS] };\n await fs.promises.mkdir(bpDir, { recursive: true });\n const tmp = path.join(bpDir, `.permissions.${process.pid}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, path.join(bpDir, \"permissions.json\"));\n}\n\n/**\n * Add `{ pack_id, version }` to `worlds/<level>/world_behavior_packs.json`\n * (or `world_resource_packs.json`). If the pack_id already exists, replace its\n * version. File missing \u2192 initialize as `[]`.\n */\nexport async function enablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"enable\");\n}\n\n/** Remove a pack_id from the world's enable-list JSON. */\nexport async function disablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"disable\");\n}\n\ninterface WorldPackEntry {\n pack_id: string;\n version: [number, number, number];\n}\n\nasync function editWorldPackList(\n opts: EnablePackOpts,\n mode: \"enable\" | \"disable\"\n): Promise<void> {\n const file = worldPackListFile(opts.worldsDir, opts.levelName, opts.kind);\n /* \u4E0E readWorldPackList \u540C\u6E90\u89E3\u6790,\u518D\u5199\u56DE(DRY);\u5F02\u6B65\u5199\u8DEF\u5F84\u4FDD\u7559\u539F\u8BED\u4E49 */\n let entries: WorldPackEntry[] = readWorldPackList(opts.worldsDir, opts.levelName, opts.kind);\n const idx = entries.findIndex((e) => e.pack_id === opts.packUuid);\n if (mode === \"enable\") {\n const next: WorldPackEntry = { pack_id: opts.packUuid, version: opts.version };\n if (idx >= 0) entries[idx] = next;\n else entries.push(next);\n } else {\n if (idx >= 0) entries.splice(idx, 1);\n }\n await fs.promises.mkdir(path.dirname(file), { recursive: true });\n const tmp = `${file}.${process.pid}.tmp`;\n await fs.promises.writeFile(tmp, JSON.stringify(entries, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, file);\n}\n\n/* \u2500\u2500 \u4F4E\u5C42 helpers (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport async function writeBehaviorPackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n },\n dependencies?: PackManifestDependency[] | undefined\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (behavior pack)` : \"SFMC behavior pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"script\",\n language: \"javascript\",\n entry: \"scripts/main.js\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n dependencies:\n dependencies && dependencies.length > 0 ? dependencies : BASELINE_BEDROCK_DEPENDENCIES,\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\nexport async function writeResourcePackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n }\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (resource pack)` : \"SFMC resource pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"resources\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\n/* Re-export copyFileAsync so callers can copy icon without\n * pulling in the full fsx surface area. */\nexport { copyFileAsync, copyDirAsync };\n\n/* \u2500\u2500 Discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Walk `<modulesDir>/<id>/resource_pack/` for every installed module and\n * return a map { id: absoluteDir }. Modules without a resource_pack folder\n * are silently skipped. Used by `assemble-rp` and the sfmc CLI to know which\n * modules to merge into the resource pack output.\n */\nexport function scanModuleResourcePacks(modulesDir: string): Record<string, string> {\n const out: Record<string, string> = {};\n if (!fs.existsSync(modulesDir)) return out;\n for (const entry of fs.readdirSync(modulesDir, { withFileTypes: true })) {\n if (entry.name.startsWith(\".\")) continue;\n // \u8DDF\u968F symlink\uFF08--link \u5B89\u88C5\uFF09\uFF1BDirent.isDirectory() \u5BF9\u94FE\u63A5\u76EE\u5F55\u4E3A false\n try {\n if (!fs.statSync(path.join(modulesDir, entry.name)).isDirectory()) continue;\n } catch {\n continue;\n }\n const rpDir = path.join(modulesDir, entry.name, \"resource_pack\");\n if (fs.existsSync(rpDir)) {\n out[entry.name] = rpDir;\n }\n }\n return out;\n}\n\n/**\n * \u4ECE JSON \u6587\u4EF6\u52A0\u8F7D\u663E\u5F0F moduleId \u2192 resource_pack \u76EE\u5F55\u6620\u5C04\u3002\n * \u4F9B assemble-rp --modules-json \u4F7F\u7528,\u907F\u514D\u8C03\u7528\u65B9\u518D\u505A\u4E34\u65F6\u76EE\u5F55\u955C\u50CF(OCP/DRY)\u3002\n */\nexport function loadModuleResourcePackMap(jsonPath: string): Record<string, string> {\n const raw = JSON.parse(fs.readFileSync(jsonPath, \"utf8\")) as unknown;\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n throw new Error(`modules-json must be an object: ${jsonPath}`);\n }\n const out: Record<string, string> = {};\n for (const [id, dir] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof id !== \"string\" || !id || typeof dir !== \"string\" || !dir) continue;\n const abs = path.resolve(dir);\n if (!fs.existsSync(abs)) {\n throw new Error(`modules-json entry missing: ${id} \u2192 ${abs}`);\n }\n out[id] = abs;\n }\n return out;\n}\n\n/**\n * \u8BFB\u53D6\u4E16\u754C enable-list(\u5355\u4E00\u6743\u5A01,\u4F9B has-pack / list-packs / \u8C03\u7528\u65B9\u590D\u7528 \u2014 DRY)\u3002\n * \u6587\u4EF6\u7F3A\u5931 \u2192 entries=[]\uFF1BJSON \u635F\u574F \u2192 entries=[] \u4E14 parseFailedFile \u6709\u503C\uFF08\u4F9B doctor \u533A\u5206\uFF09\u3002\n */\nexport type WorldPackListReadResult = {\n entries: Array<{ pack_id: string; version: [number, number, number] }>;\n /** \u6587\u4EF6\u5B58\u5728\u4F46\u89E3\u6790\u5931\u8D25\u65F6\u4E3A\u8BE5 JSON \u7EDD\u5BF9\u8DEF\u5F84 */\n parseFailedFile?: string;\n};\n\nexport function readWorldPackListResult(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): WorldPackListReadResult {\n const file = worldPackListFile(worldsDir, levelName, kind);\n if (!fs.existsSync(file)) return { entries: [] };\n try {\n const arr = JSON.parse(fs.readFileSync(file, \"utf8\")) as unknown;\n if (!Array.isArray(arr)) return { entries: [], parseFailedFile: file };\n const out: Array<{ pack_id: string; version: [number, number, number] }> = [];\n for (const e of arr) {\n if (!e || typeof e !== \"object\") continue;\n const packId = (e as { pack_id?: unknown }).pack_id;\n const ver = (e as { version?: unknown }).version;\n if (typeof packId !== \"string\" || !packId) continue;\n const version: [number, number, number] =\n Array.isArray(ver) && ver.length >= 3\n ? [Number(ver[0]), Number(ver[1]), Number(ver[2])]\n : [1, 0, 0];\n out.push({ pack_id: packId, version });\n }\n return { entries: out };\n } catch {\n return { entries: [], parseFailedFile: file };\n }\n}\n\n/** \u517C\u5BB9\u8BFB\u4FA7\uFF1A\u53EA\u8981 entries\uFF08\u635F\u574F\u65F6\u4E0E\u7F3A\u5931\u540C\u4E3A []\uFF09\u3002\u8BE6\u7EC6\u7ED3\u679C\u89C1 readWorldPackListResult\u3002 */\nexport function readWorldPackList(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): Array<{ pack_id: string; version: [number, number, number] }> {\n return readWorldPackListResult(worldsDir, levelName, kind).entries;\n}\n\n/** \u4E16\u754C enable-list \u662F\u5426\u5DF2\u542B\u6307\u5B9A pack_id(\u53EA\u8BFB,\u4F9B preflight \u590D\u7528)\u3002 */\nexport function worldPackListHas(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\",\n packUuid: string\n): boolean {\n return readWorldPackList(worldsDir, levelName, kind).some((e) => e.pack_id === packUuid);\n}"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,7 @@
4
4
  * 只 POST 结构化事件;群 openid / 频控由 db-server 处理(DIP)。
5
5
  * 失败仅 warn,不抛错。
6
6
  */
7
- export type BdsLifecycleEventType = "crash" | "start";
7
+ export type BdsLifecycleEventType = "crash" | "start" | "stop";
8
8
  /**
9
9
  * POST /api/sfmc/qq/events;超时/非 2xx 不抛。
10
10
  */
@@ -1 +1 @@
1
- {"version":3,"file":"qq-events-notify.d.ts","sourceRoot":"","sources":["../src/qq-events-notify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,OAAO,CAAC;AAiBtD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,qBAAqB,EAC3B,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAAC,IAAI,CAAC,CA6Cf"}
1
+ {"version":3,"file":"qq-events-notify.d.ts","sourceRoot":"","sources":["../src/qq-events-notify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAiB/D;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,qBAAqB,EAC3B,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAAC,IAAI,CAAC,CA6Cf"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/qq-events-notify.ts"],
4
- "sourcesContent": ["/**\n * qq-events-notify.ts \u2014 \u5411 db-server \u4E0A\u62A5 BDS \u542F\u505C\u4E8B\u4EF6\n *\n * \u53EA POST \u7ED3\u6784\u5316\u4E8B\u4EF6\uFF1B\u7FA4 openid / \u9891\u63A7\u7531 db-server \u5904\u7406\uFF08DIP\uFF09\u3002\n * \u5931\u8D25\u4EC5 warn\uFF0C\u4E0D\u629B\u9519\u3002\n */\n\nimport {\n DEFAULT_DB_CONFIG,\n loadEnsuredConfig,\n type DBConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport http from \"node:http\";\nimport { log } from \"./log.js\";\nimport { ROOT_DIR } from \"./paths.js\";\n\nexport type BdsLifecycleEventType = \"crash\" | \"start\";\n\nfunction resolveDbPort(): number {\n try {\n const cfg = loadEnsuredConfig(\n ROOT_DIR,\n \"db_config.json\",\n \"db_config\",\n { ...DEFAULT_DB_CONFIG } as Record<string, unknown>\n ) as DBConfig;\n const n = Number(cfg.db_port ?? 3001);\n return Number.isFinite(n) && n > 0 ? n : 3001;\n } catch {\n return 3001;\n }\n}\n\n/**\n * POST /api/sfmc/qq/events\uFF1B\u8D85\u65F6/\u975E 2xx \u4E0D\u629B\u3002\n */\nexport function postBdsLifecycleEvent(\n type: BdsLifecycleEventType,\n detail?: string,\n opts?: { host?: string; port?: number; timeoutMs?: number }\n): Promise<void> {\n const host = opts?.host ?? \"127.0.0.1\";\n const port = opts?.port ?? resolveDbPort();\n const timeoutMs = opts?.timeoutMs ?? 3_000;\n const payload = JSON.stringify({\n type,\n detail: detail ?? undefined,\n });\n\n return new Promise((resolve) => {\n const req = http.request(\n {\n hostname: host,\n port,\n path: \"/api/sfmc/qq/events\",\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(payload),\n },\n timeout: timeoutMs,\n },\n (res) => {\n res.resume();\n res.on(\"end\", () => {\n const code = res.statusCode ?? 0;\n if (code < 200 || code >= 300) {\n log.warn(`[QQ\u4E8B\u4EF6] db-server \u8FD4\u56DE HTTP ${code} (type=${type})`);\n }\n resolve();\n });\n }\n );\n req.on(\"timeout\", () => {\n req.destroy();\n log.warn(`[QQ\u4E8B\u4EF6] \u4E0A\u62A5\u8D85\u65F6 ${timeoutMs}ms (type=${type})`);\n resolve();\n });\n req.on(\"error\", (err) => {\n log.warn(`[QQ\u4E8B\u4EF6] \u4E0A\u62A5\u5931\u8D25: ${err.message} (type=${type})`);\n resolve();\n });\n req.write(payload);\n req.end();\n });\n}\n"],
4
+ "sourcesContent": ["/**\n * qq-events-notify.ts \u2014 \u5411 db-server \u4E0A\u62A5 BDS \u542F\u505C\u4E8B\u4EF6\n *\n * \u53EA POST \u7ED3\u6784\u5316\u4E8B\u4EF6\uFF1B\u7FA4 openid / \u9891\u63A7\u7531 db-server \u5904\u7406\uFF08DIP\uFF09\u3002\n * \u5931\u8D25\u4EC5 warn\uFF0C\u4E0D\u629B\u9519\u3002\n */\n\nimport {\n DEFAULT_DB_CONFIG,\n loadEnsuredConfig,\n type DBConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport http from \"node:http\";\nimport { log } from \"./log.js\";\nimport { ROOT_DIR } from \"./paths.js\";\n\nexport type BdsLifecycleEventType = \"crash\" | \"start\" | \"stop\";\n\nfunction resolveDbPort(): number {\n try {\n const cfg = loadEnsuredConfig(\n ROOT_DIR,\n \"db_config.json\",\n \"db_config\",\n { ...DEFAULT_DB_CONFIG } as Record<string, unknown>\n ) as DBConfig;\n const n = Number(cfg.db_port ?? 3001);\n return Number.isFinite(n) && n > 0 ? n : 3001;\n } catch {\n return 3001;\n }\n}\n\n/**\n * POST /api/sfmc/qq/events\uFF1B\u8D85\u65F6/\u975E 2xx \u4E0D\u629B\u3002\n */\nexport function postBdsLifecycleEvent(\n type: BdsLifecycleEventType,\n detail?: string,\n opts?: { host?: string; port?: number; timeoutMs?: number }\n): Promise<void> {\n const host = opts?.host ?? \"127.0.0.1\";\n const port = opts?.port ?? resolveDbPort();\n const timeoutMs = opts?.timeoutMs ?? 3_000;\n const payload = JSON.stringify({\n type,\n detail: detail ?? undefined,\n });\n\n return new Promise((resolve) => {\n const req = http.request(\n {\n hostname: host,\n port,\n path: \"/api/sfmc/qq/events\",\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(payload),\n },\n timeout: timeoutMs,\n },\n (res) => {\n res.resume();\n res.on(\"end\", () => {\n const code = res.statusCode ?? 0;\n if (code < 200 || code >= 300) {\n log.warn(`[QQ\u4E8B\u4EF6] db-server \u8FD4\u56DE HTTP ${code} (type=${type})`);\n }\n resolve();\n });\n }\n );\n req.on(\"timeout\", () => {\n req.destroy();\n log.warn(`[QQ\u4E8B\u4EF6] \u4E0A\u62A5\u8D85\u65F6 ${timeoutMs}ms (type=${type})`);\n resolve();\n });\n req.on(\"error\", (err) => {\n log.warn(`[QQ\u4E8B\u4EF6] \u4E0A\u62A5\u5931\u8D25: ${err.message} (type=${type})`);\n resolve();\n });\n req.write(payload);\n req.end();\n });\n}\n"],
5
5
  "mappings": "AAOA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,OAAO,UAAU;AACjB,SAAS,WAAW;AACpB,SAAS,gBAAgB;AAIzB,SAAS,gBAAwB;AAC/B,MAAI;AACF,UAAM,MAAM;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,GAAG,kBAAkB;AAAA,IACzB;AACA,UAAM,IAAI,OAAO,IAAI,WAAW,IAAI;AACpC,WAAO,OAAO,SAAS,CAAC,KAAK,IAAI,IAAI,IAAI;AAAA,EAC3C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,sBACd,MACA,QACA,MACe;AACf,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,OAAO,MAAM,QAAQ,cAAc;AACzC,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,UAAU,KAAK,UAAU;AAAA,IAC7B;AAAA,IACA,QAAQ,UAAU;AAAA,EACpB,CAAC;AAED,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,MAAM,KAAK;AAAA,MACf;AAAA,QACE,UAAU;AAAA,QACV;AAAA,QACA,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,kBAAkB,OAAO,WAAW,OAAO;AAAA,QAC7C;AAAA,QACA,SAAS;AAAA,MACX;AAAA,MACA,CAAC,QAAQ;AACP,YAAI,OAAO;AACX,YAAI,GAAG,OAAO,MAAM;AAClB,gBAAM,OAAO,IAAI,cAAc;AAC/B,cAAI,OAAO,OAAO,QAAQ,KAAK;AAC7B,gBAAI,KAAK,gDAA4B,IAAI,UAAU,IAAI,GAAG;AAAA,UAC5D;AACA,kBAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF;AACA,QAAI,GAAG,WAAW,MAAM;AACtB,UAAI,QAAQ;AACZ,UAAI,KAAK,6CAAe,SAAS,YAAY,IAAI,GAAG;AACpD,cAAQ;AAAA,IACV,CAAC;AACD,QAAI,GAAG,SAAS,CAAC,QAAQ;AACvB,UAAI,KAAK,8CAAgB,IAAI,OAAO,UAAU,IAAI,GAAG;AACrD,cAAQ;AAAA,IACV,CAAC;AACD,QAAI,MAAM,OAAO;AACjB,QAAI,IAAI;AAAA,EACV,CAAC;AACH;",
6
6
  "names": []
7
7
  }
package/dist/qqutil.d.ts CHANGED
@@ -1,12 +1,16 @@
1
1
  /**
2
- * qqutil.ts — QQ 通知工具(官方 Bot / LLBot 双后端)
2
+ * qqutil.ts — BDS 运维与更新通知推送工具(支持官方 Bot 与 LLBot 双后端)
3
3
  *
4
- * 改进:
5
- * - sendTimeout 提供总超时,避免通知发送挂死主流程
6
- * - 静默模式 (失败不抛出),保证主流程不被通知干扰
7
- * - qq_backend=official 时走 SDK 发群;llbot 仍走 OneBot HTTP
4
+ * 核心机制:
5
+ * - 双后端适配:根据 `qq_backend` 配置自动分发至官方开放平台发群接口或 LLBot OneBot HTTP 接口
6
+ * - 故障隔离:通知发送失败仅记录告警日志并不中断主流程,确保主服务运维正常执行
7
+ * - 发送超时熔断:设置请求超时时间,防止外部网络响应延迟堵塞 BDS 启动与更新
8
+ */
9
+ /**
10
+ * 检查平台中 `qq-bridge` 模块是否处于启用状态。
11
+ *
12
+ * @returns 若启用返回 `true`,否则返回 `false`。
8
13
  */
9
- /** 检查 qq-bridge 模块是否启用 */
10
14
  export declare function isQqBridgeEnabled(): boolean;
11
15
  export declare function sendText(text: string): Promise<void>;
12
16
  export declare function sendMixed(segments: unknown[]): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"qqutil.d.ts","sourceRoot":"","sources":["../src/qqutil.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiCH,0BAA0B;AAC1B,wBAAgB,iBAAiB,IAAI,OAAO,CAQ3C;AAgED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB1D;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BlE;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlF"}
1
+ {"version":3,"file":"qqutil.d.ts","sourceRoot":"","sources":["../src/qqutil.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwBH;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C;AAgED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB1D;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgClE;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlF"}