@sfmc-bds/bds-tools 0.2.0-beta.1 → 0.2.0-beta.10

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 (103) hide show
  1. package/LICENSE +663 -0
  2. package/dist/bds-manager.d.ts +16 -6
  3. package/dist/bds-manager.d.ts.map +1 -1
  4. package/dist/bds-manager.js +40 -65
  5. package/dist/bds-manager.js.map +2 -2
  6. package/dist/check-update.d.ts.map +1 -1
  7. package/dist/check-update.js +4 -6
  8. package/dist/check-update.js.map +2 -2
  9. package/dist/cli-pack-manager.js +0 -0
  10. package/dist/fsx.d.ts +2 -6
  11. package/dist/fsx.d.ts.map +1 -1
  12. package/dist/fsx.js +3 -14
  13. package/dist/fsx.js.map +2 -2
  14. package/dist/host-platform.d.ts +25 -0
  15. package/dist/host-platform.d.ts.map +1 -0
  16. package/dist/host-platform.js +50 -0
  17. package/dist/host-platform.js.map +7 -0
  18. package/dist/http.d.ts +49 -11
  19. package/dist/http.d.ts.map +1 -1
  20. package/dist/http.js.map +2 -2
  21. package/dist/log.d.ts +2 -3
  22. package/dist/log.d.ts.map +1 -1
  23. package/dist/log.js +0 -1
  24. package/dist/log.js.map +2 -2
  25. package/dist/pack-manager-lifecycle.test.js +252 -0
  26. package/dist/pack-manager-lifecycle.test.js.map +7 -0
  27. package/dist/pack-manager.d.ts +24 -29
  28. package/dist/pack-manager.d.ts.map +1 -1
  29. package/dist/pack-manager.js +11 -5
  30. package/dist/pack-manager.js.map +2 -2
  31. package/dist/pack-update/bindings.d.ts +16 -0
  32. package/dist/pack-update/bindings.d.ts.map +1 -0
  33. package/dist/pack-update/bindings.js +69 -0
  34. package/dist/pack-update/bindings.js.map +7 -0
  35. package/dist/pack-update/config.d.ts +16 -0
  36. package/dist/pack-update/config.d.ts.map +1 -0
  37. package/dist/pack-update/config.js +146 -0
  38. package/dist/pack-update/config.js.map +7 -0
  39. package/dist/pack-update/config.test.js +75 -0
  40. package/dist/pack-update/config.test.js.map +7 -0
  41. package/dist/pack-update/deps.d.ts +28 -0
  42. package/dist/pack-update/deps.d.ts.map +1 -0
  43. package/dist/pack-update/deps.js +20 -0
  44. package/dist/pack-update/deps.js.map +7 -0
  45. package/dist/pack-update/index.d.ts +55 -0
  46. package/dist/pack-update/index.d.ts.map +1 -0
  47. package/dist/pack-update/index.js +72 -0
  48. package/dist/pack-update/index.js.map +7 -0
  49. package/dist/pack-update/providers/curseforge.d.ts +23 -0
  50. package/dist/pack-update/providers/curseforge.d.ts.map +1 -0
  51. package/dist/pack-update/providers/curseforge.js +229 -0
  52. package/dist/pack-update/providers/curseforge.js.map +7 -0
  53. package/dist/pack-update/providers/index.d.ts +16 -0
  54. package/dist/pack-update/providers/index.d.ts.map +1 -0
  55. package/dist/pack-update/providers/index.js +37 -0
  56. package/dist/pack-update/providers/index.js.map +7 -0
  57. package/dist/pack-update/service.d.ts +28 -0
  58. package/dist/pack-update/service.d.ts.map +1 -0
  59. package/dist/pack-update/service.js +570 -0
  60. package/dist/pack-update/service.js.map +7 -0
  61. package/dist/pack-update/types.d.ts +126 -0
  62. package/dist/pack-update/types.d.ts.map +1 -0
  63. package/dist/pack-update/types.js +8 -0
  64. package/dist/pack-update/types.js.map +7 -0
  65. package/dist/pack-update/version-policy.d.ts +81 -0
  66. package/dist/pack-update/version-policy.d.ts.map +1 -0
  67. package/dist/pack-update/version-policy.js +210 -0
  68. package/dist/pack-update/version-policy.js.map +7 -0
  69. package/dist/pack-update/version-policy.test.js +137 -0
  70. package/dist/pack-update/version-policy.test.js.map +7 -0
  71. package/dist/paths.d.ts +1 -1
  72. package/dist/paths.d.ts.map +1 -1
  73. package/dist/paths.js +3 -5
  74. package/dist/paths.js.map +2 -2
  75. package/dist/process-probe.d.ts +34 -0
  76. package/dist/process-probe.d.ts.map +1 -0
  77. package/dist/process-probe.js +152 -0
  78. package/dist/process-probe.js.map +7 -0
  79. package/dist/process-probe.test.js +76 -0
  80. package/dist/process-probe.test.js.map +7 -0
  81. package/dist/qq-events-notify.d.ts +16 -0
  82. package/dist/qq-events-notify.d.ts.map +1 -0
  83. package/dist/qq-events-notify.js +70 -0
  84. package/dist/qq-events-notify.js.map +7 -0
  85. package/dist/qqutil.d.ts +10 -5
  86. package/dist/qqutil.d.ts.map +1 -1
  87. package/dist/qqutil.js +49 -8
  88. package/dist/qqutil.js.map +2 -2
  89. package/dist/upstream.d.ts +18 -9
  90. package/dist/upstream.d.ts.map +1 -1
  91. package/dist/upstream.js +8 -7
  92. package/dist/upstream.js.map +2 -2
  93. package/dist/version.js +2 -2
  94. package/dist/version.js.map +2 -2
  95. package/dist/world-packs.d.ts +98 -7
  96. package/dist/world-packs.d.ts.map +1 -1
  97. package/dist/world-packs.js +129 -57
  98. package/dist/world-packs.js.map +2 -2
  99. package/dist/world-packs.test.js +676 -0
  100. package/dist/world-packs.test.js.map +7 -0
  101. package/dist/zipx.test.js +36 -0
  102. package/dist/zipx.test.js.map +7 -0
  103. package/package.json +43 -39
package/dist/qqutil.js CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  modulePath,
4
4
  readJson
5
5
  } from "@sfmc-bds/sdk/node/config";
6
+ import { sendGroupTextMessage } from "@sfmc-bds/sdk/node/qq-official";
6
7
  import http from "node:http";
7
8
  import { log } from "./log.js";
8
9
  import { ROOT_DIR } from "./paths.js";
@@ -19,15 +20,18 @@ function isQqBridgeEnabled() {
19
20
  const mod = catalog.modules?.find((m) => m.id === "qq-bridge" || m.configKey === "qq_bridge");
20
21
  return mod ? lock.modules?.[mod.id ?? ""]?.enabled === true : false;
21
22
  }
23
+ function isOfficialBackend(cfg) {
24
+ return (cfg.qq_backend ?? "official") === "official";
25
+ }
22
26
  function sendToLLBot(payload, timeoutMs = 5e3) {
23
27
  const cfg = getConfig();
24
- const url = new URL(cfg.llbot_http || "http://127.0.0.1:3000");
28
+ const url = new URL(cfg.llbot_http || "http://127.0.0.1:3004");
25
29
  const data = JSON.stringify(payload);
26
30
  return new Promise((resolve, reject) => {
27
31
  const req = http.request(
28
32
  {
29
33
  hostname: url.hostname,
30
- port: url.port || 3e3,
34
+ port: url.port || 3004,
31
35
  path: "/send_group_msg",
32
36
  method: "POST",
33
37
  headers: {
@@ -60,14 +64,36 @@ async function safeSend(label, fn) {
60
64
  log.warn(`[QQ] ${label} \u5931\u8D25: ${e.message}`);
61
65
  }
62
66
  }
67
+ async function sendOfficialText(text) {
68
+ const cfg = getConfig();
69
+ const appId = String(cfg.qq_app_id ?? "");
70
+ const appSecret = String(cfg.qq_app_secret ?? "");
71
+ const groupOpenid = String(cfg.qq_group_openid ?? "");
72
+ if (!appId || !appSecret || !groupOpenid) {
73
+ throw new Error("\u5B98\u65B9\u540E\u7AEF\u7F3A\u5C11 qq_app_id / qq_app_secret / qq_group_openid");
74
+ }
75
+ const result = await sendGroupTextMessage(
76
+ { appId, appSecret, sandbox: cfg.qq_sandbox === true },
77
+ { groupOpenid, content: text }
78
+ );
79
+ if (!result.ok) throw new Error(result.error);
80
+ }
63
81
  async function sendText(text) {
64
82
  const cfg = getConfig();
65
- if (!isQqBridgeEnabled() || !cfg.qq_group_id) {
66
- log.warn("[QQ] qq-bridge \u672A\u542F\u7528\u6216 qq_group_id \u7F3A\u5931");
83
+ if (!isQqBridgeEnabled()) {
84
+ log.warn("[QQ] qq-bridge \u672A\u542F\u7528");
85
+ return;
86
+ }
87
+ if (isOfficialBackend(cfg)) {
88
+ await safeSend("sendText(official)", () => sendOfficialText(text));
89
+ return;
90
+ }
91
+ if (!cfg.qq_group_id) {
92
+ log.warn("[QQ] qq_group_id \u7F3A\u5931");
67
93
  return;
68
94
  }
69
95
  await safeSend(
70
- "sendText",
96
+ "sendText(llbot)",
71
97
  () => sendToLLBot({
72
98
  group_id: parseInt(cfg.qq_group_id ?? "0", 10),
73
99
  message: [{ type: "text", data: { text } }]
@@ -76,12 +102,27 @@ async function sendText(text) {
76
102
  }
77
103
  async function sendMixed(segments) {
78
104
  const cfg = getConfig();
79
- if (!isQqBridgeEnabled() || !cfg.qq_group_id) {
80
- log.warn("[QQ] qq-bridge \u672A\u542F\u7528\u6216 qq_group_id \u7F3A\u5931");
105
+ if (!isQqBridgeEnabled()) {
106
+ log.warn("[QQ] qq-bridge \u672A\u542F\u7528");
107
+ return;
108
+ }
109
+ if (isOfficialBackend(cfg)) {
110
+ const text = segments.map((seg) => {
111
+ const s = seg;
112
+ if (s?.type === "text") return String(s.data?.text ?? "");
113
+ if (s?.type === "image") return "[\u56FE\u7247]";
114
+ return "";
115
+ }).join("").trim();
116
+ if (!text) return;
117
+ await safeSend("sendMixed(official)", () => sendOfficialText(text));
118
+ return;
119
+ }
120
+ if (!cfg.qq_group_id) {
121
+ log.warn("[QQ] qq_group_id \u7F3A\u5931");
81
122
  return;
82
123
  }
83
124
  await safeSend(
84
- "sendMixed",
125
+ "sendMixed(llbot)",
85
126
  () => sendToLLBot({
86
127
  group_id: parseInt(cfg.qq_group_id ?? "0", 10),
87
128
  message: segments
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/qqutil.ts"],
4
- "sourcesContent": ["/**\n * qqutil.ts \u2014 QQ \u901A\u77E5\u5DE5\u5177 (\u57FA\u4E8E LLBot HTTP OneBot 11)\n *\n * \u6539\u8FDB:\n * - sendTimeout \u63D0\u4F9B\u603B\u8D85\u65F6\uFF0C\u907F\u514D\u901A\u77E5\u53D1\u9001\u6302\u6B7B\u4E3B\u6D41\u7A0B\n * - \u9759\u9ED8\u6A21\u5F0F (\u5931\u8D25\u4E0D\u629B\u51FA)\uFF0C\u4FDD\u8BC1\u4E3B\u6D41\u7A0B\u4E0D\u88AB\u901A\u77E5\u5E72\u6270\n */\n\nimport {\n configPath,\n modulePath,\n readJson,\n type Catalog,\n type ModuleLock,\n type QQBridgeConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport http from \"node:http\";\nimport { log } from \"./log.js\";\nimport { ROOT_DIR } from \"./paths.js\";\n\ntype QqConfig = Pick<QQBridgeConfig, \"llbot_http\" | \"qq_group_id\">;\n\nlet cachedCfg: QqConfig | null = null;\nfunction getConfig(): QqConfig {\n if (cachedCfg) return cachedCfg;\n cachedCfg = (readJson<QQBridgeConfig>(configPath(ROOT_DIR, \"qq_config.json\")) ?? {}) as QqConfig;\n return cachedCfg;\n}\n\n/** \u68C0\u67E5 qq-bridge \u6A21\u5757\u662F\u5426\u542F\u7528 */\nexport function isQqBridgeEnabled(): boolean {\n const catalog = readJson<Catalog>(modulePath(ROOT_DIR, \"catalog.json\"));\n const lock = readJson<ModuleLock>(modulePath(ROOT_DIR, \"module-lock.json\"));\n if (!catalog || !lock) return true; // \u6A21\u5757\u76EE\u5F55\u7F3A\u5931\u5219\u4FDD\u5B88\u89C6\u4E3A\u53EF\u7528\n const mod = catalog.modules?.find((m) => m.id === \"qq-bridge\" || m.configKey === \"qq_bridge\") as\n { id?: string } | undefined;\n return mod ? lock.modules?.[mod.id ?? \"\"]?.enabled === true : false;\n}\n\nfunction sendToLLBot(payload: unknown, timeoutMs = 5_000): Promise<void> {\n const cfg = getConfig();\n const url = new URL(cfg.llbot_http || \"http://127.0.0.1:3000\");\n const data = JSON.stringify(payload);\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n hostname: url.hostname,\n port: url.port || 3000,\n path: \"/send_group_msg\",\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(data),\n },\n timeout: timeoutMs,\n },\n (res) => {\n let body = \"\";\n res.on(\"data\", (c) => (body += c));\n res.on(\"end\", () => {\n if (res.statusCode === 200) resolve();\n else reject(new Error(`LLBot HTTP ${res.statusCode}: ${body.slice(0, 200)}`));\n });\n }\n );\n req.on(\"timeout\", () => {\n req.destroy(new Error(`LLBot \u8D85\u65F6 ${timeoutMs}ms`));\n });\n req.on(\"error\", reject);\n req.write(data);\n req.end();\n });\n}\n\nasync function safeSend(label: string, fn: () => Promise<void>): Promise<void> {\n try {\n await fn();\n } catch (e) {\n log.warn(`[QQ] ${label} \u5931\u8D25: ${(e as Error).message}`);\n }\n}\n\nexport async function sendText(text: string): Promise<void> {\n const cfg = getConfig();\n if (!isQqBridgeEnabled() || !cfg.qq_group_id) {\n log.warn(\"[QQ] qq-bridge \u672A\u542F\u7528\u6216 qq_group_id \u7F3A\u5931\");\n return;\n }\n await safeSend(\"sendText\", () =>\n sendToLLBot({\n group_id: parseInt(cfg.qq_group_id ?? \"0\", 10),\n message: [{ type: \"text\", data: { text } }],\n })\n );\n}\n\nexport async function sendMixed(segments: unknown[]): Promise<void> {\n const cfg = getConfig();\n if (!isQqBridgeEnabled() || !cfg.qq_group_id) {\n log.warn(\"[QQ] qq-bridge \u672A\u542F\u7528\u6216 qq_group_id \u7F3A\u5931\");\n return;\n }\n await safeSend(\"sendMixed\", () =>\n sendToLLBot({\n group_id: parseInt(cfg.qq_group_id ?? \"0\", 10),\n message: segments,\n })\n );\n}\n\nexport async function sendWithImage(text: string, base64Img: string): Promise<void> {\n const segments: unknown[] = [];\n if (text) segments.push({ type: \"text\", data: { text } });\n if (base64Img) segments.push({ type: \"image\", data: { file: `base64://${base64Img}` } });\n if (segments.length === 0) return;\n await sendMixed(segments);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * qqutil.ts \u2014 BDS \u8FD0\u7EF4\u4E0E\u66F4\u65B0\u901A\u77E5\u63A8\u9001\u5DE5\u5177\uFF08\u652F\u6301\u5B98\u65B9 Bot \u4E0E LLBot \u53CC\u540E\u7AEF\uFF09\n *\n * \u6838\u5FC3\u673A\u5236\uFF1A\n * - \u53CC\u540E\u7AEF\u9002\u914D\uFF1A\u6839\u636E `qq_backend` \u914D\u7F6E\u81EA\u52A8\u5206\u53D1\u81F3\u5B98\u65B9\u5F00\u653E\u5E73\u53F0\u53D1\u7FA4\u63A5\u53E3\u6216 LLBot OneBot HTTP \u63A5\u53E3\n * - \u6545\u969C\u9694\u79BB\uFF1A\u901A\u77E5\u53D1\u9001\u5931\u8D25\u4EC5\u8BB0\u5F55\u544A\u8B66\u65E5\u5FD7\u5E76\u4E0D\u4E2D\u65AD\u4E3B\u6D41\u7A0B\uFF0C\u786E\u4FDD\u4E3B\u670D\u52A1\u8FD0\u7EF4\u6B63\u5E38\u6267\u884C\n * - \u53D1\u9001\u8D85\u65F6\u7194\u65AD\uFF1A\u8BBE\u7F6E\u8BF7\u6C42\u8D85\u65F6\u65F6\u95F4\uFF0C\u9632\u6B62\u5916\u90E8\u7F51\u7EDC\u54CD\u5E94\u5EF6\u8FDF\u5835\u585E BDS \u542F\u52A8\u4E0E\u66F4\u65B0\n */\n\nimport {\n configPath,\n modulePath,\n readJson,\n type Catalog,\n type ModuleLock,\n type QQBridgeConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport { sendGroupTextMessage } from \"@sfmc-bds/sdk/node/qq-official\";\nimport http from \"node:http\";\nimport { log } from \"./log.js\";\nimport { ROOT_DIR } from \"./paths.js\";\n\ntype QqConfig = Pick<\n QQBridgeConfig,\n | \"llbot_http\"\n | \"qq_group_id\"\n | \"qq_backend\"\n | \"qq_app_id\"\n | \"qq_app_secret\"\n | \"qq_sandbox\"\n | \"qq_group_openid\"\n>;\n\nlet cachedCfg: QqConfig | null = null;\nfunction getConfig(): QqConfig {\n if (cachedCfg) return cachedCfg;\n cachedCfg = (readJson<QQBridgeConfig>(configPath(ROOT_DIR, \"qq_config.json\")) ?? {}) as QqConfig;\n return cachedCfg;\n}\n\n/**\n * \u68C0\u67E5\u5E73\u53F0\u4E2D `qq-bridge` \u6A21\u5757\u662F\u5426\u5904\u4E8E\u542F\u7528\u72B6\u6001\u3002\n *\n * @returns \u82E5\u542F\u7528\u8FD4\u56DE `true`\uFF0C\u5426\u5219\u8FD4\u56DE `false`\u3002\n */\nexport function isQqBridgeEnabled(): boolean {\n\n const catalog = readJson<Catalog>(modulePath(ROOT_DIR, \"catalog.json\"));\n const lock = readJson<ModuleLock>(modulePath(ROOT_DIR, \"module-lock.json\"));\n if (!catalog || !lock) return true; // \u6A21\u5757\u76EE\u5F55\u7F3A\u5931\u5219\u4FDD\u5B88\u89C6\u4E3A\u53EF\u7528\n const mod = catalog.modules?.find((m) => m.id === \"qq-bridge\" || m.configKey === \"qq_bridge\");\n return mod ? lock.modules?.[mod.id ?? \"\"]?.enabled === true : false;\n}\n\nfunction isOfficialBackend(cfg: QqConfig): boolean {\n return (cfg.qq_backend ?? \"official\") === \"official\";\n}\n\nfunction sendToLLBot(payload: unknown, timeoutMs = 5_000): Promise<void> {\n const cfg = getConfig();\n const url = new URL(cfg.llbot_http || \"http://127.0.0.1:3004\");\n const data = JSON.stringify(payload);\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n hostname: url.hostname,\n port: url.port || 3004,\n path: \"/send_group_msg\",\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(data),\n },\n timeout: timeoutMs,\n },\n (res) => {\n let body = \"\";\n res.on(\"data\", (c) => (body += c));\n res.on(\"end\", () => {\n if (res.statusCode === 200) resolve();\n else reject(new Error(`LLBot HTTP ${res.statusCode}: ${body.slice(0, 200)}`));\n });\n }\n );\n req.on(\"timeout\", () => {\n req.destroy(new Error(`LLBot \u8D85\u65F6 ${timeoutMs}ms`));\n });\n req.on(\"error\", reject);\n req.write(data);\n req.end();\n });\n}\n\nasync function safeSend(label: string, fn: () => Promise<void>): Promise<void> {\n try {\n await fn();\n } catch (e) {\n log.warn(`[QQ] ${label} \u5931\u8D25: ${(e as Error).message}`);\n }\n}\n\nasync function sendOfficialText(text: string): Promise<void> {\n const cfg = getConfig();\n const appId = String(cfg.qq_app_id ?? \"\");\n const appSecret = String(cfg.qq_app_secret ?? \"\");\n const groupOpenid = String(cfg.qq_group_openid ?? \"\");\n if (!appId || !appSecret || !groupOpenid) {\n throw new Error(\"\u5B98\u65B9\u540E\u7AEF\u7F3A\u5C11 qq_app_id / qq_app_secret / qq_group_openid\");\n }\n const result = await sendGroupTextMessage(\n { appId, appSecret, sandbox: cfg.qq_sandbox === true },\n { groupOpenid, content: text }\n );\n if (!result.ok) throw new Error(result.error);\n}\n\nexport async function sendText(text: string): Promise<void> {\n const cfg = getConfig();\n if (!isQqBridgeEnabled()) {\n log.warn(\"[QQ] qq-bridge \u672A\u542F\u7528\");\n return;\n }\n if (isOfficialBackend(cfg)) {\n await safeSend(\"sendText(official)\", () => sendOfficialText(text));\n return;\n }\n if (!cfg.qq_group_id) {\n log.warn(\"[QQ] qq_group_id \u7F3A\u5931\");\n return;\n }\n await safeSend(\"sendText(llbot)\", () =>\n sendToLLBot({\n group_id: parseInt(cfg.qq_group_id ?? \"0\", 10),\n message: [{ type: \"text\", data: { text } }],\n })\n );\n}\n\nexport async function sendMixed(segments: unknown[]): Promise<void> {\n const cfg = getConfig();\n if (!isQqBridgeEnabled()) {\n log.warn(\"[QQ] qq-bridge \u672A\u542F\u7528\");\n return;\n }\n if (isOfficialBackend(cfg)) {\n // \u5B98\u65B9\u8DEF\u5F84\u4EC5\u62FC\u7EAF\u6587\u672C\uFF1B\u56FE\u7247\u6BB5\u964D\u7EA7\u4E3A [\u56FE\u7247]\n const text = segments\n .map((seg) => {\n const s = seg as { type?: string; data?: { text?: string } };\n if (s?.type === \"text\") return String(s.data?.text ?? \"\");\n if (s?.type === \"image\") return \"[\u56FE\u7247]\";\n return \"\";\n })\n .join(\"\")\n .trim();\n if (!text) return;\n await safeSend(\"sendMixed(official)\", () => sendOfficialText(text));\n return;\n }\n if (!cfg.qq_group_id) {\n log.warn(\"[QQ] qq_group_id \u7F3A\u5931\");\n return;\n }\n await safeSend(\"sendMixed(llbot)\", () =>\n sendToLLBot({\n group_id: parseInt(cfg.qq_group_id ?? \"0\", 10),\n message: segments,\n })\n );\n}\n\nexport async function sendWithImage(text: string, base64Img: string): Promise<void> {\n const segments: unknown[] = [];\n if (text) segments.push({ type: \"text\", data: { text } });\n if (base64Img) segments.push({ type: \"image\", data: { file: `base64://${base64Img}` } });\n if (segments.length === 0) return;\n await sendMixed(segments);\n}\n\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,18 +1,27 @@
1
1
  /**
2
- * upstream.ts — 版本源 / 下载源 / 哈希校验
2
+ * upstream.ts — BDS 上游版本源、多镜像下载与完整性校验
3
3
  *
4
- * 改进:
5
- * - 3 次重试 + 指数退避
6
- * - sha1 / sha256 同时校验
7
- * - 流式校验 + 边下边校验
4
+ * 核心机制:
5
+ * - 多源容灾:官方源与镜像源并行竞争与多轮指数退避重试
6
+ * - 动态 URL 模板渲染:根据操作系统架构与更新通道计算下载地址
7
+ * - 流式哈希校验:支持 SHA-1 与 SHA-256 完整性流式计算校验
8
+ * - 版本白名单兼容门禁:防止自动升级至未验证版本
8
9
  */
10
+ import { type BdsHostOs } from "./host-platform.js";
9
11
  import type { BdsUpdaterConfig, VersionDetails, VersionInfo } from "./types.js";
10
- /** 获取最新版本号 (含 cdn_root),3 次重试 */
11
- export declare function getVersionInfo(cfg: BdsUpdaterConfig, channel: string): Promise<VersionInfo>;
12
+ /**
13
+ * 获取 BDS 最新可用版本信息(支持重试与指数退避)。
14
+ *
15
+ * @param cfg BDS 更新器配置。
16
+ * @param channel 更新通道(如 "release" 或 "preview")。
17
+ * @param hostOs 目标主机操作系统类型。
18
+ * @returns 包含最新版本号与 CDN 根路径的信息对象。
19
+ */
20
+ export declare function getVersionInfo(cfg: BdsUpdaterConfig, channel: string, hostOs?: BdsHostOs): Promise<VersionInfo>;
12
21
  /** 获取 per-version 的下载链接 + 哈希 (fallback GitHub → jsdelivr) */
13
- export declare function fetchVersionDetails(cfg: BdsUpdaterConfig, channel: string, version: string): Promise<VersionDetails>;
22
+ export declare function fetchVersionDetails(cfg: BdsUpdaterConfig, channel: string, version: string, hostOs?: BdsHostOs): Promise<VersionDetails>;
14
23
  /** 候选下载 URL (按优先级) */
15
- export declare function buildDownloadUrls(cfg: BdsUpdaterConfig, channel: string, version: string, details: VersionDetails): string[];
24
+ export declare function buildDownloadUrls(cfg: BdsUpdaterConfig, channel: string, version: string, details: VersionDetails, hostOs?: BdsHostOs): string[];
16
25
  /** 同步 / 异步校验文件哈希 */
17
26
  export declare function verifyFileHash(filePath: string, expectedSha1: string, expectedSha256: string): Promise<boolean>;
18
27
  /** 检查版本兼容性 (白名单) */
@@ -1 +1 @@
1
- {"version":3,"file":"upstream.d.ts","sourceRoot":"","sources":["../src/upstream.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAchF,iCAAiC;AACjC,wBAAsB,cAAc,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA8BjG;AAED,6DAA6D;AAC7D,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,gBAAgB,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,CA2BzB;AAED,sBAAsB;AACtB,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,gBAAgB,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,GACtB,MAAM,EAAE,CAeV;AAED,oBAAoB;AACpB,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBrH;AAED,oBAAoB;AACpB,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAInF"}
1
+ {"version":3,"file":"upstream.d.ts","sourceRoot":"","sources":["../src/upstream.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGvG,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAchF;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAElC,GAAG,EAAE,gBAAgB,EACrB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,SAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC,CA8BtB;AAED,6DAA6D;AAC7D,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,gBAAgB,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,SAAuB,GAC9B,OAAO,CAAC,cAAc,CAAC,CA2BzB;AAED,sBAAsB;AACtB,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,gBAAgB,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,EACvB,MAAM,GAAE,SAAuB,GAC9B,MAAM,EAAE,CAYV;AAED,oBAAoB;AACpB,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBrH;AAED,oBAAoB;AACpB,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAInF"}
package/dist/upstream.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import crypto from "node:crypto";
2
2
  import fs from "node:fs";
3
+ import { bdsCdnZipSuffix, bdsDetailsPlatformKey, bdsHostOs } from "./host-platform.js";
3
4
  import { fetchJsonWithFallback } from "./http.js";
4
5
  import { log } from "./log.js";
5
6
  import { toVer3 } from "./version.js";
@@ -12,7 +13,7 @@ function resolveTemplate(tpl, vars) {
12
13
  }
13
14
  return s;
14
15
  }
15
- async function getVersionInfo(cfg, channel) {
16
+ async function getVersionInfo(cfg, channel, hostOs = bdsHostOs()) {
16
17
  const api = cfg.version_versions || process.env["BDS_VERSIONS_API"] || DEFAULT_VERSIONS_API;
17
18
  const mirror = cfg.version_versions_mirror || process.env["BDS_VERSIONS_MIRROR"] || DEFAULT_VERSIONS_MIRROR;
18
19
  const sources = [api, mirror].filter(Boolean);
@@ -26,7 +27,7 @@ async function getVersionInfo(cfg, channel) {
26
27
  const entry = channel === "preview" ? json.preview : json.release;
27
28
  ver = entry?.latest;
28
29
  } else {
29
- const platform = json.windows || json.linux;
30
+ const platform = hostOs === "windows" ? json.windows || json.linux : json.linux || json.windows;
30
31
  ver = channel === "preview" ? platform?.preview : platform?.stable;
31
32
  }
32
33
  if (!ver) throw new Error("\u672A\u627E\u5230\u6700\u65B0\u7248\u672C\u53F7");
@@ -42,8 +43,8 @@ async function getVersionInfo(cfg, channel) {
42
43
  }
43
44
  throw lastErr instanceof Error ? lastErr : new Error("\u7248\u672C\u53F7\u83B7\u53D6\u5931\u8D25");
44
45
  }
45
- async function fetchVersionDetails(cfg, channel, version) {
46
- const platform = channel === "preview" ? "windows_preview" : "windows";
46
+ async function fetchVersionDetails(cfg, channel, version, hostOs = bdsHostOs()) {
47
+ const platform = bdsDetailsPlatformKey(channel, hostOs);
47
48
  const ch = channel === "preview" ? "preview" : "release";
48
49
  const vars = { version, ver3: toVer3(version), platform, channel: ch };
49
50
  const detailsTpl = cfg.version_details || "https://raw.githubusercontent.com/Bedrock-OSS/BDS-Versions/main/{platform}/{version}.json";
@@ -52,7 +53,7 @@ async function fetchVersionDetails(cfg, channel, version) {
52
53
  const json = await fetchJsonWithFallback(sources);
53
54
  const mode = cfg.version_mode || "bedrock-oss";
54
55
  if (mode === "endstone") {
55
- const bw = json.binary?.windows;
56
+ const bw = hostOs === "windows" ? json.binary?.windows : json.binary?.linux;
56
57
  return {
57
58
  downloadUrl: bw?.url ?? "",
58
59
  sha1: "",
@@ -67,7 +68,7 @@ async function fetchVersionDetails(cfg, channel, version) {
67
68
  size: json.size_in_bytes ?? 0
68
69
  };
69
70
  }
70
- function buildDownloadUrls(cfg, channel, version, details) {
71
+ function buildDownloadUrls(cfg, channel, version, details, hostOs = bdsHostOs()) {
71
72
  const urls = [];
72
73
  if (cfg.download_mirror) {
73
74
  const mirrorVer = channel === "preview" ? `${version}-preview` : version;
@@ -75,7 +76,7 @@ function buildDownloadUrls(cfg, channel, version, details) {
75
76
  }
76
77
  if (details.downloadUrl) urls.push(details.downloadUrl);
77
78
  const cdnRoot = cfg.cdn_root || "https://www.minecraft.net/bedrockdedicatedserver";
78
- const suffix = channel === "preview" ? `/bin-win-preview/bedrock-server-${version}-preview.zip` : `/bin-win/bedrock-server-${version}.zip`;
79
+ const suffix = bdsCdnZipSuffix(channel, version, hostOs);
79
80
  urls.push(cdnRoot + suffix);
80
81
  urls.push(`https://minecraft.azureedge.net${suffix}`);
81
82
  return [...new Set(urls)];
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/upstream.ts"],
4
- "sourcesContent": ["/**\n * upstream.ts \u2014 \u7248\u672C\u6E90 / \u4E0B\u8F7D\u6E90 / \u54C8\u5E0C\u6821\u9A8C\n *\n * \u6539\u8FDB:\n * - 3 \u6B21\u91CD\u8BD5 + \u6307\u6570\u9000\u907F\n * - sha1 / sha256 \u540C\u65F6\u6821\u9A8C\n * - \u6D41\u5F0F\u6821\u9A8C + \u8FB9\u4E0B\u8FB9\u6821\u9A8C\n */\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport { fetchJsonWithFallback } from \"./http.js\";\nimport { log } from \"./log.js\";\nimport type { BdsUpdaterConfig, VersionDetails, VersionInfo } from \"./types.js\";\nimport { toVer3 } from \"./version.js\";\n\nconst DEFAULT_VERSIONS_API = \"https://raw.githubusercontent.com/Bedrock-OSS/BDS-Versions/main/versions.json\";\nconst DEFAULT_VERSIONS_MIRROR = \"https://cdn.jsdelivr.net/gh/Bedrock-OSS/BDS-Versions@main/versions.json\";\n\nfunction resolveTemplate(tpl: string, vars: Record<string, string>): string {\n let s = tpl;\n for (const [k, v] of Object.entries(vars)) {\n s = s.replace(new RegExp(`\\\\{${k}\\\\}`, \"g\"), v);\n }\n return s;\n}\n\n/** \u83B7\u53D6\u6700\u65B0\u7248\u672C\u53F7 (\u542B cdn_root)\uFF0C3 \u6B21\u91CD\u8BD5 */\nexport async function getVersionInfo(cfg: BdsUpdaterConfig, channel: string): Promise<VersionInfo> {\n const api = cfg.version_versions || process.env[\"BDS_VERSIONS_API\"] || DEFAULT_VERSIONS_API;\n const mirror = cfg.version_versions_mirror || process.env[\"BDS_VERSIONS_MIRROR\"] || DEFAULT_VERSIONS_MIRROR;\n const sources = [api, mirror].filter(Boolean);\n const versionMode = cfg.version_mode || \"bedrock-oss\";\n\n let lastErr: unknown;\n for (let attempt = 1; attempt <= 3; attempt++) {\n try {\n const json = await fetchJsonWithFallback<any>(sources);\n let ver: string | undefined;\n if (versionMode === \"endstone\") {\n const entry = channel === \"preview\" ? json.preview : json.release;\n ver = entry?.latest;\n } else {\n const platform = json.windows || json.linux;\n ver = channel === \"preview\" ? platform?.preview : platform?.stable;\n }\n if (!ver) throw new Error(\"\u672A\u627E\u5230\u6700\u65B0\u7248\u672C\u53F7\");\n return { version: ver, cdnRoot: json.cdn_root ?? \"\" };\n } catch (e) {\n lastErr = e;\n if (attempt < 3) {\n const wait = attempt * 3000;\n log.warn(`\u7248\u672C\u53F7\u83B7\u53D6\u5931\u8D25 (${attempt}/3): ${(e as Error).message}\uFF0C${wait / 1000}s \u540E\u91CD\u8BD5...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n }\n }\n throw lastErr instanceof Error ? lastErr : new Error(\"\u7248\u672C\u53F7\u83B7\u53D6\u5931\u8D25\");\n}\n\n/** \u83B7\u53D6 per-version \u7684\u4E0B\u8F7D\u94FE\u63A5 + \u54C8\u5E0C (fallback GitHub \u2192 jsdelivr) */\nexport async function fetchVersionDetails(\n cfg: BdsUpdaterConfig,\n channel: string,\n version: string\n): Promise<VersionDetails> {\n const platform = channel === \"preview\" ? \"windows_preview\" : \"windows\";\n const ch = channel === \"preview\" ? \"preview\" : \"release\";\n const vars = { version, ver3: toVer3(version), platform, channel: ch };\n const detailsTpl =\n cfg.version_details || \"https://raw.githubusercontent.com/Bedrock-OSS/BDS-Versions/main/{platform}/{version}.json\";\n const mirrorTpl =\n cfg.version_details_mirror || \"https://cdn.jsdelivr.net/gh/Bedrock-OSS/BDS-Versions@main/{platform}/{version}.json\";\n const sources = [detailsTpl, mirrorTpl].filter(Boolean).map((t) => resolveTemplate(t, vars));\n\n const json = await fetchJsonWithFallback<any>(sources);\n const mode = cfg.version_mode || \"bedrock-oss\";\n if (mode === \"endstone\") {\n const bw = json.binary?.windows;\n return {\n downloadUrl: bw?.url ?? \"\",\n sha1: \"\",\n sha256: bw?.sha256 ?? \"\",\n size: bw?.size_in_bytes ?? 0,\n };\n }\n return {\n downloadUrl: json.download_url ?? \"\",\n sha1: json.sha1 ?? \"\",\n sha256: \"\",\n size: json.size_in_bytes ?? 0,\n };\n}\n\n/** \u5019\u9009\u4E0B\u8F7D URL (\u6309\u4F18\u5148\u7EA7) */\nexport function buildDownloadUrls(\n cfg: BdsUpdaterConfig,\n channel: string,\n version: string,\n details: VersionDetails\n): string[] {\n const urls: string[] = [];\n if (cfg.download_mirror) {\n const mirrorVer = channel === \"preview\" ? `${version}-preview` : version;\n urls.push(resolveTemplate(cfg.download_mirror, { version: mirrorVer }));\n }\n if (details.downloadUrl) urls.push(details.downloadUrl);\n const cdnRoot = cfg.cdn_root || \"https://www.minecraft.net/bedrockdedicatedserver\";\n const suffix =\n channel === \"preview\"\n ? `/bin-win-preview/bedrock-server-${version}-preview.zip`\n : `/bin-win/bedrock-server-${version}.zip`;\n urls.push(cdnRoot + suffix);\n urls.push(`https://minecraft.azureedge.net${suffix}`);\n return [...new Set(urls)];\n}\n\n/** \u540C\u6B65 / \u5F02\u6B65\u6821\u9A8C\u6587\u4EF6\u54C8\u5E0C */\nexport async function verifyFileHash(filePath: string, expectedSha1: string, expectedSha256: string): Promise<boolean> {\n const expected = expectedSha256 || expectedSha1;\n if (!expected) return true;\n const algo: \"sha1\" | \"sha256\" = expectedSha256 ? \"sha256\" : \"sha1\";\n\n return new Promise((resolve, reject) => {\n const h = crypto.createHash(algo);\n const stream = fs.createReadStream(filePath);\n stream.on(\"data\", (chunk: Buffer | string) => {\n h.update(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n stream.on(\"end\", () => {\n const actual = h.digest(\"hex\").toLowerCase();\n resolve(actual === expected.toLowerCase());\n });\n stream.on(\"error\", reject);\n });\n}\n\n/** \u68C0\u67E5\u7248\u672C\u517C\u5BB9\u6027 (\u767D\u540D\u5355) */\nexport function isVersionCompatible(cfg: BdsUpdaterConfig, version: string): boolean {\n const allow = cfg.compatible_versions;\n if (!allow || allow.length === 0) return true;\n return allow.includes(version) || allow.includes(toVer3(version));\n}\n\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * upstream.ts \u2014 BDS \u4E0A\u6E38\u7248\u672C\u6E90\u3001\u591A\u955C\u50CF\u4E0B\u8F7D\u4E0E\u5B8C\u6574\u6027\u6821\u9A8C\n *\n * \u6838\u5FC3\u673A\u5236\uFF1A\n * - \u591A\u6E90\u5BB9\u707E\uFF1A\u5B98\u65B9\u6E90\u4E0E\u955C\u50CF\u6E90\u5E76\u884C\u7ADE\u4E89\u4E0E\u591A\u8F6E\u6307\u6570\u9000\u907F\u91CD\u8BD5\n * - \u52A8\u6001 URL \u6A21\u677F\u6E32\u67D3\uFF1A\u6839\u636E\u64CD\u4F5C\u7CFB\u7EDF\u67B6\u6784\u4E0E\u66F4\u65B0\u901A\u9053\u8BA1\u7B97\u4E0B\u8F7D\u5730\u5740\n * - \u6D41\u5F0F\u54C8\u5E0C\u6821\u9A8C\uFF1A\u652F\u6301 SHA-1 \u4E0E SHA-256 \u5B8C\u6574\u6027\u6D41\u5F0F\u8BA1\u7B97\u6821\u9A8C\n * - \u7248\u672C\u767D\u540D\u5355\u517C\u5BB9\u95E8\u7981\uFF1A\u9632\u6B62\u81EA\u52A8\u5347\u7EA7\u81F3\u672A\u9A8C\u8BC1\u7248\u672C\n */\n\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport { bdsCdnZipSuffix, bdsDetailsPlatformKey, bdsHostOs, type BdsHostOs } from \"./host-platform.js\";\nimport { fetchJsonWithFallback } from \"./http.js\";\nimport { log } from \"./log.js\";\nimport type { BdsUpdaterConfig, VersionDetails, VersionInfo } from \"./types.js\";\nimport { toVer3 } from \"./version.js\";\n\nconst DEFAULT_VERSIONS_API = \"https://raw.githubusercontent.com/Bedrock-OSS/BDS-Versions/main/versions.json\";\nconst DEFAULT_VERSIONS_MIRROR = \"https://cdn.jsdelivr.net/gh/Bedrock-OSS/BDS-Versions@main/versions.json\";\n\nfunction resolveTemplate(tpl: string, vars: Record<string, string>): string {\n let s = tpl;\n for (const [k, v] of Object.entries(vars)) {\n s = s.replace(new RegExp(`\\\\{${k}\\\\}`, \"g\"), v);\n }\n return s;\n}\n\n/**\n * \u83B7\u53D6 BDS \u6700\u65B0\u53EF\u7528\u7248\u672C\u4FE1\u606F\uFF08\u652F\u6301\u91CD\u8BD5\u4E0E\u6307\u6570\u9000\u907F\uFF09\u3002\n *\n * @param cfg BDS \u66F4\u65B0\u5668\u914D\u7F6E\u3002\n * @param channel \u66F4\u65B0\u901A\u9053\uFF08\u5982 \"release\" \u6216 \"preview\"\uFF09\u3002\n * @param hostOs \u76EE\u6807\u4E3B\u673A\u64CD\u4F5C\u7CFB\u7EDF\u7C7B\u578B\u3002\n * @returns \u5305\u542B\u6700\u65B0\u7248\u672C\u53F7\u4E0E CDN \u6839\u8DEF\u5F84\u7684\u4FE1\u606F\u5BF9\u8C61\u3002\n */\nexport async function getVersionInfo(\n\n cfg: BdsUpdaterConfig,\n channel: string,\n hostOs: BdsHostOs = bdsHostOs()\n): Promise<VersionInfo> {\n const api = cfg.version_versions || process.env[\"BDS_VERSIONS_API\"] || DEFAULT_VERSIONS_API;\n const mirror = cfg.version_versions_mirror || process.env[\"BDS_VERSIONS_MIRROR\"] || DEFAULT_VERSIONS_MIRROR;\n const sources = [api, mirror].filter(Boolean);\n const versionMode = cfg.version_mode || \"bedrock-oss\";\n\n let lastErr: unknown;\n for (let attempt = 1; attempt <= 3; attempt++) {\n try {\n const json = await fetchJsonWithFallback<any>(sources);\n let ver: string | undefined;\n if (versionMode === \"endstone\") {\n const entry = channel === \"preview\" ? json.preview : json.release;\n ver = entry?.latest;\n } else {\n const platform = hostOs === \"windows\" ? json.windows || json.linux : json.linux || json.windows;\n ver = channel === \"preview\" ? platform?.preview : platform?.stable;\n }\n if (!ver) throw new Error(\"\u672A\u627E\u5230\u6700\u65B0\u7248\u672C\u53F7\");\n return { version: ver, cdnRoot: json.cdn_root ?? \"\" };\n } catch (e) {\n lastErr = e;\n if (attempt < 3) {\n const wait = attempt * 3000;\n log.warn(`\u7248\u672C\u53F7\u83B7\u53D6\u5931\u8D25 (${attempt}/3): ${(e as Error).message}\uFF0C${wait / 1000}s \u540E\u91CD\u8BD5...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n }\n }\n throw lastErr instanceof Error ? lastErr : new Error(\"\u7248\u672C\u53F7\u83B7\u53D6\u5931\u8D25\");\n}\n\n/** \u83B7\u53D6 per-version \u7684\u4E0B\u8F7D\u94FE\u63A5 + \u54C8\u5E0C (fallback GitHub \u2192 jsdelivr) */\nexport async function fetchVersionDetails(\n cfg: BdsUpdaterConfig,\n channel: string,\n version: string,\n hostOs: BdsHostOs = bdsHostOs()\n): Promise<VersionDetails> {\n const platform = bdsDetailsPlatformKey(channel, hostOs);\n const ch = channel === \"preview\" ? \"preview\" : \"release\";\n const vars = { version, ver3: toVer3(version), platform, channel: ch };\n const detailsTpl =\n cfg.version_details || \"https://raw.githubusercontent.com/Bedrock-OSS/BDS-Versions/main/{platform}/{version}.json\";\n const mirrorTpl =\n cfg.version_details_mirror || \"https://cdn.jsdelivr.net/gh/Bedrock-OSS/BDS-Versions@main/{platform}/{version}.json\";\n const sources = [detailsTpl, mirrorTpl].filter(Boolean).map((t) => resolveTemplate(t, vars));\n\n const json = await fetchJsonWithFallback<any>(sources);\n const mode = cfg.version_mode || \"bedrock-oss\";\n if (mode === \"endstone\") {\n const bw = hostOs === \"windows\" ? json.binary?.windows : json.binary?.linux;\n return {\n downloadUrl: bw?.url ?? \"\",\n sha1: \"\",\n sha256: bw?.sha256 ?? \"\",\n size: bw?.size_in_bytes ?? 0,\n };\n }\n return {\n downloadUrl: json.download_url ?? \"\",\n sha1: json.sha1 ?? \"\",\n sha256: \"\",\n size: json.size_in_bytes ?? 0,\n };\n}\n\n/** \u5019\u9009\u4E0B\u8F7D URL (\u6309\u4F18\u5148\u7EA7) */\nexport function buildDownloadUrls(\n cfg: BdsUpdaterConfig,\n channel: string,\n version: string,\n details: VersionDetails,\n hostOs: BdsHostOs = bdsHostOs()\n): string[] {\n const urls: string[] = [];\n if (cfg.download_mirror) {\n const mirrorVer = channel === \"preview\" ? `${version}-preview` : version;\n urls.push(resolveTemplate(cfg.download_mirror, { version: mirrorVer }));\n }\n if (details.downloadUrl) urls.push(details.downloadUrl);\n const cdnRoot = cfg.cdn_root || \"https://www.minecraft.net/bedrockdedicatedserver\";\n const suffix = bdsCdnZipSuffix(channel, version, hostOs);\n urls.push(cdnRoot + suffix);\n urls.push(`https://minecraft.azureedge.net${suffix}`);\n return [...new Set(urls)];\n}\n\n/** \u540C\u6B65 / \u5F02\u6B65\u6821\u9A8C\u6587\u4EF6\u54C8\u5E0C */\nexport async function verifyFileHash(filePath: string, expectedSha1: string, expectedSha256: string): Promise<boolean> {\n const expected = expectedSha256 || expectedSha1;\n if (!expected) return true;\n const algo: \"sha1\" | \"sha256\" = expectedSha256 ? \"sha256\" : \"sha1\";\n\n return new Promise((resolve, reject) => {\n const h = crypto.createHash(algo);\n const stream = fs.createReadStream(filePath);\n stream.on(\"data\", (chunk: Buffer | string) => {\n h.update(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n stream.on(\"end\", () => {\n const actual = h.digest(\"hex\").toLowerCase();\n resolve(actual === expected.toLowerCase());\n });\n stream.on(\"error\", reject);\n });\n}\n\n/** \u68C0\u67E5\u7248\u672C\u517C\u5BB9\u6027 (\u767D\u540D\u5355) */\nexport function isVersionCompatible(cfg: BdsUpdaterConfig, version: string): boolean {\n const allow = cfg.compatible_versions;\n if (!allow || allow.length === 0) return true;\n return allow.includes(version) || allow.includes(toVer3(version));\n}\n\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/version.js CHANGED
@@ -53,7 +53,7 @@ async function getCurrentVersionAsync(exePath) {
53
53
  for (const [ver, entry] of Object.entries(cache)) {
54
54
  if (entry.sha256 === actual) return ver;
55
55
  }
56
- log.warn("[BDSUpdater] bedrock_server.exe \u54C8\u5E0C\u672A\u5339\u914D\u7F13\u5B58\uFF0C\u7591\u4F3C\u88AB\u6539\u52A8\u6216\u9996\u6B21\u542F\u52A8");
56
+ log.warn("[BDSUpdater] BDS \u53EF\u6267\u884C\u6587\u4EF6\u54C8\u5E0C\u672A\u5339\u914D\u7F13\u5B58\uFF0C\u7591\u4F3C\u88AB\u6539\u52A8\u6216\u9996\u6B21\u542F\u52A8");
57
57
  return "0.0.0.0";
58
58
  }
59
59
  function getCurrentVersionSync(exePath) {
@@ -64,7 +64,7 @@ function getCurrentVersionSync(exePath) {
64
64
  for (const [ver, entry] of Object.entries(cache)) {
65
65
  if (entry.sha256 === actual) return ver;
66
66
  }
67
- log.warn("[BDSUpdater] bedrock_server.exe \u54C8\u5E0C\u672A\u5339\u914D\u7F13\u5B58");
67
+ log.warn("[BDSUpdater] BDS \u53EF\u6267\u884C\u6587\u4EF6\u54C8\u5E0C\u672A\u5339\u914D\u7F13\u5B58");
68
68
  return "0.0.0.0";
69
69
  }
70
70
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["/**\n * version.ts \u2014 \u7248\u672C\u53F7\u5DE5\u5177 / \u7248\u672C\u7F13\u5B58\n */\n\nimport { readJson, writeJson } from \"@sfmc-bds/sdk/node/config\";\nimport fs from \"node:fs\";\nimport { VERSION_CACHE } from \"./paths.js\";\nimport { hashFileSync, hashFileAsync } from \"./fsx.js\";\nimport { log } from \"./log.js\";\n\n/** 4\u6BB5 \u2192 3\u6BB5 (\u53BB\u5C3E) */\nexport function toVer3(v: string): string {\n return v.split(\".\").slice(0, 3).join(\".\");\n}\n\n/** 3\u6BB5 \u2192 4\u6BB5 (\u8865 0) */\nexport function toVer4(v: string): string {\n const p = v.split(\".\");\n while (p.length < 4) p.push(\"0\");\n return p.join(\".\");\n}\n\n/** \u7248\u672C\u6BD4\u8F83 (\u6309 4 \u6BB5\u6570\u5B57\u6392\u5E8F) */\nexport function compareVersions(a: string, b: string): number {\n const sa = a.replace(/-preview$/, \"\");\n const sb = b.replace(/-preview$/, \"\");\n const pa = sa.split(\".\").map(Number);\n const pb = sb.split(\".\").map(Number);\n for (let i = 0; i < 4; i++) {\n const ai = pa[i] ?? 0;\n const bi = pb[i] ?? 0;\n if (ai !== bi) return ai - bi;\n }\n // preview \u4F4E\u4E8E\u4E0D\u5E26 -preview \u7684\u540C\u4E00\u6570\u5B57\n if (a.endsWith(\"-preview\") && !b.endsWith(\"-preview\")) return -1;\n if (!a.endsWith(\"-preview\") && b.endsWith(\"-preview\")) return 1;\n return 0;\n}\n\n/** \u7B80\u5355\u7684\u771F\u503C\u6821\u9A8C (\u6309\u7248\u672C\u53F7\u5916\u5F62) */\nexport function isValidVersion(v: string): boolean {\n return /^\\d+\\.\\d+\\.\\d+(\\.\\d+)?(-preview)?$/.test(v);\n}\n\n/** \u7F13\u5B58\u6761\u76EE\u7C7B\u578B */\ninterface CacheEntry {\n sha256: string;\n verified_at: number;\n}\n\nfunction readCache(): Record<string, CacheEntry> {\n return readJson<Record<string, CacheEntry>>(VERSION_CACHE) ?? {};\n}\n\n/** \u4EC5\u4FDD\u7559\u6700\u8FD1 3 \u6761\u7248\u672C\u7F13\u5B58 (\u907F\u514D\u65E0\u9650\u589E\u957F) */\nfunction trimCache(cache: Record<string, CacheEntry>): Record<string, CacheEntry> {\n const keys = Object.keys(cache).sort(compareVersions).slice(-3);\n const trimmed: Record<string, CacheEntry> = {};\n for (const k of keys) trimmed[k] = cache[k]!;\n return trimmed;\n}\n\nexport function saveVersionCache(version: string, sha256: string): void {\n const cache = readCache();\n cache[version] = { sha256, verified_at: Date.now() };\n try {\n writeJson(VERSION_CACHE, trimCache(cache));\n } catch {\n /* ignore */\n }\n}\n\n/**\n * \u5F02\u6B65\u8BC6\u522B\u5F53\u524D BDS \u7248\u672C\n * \u4F18\u5148\u901A\u8FC7 SHA256 \u53CD\u67E5\u7F13\u5B58\uFF0C\u5931\u8D25\u5219\u56DE\u9000 `current_version.txt`\uFF08\u5982\u679C\u5B58\u5728\uFF09\n */\nexport async function getCurrentVersionAsync(exePath: string): Promise<string> {\n if (!fs.existsSync(exePath)) return \"0.0.0.0\";\n const actual = await hashFileAsync(exePath, \"sha256\");\n if (!actual) return \"0.0.0.0\";\n\n const cache = readCache();\n for (const [ver, entry] of Object.entries(cache)) {\n if (entry.sha256 === actual) return ver;\n }\n log.warn(\"[BDSUpdater] bedrock_server.exe \u54C8\u5E0C\u672A\u5339\u914D\u7F13\u5B58\uFF0C\u7591\u4F3C\u88AB\u6539\u52A8\u6216\u9996\u6B21\u542F\u52A8\");\n return \"0.0.0.0\";\n}\n\n/** \u540C\u6B65\u7248\u672C (\u517C\u5BB9\u65E7\u6D41\u7A0B) */\nexport function getCurrentVersionSync(exePath: string): string {\n if (!fs.existsSync(exePath)) return \"0.0.0.0\";\n const actual = hashFileSync(exePath, \"sha256\");\n if (!actual) return \"0.0.0.0\";\n const cache = readCache();\n for (const [ver, entry] of Object.entries(cache)) {\n if (entry.sha256 === actual) return ver;\n }\n log.warn(\"[BDSUpdater] bedrock_server.exe \u54C8\u5E0C\u672A\u5339\u914D\u7F13\u5B58\");\n return \"0.0.0.0\";\n}\n"],
5
- "mappings": "AAIA,SAAS,UAAU,iBAAiB;AACpC,OAAO,QAAQ;AACf,SAAS,qBAAqB;AAC9B,SAAS,cAAc,qBAAqB;AAC5C,SAAS,WAAW;AAGb,SAAS,OAAO,GAAmB;AACxC,SAAO,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG;AAC1C;AAGO,SAAS,OAAO,GAAmB;AACxC,QAAM,IAAI,EAAE,MAAM,GAAG;AACrB,SAAO,EAAE,SAAS,EAAG,GAAE,KAAK,GAAG;AAC/B,SAAO,EAAE,KAAK,GAAG;AACnB;AAGO,SAAS,gBAAgB,GAAW,GAAmB;AAC5D,QAAM,KAAK,EAAE,QAAQ,aAAa,EAAE;AACpC,QAAM,KAAK,EAAE,QAAQ,aAAa,EAAE;AACpC,QAAM,KAAK,GAAG,MAAM,GAAG,EAAE,IAAI,MAAM;AACnC,QAAM,KAAK,GAAG,MAAM,GAAG,EAAE,IAAI,MAAM;AACnC,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,QAAI,OAAO,GAAI,QAAO,KAAK;AAAA,EAC7B;AAEA,MAAI,EAAE,SAAS,UAAU,KAAK,CAAC,EAAE,SAAS,UAAU,EAAG,QAAO;AAC9D,MAAI,CAAC,EAAE,SAAS,UAAU,KAAK,EAAE,SAAS,UAAU,EAAG,QAAO;AAC9D,SAAO;AACT;AAGO,SAAS,eAAe,GAAoB;AACjD,SAAO,qCAAqC,KAAK,CAAC;AACpD;AAQA,SAAS,YAAwC;AAC/C,SAAO,SAAqC,aAAa,KAAK,CAAC;AACjE;AAGA,SAAS,UAAU,OAA+D;AAChF,QAAM,OAAO,OAAO,KAAK,KAAK,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE;AAC9D,QAAM,UAAsC,CAAC;AAC7C,aAAW,KAAK,KAAM,SAAQ,CAAC,IAAI,MAAM,CAAC;AAC1C,SAAO;AACT;AAEO,SAAS,iBAAiB,SAAiB,QAAsB;AACtE,QAAM,QAAQ,UAAU;AACxB,QAAM,OAAO,IAAI,EAAE,QAAQ,aAAa,KAAK,IAAI,EAAE;AACnD,MAAI;AACF,cAAU,eAAe,UAAU,KAAK,CAAC;AAAA,EAC3C,QAAQ;AAAA,EAER;AACF;AAMA,eAAsB,uBAAuB,SAAkC;AAC7E,MAAI,CAAC,GAAG,WAAW,OAAO,EAAG,QAAO;AACpC,QAAM,SAAS,MAAM,cAAc,SAAS,QAAQ;AACpD,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,QAAQ,UAAU;AACxB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,MAAM,WAAW,OAAQ,QAAO;AAAA,EACtC;AACA,MAAI,KAAK,8IAAoD;AAC7D,SAAO;AACT;AAGO,SAAS,sBAAsB,SAAyB;AAC7D,MAAI,CAAC,GAAG,WAAW,OAAO,EAAG,QAAO;AACpC,QAAM,SAAS,aAAa,SAAS,QAAQ;AAC7C,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,QAAQ,UAAU;AACxB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,MAAM,WAAW,OAAQ,QAAO;AAAA,EACtC;AACA,MAAI,KAAK,4EAAyC;AAClD,SAAO;AACT;",
4
+ "sourcesContent": ["/**\n * version.ts \u2014 \u7248\u672C\u53F7\u5DE5\u5177 / \u7248\u672C\u7F13\u5B58\n */\n\nimport { readJson, writeJson } from \"@sfmc-bds/sdk/node/config\";\nimport fs from \"node:fs\";\nimport { VERSION_CACHE } from \"./paths.js\";\nimport { hashFileSync, hashFileAsync } from \"./fsx.js\";\nimport { log } from \"./log.js\";\n\n/** 4\u6BB5 \u2192 3\u6BB5 (\u53BB\u5C3E) */\nexport function toVer3(v: string): string {\n return v.split(\".\").slice(0, 3).join(\".\");\n}\n\n/** 3\u6BB5 \u2192 4\u6BB5 (\u8865 0) */\nexport function toVer4(v: string): string {\n const p = v.split(\".\");\n while (p.length < 4) p.push(\"0\");\n return p.join(\".\");\n}\n\n/** \u7248\u672C\u6BD4\u8F83 (\u6309 4 \u6BB5\u6570\u5B57\u6392\u5E8F) */\nexport function compareVersions(a: string, b: string): number {\n const sa = a.replace(/-preview$/, \"\");\n const sb = b.replace(/-preview$/, \"\");\n const pa = sa.split(\".\").map(Number);\n const pb = sb.split(\".\").map(Number);\n for (let i = 0; i < 4; i++) {\n const ai = pa[i] ?? 0;\n const bi = pb[i] ?? 0;\n if (ai !== bi) return ai - bi;\n }\n // preview \u4F4E\u4E8E\u4E0D\u5E26 -preview \u7684\u540C\u4E00\u6570\u5B57\n if (a.endsWith(\"-preview\") && !b.endsWith(\"-preview\")) return -1;\n if (!a.endsWith(\"-preview\") && b.endsWith(\"-preview\")) return 1;\n return 0;\n}\n\n/** \u7B80\u5355\u7684\u771F\u503C\u6821\u9A8C (\u6309\u7248\u672C\u53F7\u5916\u5F62) */\nexport function isValidVersion(v: string): boolean {\n return /^\\d+\\.\\d+\\.\\d+(\\.\\d+)?(-preview)?$/.test(v);\n}\n\n/** \u7F13\u5B58\u6761\u76EE\u7C7B\u578B */\ninterface CacheEntry {\n sha256: string;\n verified_at: number;\n}\n\nfunction readCache(): Record<string, CacheEntry> {\n return readJson<Record<string, CacheEntry>>(VERSION_CACHE) ?? {};\n}\n\n/** \u4EC5\u4FDD\u7559\u6700\u8FD1 3 \u6761\u7248\u672C\u7F13\u5B58 (\u907F\u514D\u65E0\u9650\u589E\u957F) */\nfunction trimCache(cache: Record<string, CacheEntry>): Record<string, CacheEntry> {\n const keys = Object.keys(cache).sort(compareVersions).slice(-3);\n const trimmed: Record<string, CacheEntry> = {};\n for (const k of keys) trimmed[k] = cache[k]!;\n return trimmed;\n}\n\nexport function saveVersionCache(version: string, sha256: string): void {\n const cache = readCache();\n cache[version] = { sha256, verified_at: Date.now() };\n try {\n writeJson(VERSION_CACHE, trimCache(cache));\n } catch {\n /* ignore */\n }\n}\n\n/**\n * \u5F02\u6B65\u8BC6\u522B\u5F53\u524D BDS \u7248\u672C\n * \u4F18\u5148\u901A\u8FC7 SHA256 \u53CD\u67E5\u7F13\u5B58\uFF0C\u5931\u8D25\u5219\u56DE\u9000 `current_version.txt`\uFF08\u5982\u679C\u5B58\u5728\uFF09\n */\nexport async function getCurrentVersionAsync(exePath: string): Promise<string> {\n if (!fs.existsSync(exePath)) return \"0.0.0.0\";\n const actual = await hashFileAsync(exePath, \"sha256\");\n if (!actual) return \"0.0.0.0\";\n\n const cache = readCache();\n for (const [ver, entry] of Object.entries(cache)) {\n if (entry.sha256 === actual) return ver;\n }\n log.warn(\"[BDSUpdater] BDS \u53EF\u6267\u884C\u6587\u4EF6\u54C8\u5E0C\u672A\u5339\u914D\u7F13\u5B58\uFF0C\u7591\u4F3C\u88AB\u6539\u52A8\u6216\u9996\u6B21\u542F\u52A8\");\n return \"0.0.0.0\";\n}\n\n/** \u540C\u6B65\u7248\u672C (\u517C\u5BB9\u65E7\u6D41\u7A0B) */\nexport function getCurrentVersionSync(exePath: string): string {\n if (!fs.existsSync(exePath)) return \"0.0.0.0\";\n const actual = hashFileSync(exePath, \"sha256\");\n if (!actual) return \"0.0.0.0\";\n const cache = readCache();\n for (const [ver, entry] of Object.entries(cache)) {\n if (entry.sha256 === actual) return ver;\n }\n log.warn(\"[BDSUpdater] BDS \u53EF\u6267\u884C\u6587\u4EF6\u54C8\u5E0C\u672A\u5339\u914D\u7F13\u5B58\");\n return \"0.0.0.0\";\n}\n"],
5
+ "mappings": "AAIA,SAAS,UAAU,iBAAiB;AACpC,OAAO,QAAQ;AACf,SAAS,qBAAqB;AAC9B,SAAS,cAAc,qBAAqB;AAC5C,SAAS,WAAW;AAGb,SAAS,OAAO,GAAmB;AACxC,SAAO,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG;AAC1C;AAGO,SAAS,OAAO,GAAmB;AACxC,QAAM,IAAI,EAAE,MAAM,GAAG;AACrB,SAAO,EAAE,SAAS,EAAG,GAAE,KAAK,GAAG;AAC/B,SAAO,EAAE,KAAK,GAAG;AACnB;AAGO,SAAS,gBAAgB,GAAW,GAAmB;AAC5D,QAAM,KAAK,EAAE,QAAQ,aAAa,EAAE;AACpC,QAAM,KAAK,EAAE,QAAQ,aAAa,EAAE;AACpC,QAAM,KAAK,GAAG,MAAM,GAAG,EAAE,IAAI,MAAM;AACnC,QAAM,KAAK,GAAG,MAAM,GAAG,EAAE,IAAI,MAAM;AACnC,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,QAAI,OAAO,GAAI,QAAO,KAAK;AAAA,EAC7B;AAEA,MAAI,EAAE,SAAS,UAAU,KAAK,CAAC,EAAE,SAAS,UAAU,EAAG,QAAO;AAC9D,MAAI,CAAC,EAAE,SAAS,UAAU,KAAK,EAAE,SAAS,UAAU,EAAG,QAAO;AAC9D,SAAO;AACT;AAGO,SAAS,eAAe,GAAoB;AACjD,SAAO,qCAAqC,KAAK,CAAC;AACpD;AAQA,SAAS,YAAwC;AAC/C,SAAO,SAAqC,aAAa,KAAK,CAAC;AACjE;AAGA,SAAS,UAAU,OAA+D;AAChF,QAAM,OAAO,OAAO,KAAK,KAAK,EAAE,KAAK,eAAe,EAAE,MAAM,EAAE;AAC9D,QAAM,UAAsC,CAAC;AAC7C,aAAW,KAAK,KAAM,SAAQ,CAAC,IAAI,MAAM,CAAC;AAC1C,SAAO;AACT;AAEO,SAAS,iBAAiB,SAAiB,QAAsB;AACtE,QAAM,QAAQ,UAAU;AACxB,QAAM,OAAO,IAAI,EAAE,QAAQ,aAAa,KAAK,IAAI,EAAE;AACnD,MAAI;AACF,cAAU,eAAe,UAAU,KAAK,CAAC;AAAA,EAC3C,QAAQ;AAAA,EAER;AACF;AAMA,eAAsB,uBAAuB,SAAkC;AAC7E,MAAI,CAAC,GAAG,WAAW,OAAO,EAAG,QAAO;AACpC,QAAM,SAAS,MAAM,cAAc,SAAS,QAAQ;AACpD,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,QAAQ,UAAU;AACxB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,MAAM,WAAW,OAAQ,QAAO;AAAA,EACtC;AACA,MAAI,KAAK,6JAA0C;AACnD,SAAO;AACT;AAGO,SAAS,sBAAsB,SAAyB;AAC7D,MAAI,CAAC,GAAG,WAAW,OAAO,EAAG,QAAO;AACpC,QAAM,SAAS,aAAa,SAAS,QAAQ;AAC7C,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,QAAQ,UAAU;AACxB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,MAAM,WAAW,OAAQ,QAAO;AAAA,EACtC;AACA,MAAI,KAAK,2FAA+B;AACxC,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,12 @@
1
- import { Utf8BomError } from "./fsx.js";
1
+ /**
2
+ * world-packs.ts — 通用 Minecraft 基岩版世界行为包(BP)与资源包(RP)管理工具
3
+ *
4
+ * 核心能力:
5
+ * - 格式与命名规范化:过滤 Minecraft 颜色格式码,自动补充 `[BP]` / `[RP]` 前缀及冲突避让
6
+ * - 压缩包递归解构:支持 `.zip`、`.mcpack`、`.mcaddon` 嵌套包解压并智能识别 BP 与 RP 根目录
7
+ * - 版本递增与同步:同步升级 manifest 中的版本元数据并对齐世界启用清单版本
8
+ * - 幂等安装与回滚:按 UUID 精确匹配升级与安装计划,支持删除备份至回收站机制
9
+ */
2
10
  import { type WorldPackListReadResult } from "./pack-manager.js";
3
11
  export type WorldPackKind = "behavior" | "resource";
4
12
  export interface PackManifestInfo {
@@ -27,13 +35,24 @@ export declare function stripWorldPackFolderPrefix(rawName: string): string;
27
35
  */
28
36
  export declare function isGenericPackFolderStem(rawName: string): boolean;
29
37
  /**
30
- * 选定安装文件夹名:hint 过泛时改用 manifest.name;再与 dest 内已有目录避让(不同 uuid 不互相覆盖)。
38
+ * 选定安装文件夹名:hint 过泛时改用 manifest.name;再与已占用名避让(不同 uuid 不互相覆盖)。
39
+ * 纯函数:只依赖 taken 集合,便于表驱动单测(DRY:decide / choose 共用)。
40
+ */
41
+ export declare function allocatePackFolderName(opts: {
42
+ hint?: string;
43
+ info: PackManifestInfo;
44
+ takenFolderNames: Iterable<string>;
45
+ /** 同 uuid 更新时允许占用的已有目录名(不触发避让) */
46
+ allowFolderName?: string;
47
+ }): string;
48
+ /**
49
+ * 选定安装文件夹名(读 destParent 占用)。
50
+ * 决策权威见 allocatePackFolderName / decidePackInstallPlan。
31
51
  */
32
52
  export declare function choosePackInstallFolderName(opts: {
33
53
  hint?: string;
34
54
  info: PackManifestInfo;
35
55
  destParent: string;
36
- /** 同 uuid 更新时允许占用的已有目录名(不触发避让) */
37
56
  allowFolderName?: string;
38
57
  }): string;
39
58
  /** 根据 manifest modules[].type 判定 BP / RP */
@@ -43,7 +62,6 @@ export declare function detectPackKindFromManifest(raw: {
43
62
  }>;
44
63
  }): WorldPackKind | null;
45
64
  export declare function readPackManifestInfo(packDir: string): PackManifestInfo | null;
46
- export { Utf8BomError };
47
65
  /** 深度优先找含 manifest.json 的包根(默认 maxDepth=2,root 自身为 depth 0) */
48
66
  export declare function discoverPackRoots(root: string, opts?: {
49
67
  maxDepth?: number;
@@ -82,9 +100,20 @@ export declare function resolvePackRoots(src: string, opts?: {
82
100
  export declare function extractArchiveToTemp(filePath: string): Promise<string>;
83
101
  /** 扫描世界内已安装 BP/RP 目录 */
84
102
  export declare function listInstalledWorldPacks(bdsRoot: string, levelName: string): InstalledWorldPack[];
85
- /** RP/BP 第三位版本 +1,写回 manifest */
103
+ /**
104
+ * 将目标包 manifest.json 中的 Patch 版本号递增(+1)并持久化写回。
105
+ *
106
+ * @param packDir 包根目录路径。
107
+ * @returns 递增后的版本三元组 `[major, minor, patch]`。
108
+ */
86
109
  export declare function bumpPackPatchVersion(packDir: string): [number, number, number];
87
- /** 写入 header.version(并同步 modules[].version 的 patch) */
110
+ /**
111
+ * 向目标包的 manifest.json 写入新的版本号,并同步更新内部 modules 的 patch 版本。
112
+ *
113
+ * @param packDir 包根目录路径。
114
+ * @param next 待写入的版本三元组。
115
+ * @returns 写入确认的版本三元组。
116
+ */
88
117
  export declare function writePackHeaderVersion(packDir: string, next: [number, number, number]): [number, number, number];
89
118
  /** 读取 BP manifest 中依赖的资源包 uuid(非 @minecraft 模块) */
90
119
  export declare function readPackDependencyUuids(packDir: string): string[];
@@ -118,9 +147,71 @@ export interface InstallPackResult {
118
147
  incoming: PackManifestInfo;
119
148
  };
120
149
  }
150
+ /** 目标父目录内已占用项(供纯决策,不含 FS 副作用) */
151
+ export type DestOccupancy = {
152
+ folderName: string;
153
+ dir: string;
154
+ uuid: string | null;
155
+ version: [number, number, number] | null;
156
+ /** 可读时的展示名;决策不依赖,仅供 conflict UI */
157
+ name?: string;
158
+ /** 可读时的包类型;决策展示优先用真实 kind,避免伪造 incoming.kind(LSP) */
159
+ kind?: WorldPackKind;
160
+ };
161
+ export type PackInstallPlan = {
162
+ kind: "fresh";
163
+ folderName: string;
164
+ incoming: PackManifestInfo;
165
+ } | {
166
+ kind: "overwriteInPlace";
167
+ folderName: string;
168
+ dir: string;
169
+ incoming: PackManifestInfo;
170
+ existing: PackManifestInfo & {
171
+ dir: string;
172
+ };
173
+ } | {
174
+ kind: "needConfirm";
175
+ folderName: string;
176
+ dir: string;
177
+ incoming: PackManifestInfo;
178
+ existing: PackManifestInfo & {
179
+ dir: string;
180
+ };
181
+ };
182
+ /**
183
+ * 读单目录占用事实(info 优先,否则 header)。
184
+ * 解析失败返回 null;不抛 BOM(readJsonFile 已剥离)。
185
+ */
186
+ export declare function readPackDirOccupancy(dir: string): {
187
+ uuid: string;
188
+ version: [number, number, number];
189
+ name?: string;
190
+ kind?: WorldPackKind;
191
+ } | null;
192
+ /** 扫描 destParent 下含 manifest 的目录占用(单一事实源:readPackDirOccupancy) */
193
+ export declare function scanDestOccupancy(destParent: string): DestOccupancy[];
194
+ /**
195
+ * 纯决策:装到哪、是否需确认、是否原地覆盖。
196
+ * 同 uuid:incoming 版本严格更大 → 静默覆盖;≤ 已有且 !force → needConfirm;force → 原地覆盖。
197
+ */
198
+ export declare function decidePackInstallPlan(opts: {
199
+ incoming: PackManifestInfo;
200
+ hint?: string;
201
+ occupancy: readonly DestOccupancy[];
202
+ force?: boolean;
203
+ }): PackInstallPlan;
204
+ /** 落盘后校验:防止旁路安装 / 拷贝失败仍报成功 */
205
+ export declare function verifyInstalledPack(destDir: string, incoming: PackManifestInfo): {
206
+ ok: true;
207
+ info: PackManifestInfo;
208
+ } | {
209
+ ok: false;
210
+ reason: string;
211
+ };
121
212
  /**
122
213
  * 将包目录安装到 destParent(behavior_packs 或 resource_packs)。
123
- * force=true 时覆盖「同 uuid」冲突;同名不同 uuid 会自动换文件夹名,不删别人的包。
214
+ * 编排:scan decide → apply → verify。同 uuid 版本更高时静默原地覆盖。
124
215
  */
125
216
  export declare function installPackDirectory(opts: {
126
217
  srcDir: string;
@@ -1 +1 @@
1
- {"version":3,"file":"world-packs.d.ts","sourceRoot":"","sources":["../src/world-packs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"world-packs.d.ts","sourceRoot":"","sources":["../src/world-packs.ts"],"names":[],"mappings":"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"}