@sfmc-bds/bds-tools 0.1.0 → 0.2.0-beta.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 (71) hide show
  1. package/dist/bds-manager.d.ts.map +1 -1
  2. package/dist/bds-manager.js +236 -263
  3. package/dist/bds-manager.js.map +7 -1
  4. package/dist/changelog.js +39 -50
  5. package/dist/changelog.js.map +7 -1
  6. package/dist/check-update.d.ts +2 -2
  7. package/dist/check-update.d.ts.map +1 -1
  8. package/dist/check-update.js +361 -401
  9. package/dist/check-update.js.map +7 -1
  10. package/dist/cli-pack-manager.d.ts +10 -6
  11. package/dist/cli-pack-manager.d.ts.map +1 -1
  12. package/dist/cli-pack-manager.js +226 -135
  13. package/dist/cli-pack-manager.js.map +7 -1
  14. package/dist/fsx.js +86 -100
  15. package/dist/fsx.js.map +7 -1
  16. package/dist/http.d.ts.map +1 -1
  17. package/dist/http.js +166 -185
  18. package/dist/http.js.map +7 -1
  19. package/dist/is-main.d.ts +17 -0
  20. package/dist/is-main.d.ts.map +1 -0
  21. package/dist/is-main.js +32 -0
  22. package/dist/is-main.js.map +7 -0
  23. package/dist/log.d.ts +2 -4
  24. package/dist/log.d.ts.map +1 -1
  25. package/dist/log.js +12 -19
  26. package/dist/log.js.map +7 -1
  27. package/dist/logger.js +6 -10
  28. package/dist/logger.js.map +7 -1
  29. package/dist/pack-manager.d.ts +88 -24
  30. package/dist/pack-manager.d.ts.map +1 -1
  31. package/dist/pack-manager.js +280 -245
  32. package/dist/pack-manager.js.map +7 -1
  33. package/dist/paths.d.ts +8 -3
  34. package/dist/paths.d.ts.map +1 -1
  35. package/dist/paths.js +53 -39
  36. package/dist/paths.js.map +7 -1
  37. package/dist/qqutil.d.ts.map +1 -1
  38. package/dist/qqutil.js +90 -87
  39. package/dist/qqutil.js.map +7 -1
  40. package/dist/recovery.js +26 -37
  41. package/dist/recovery.js.map +7 -1
  42. package/dist/rollback.d.ts +1 -1
  43. package/dist/rollback.js +55 -74
  44. package/dist/rollback.js.map +7 -1
  45. package/dist/server-properties.d.ts +12 -0
  46. package/dist/server-properties.d.ts.map +1 -0
  47. package/dist/server-properties.js +28 -0
  48. package/dist/server-properties.js.map +7 -0
  49. package/dist/taskbar.d.ts +2 -0
  50. package/dist/taskbar.d.ts.map +1 -1
  51. package/dist/taskbar.js +51 -82
  52. package/dist/taskbar.js.map +7 -1
  53. package/dist/types.js +1 -5
  54. package/dist/types.js.map +7 -1
  55. package/dist/update-result.d.ts +12 -0
  56. package/dist/update-result.d.ts.map +1 -0
  57. package/dist/update-result.js +15 -0
  58. package/dist/update-result.js.map +7 -0
  59. package/dist/upstream.js +94 -108
  60. package/dist/upstream.js.map +7 -1
  61. package/dist/version.js +63 -81
  62. package/dist/version.js.map +7 -1
  63. package/dist/world-packs.d.ts +112 -0
  64. package/dist/world-packs.d.ts.map +1 -0
  65. package/dist/world-packs.js +335 -0
  66. package/dist/world-packs.js.map +7 -0
  67. package/dist/zipx.d.ts +10 -0
  68. package/dist/zipx.d.ts.map +1 -0
  69. package/dist/zipx.js +48 -0
  70. package/dist/zipx.js.map +7 -0
  71. package/package.json +17 -6
package/dist/paths.d.ts CHANGED
@@ -1,17 +1,22 @@
1
1
  /**
2
2
  * paths.ts — 路径常量 & 加载 bds_updater.json
3
3
  *
4
- * ROOT_DIR = 项目根,通过 SDK 统一解析(env SFMC_ROOT > __dirname 上溯)。
5
- * SCRIPT_DIR = bds-tools/ 内部 dist 目录,bds PID / log / cache 文件落盘处。
4
+ * ROOT_DIR = 项目/数据根,通过 SDK 统一解析(env SFMC_ROOT > __dirname 上溯)。
5
+ * STATE_DIR / LOG_PATH 等运行态路径一律走 SDK stateDir / logFile,勿再手写 ".sfmc"。
6
6
  */
7
7
  import { type BdsUpdaterConfig } from "@sfmc-bds/sdk/node/config";
8
- /** 项目根目录:bds-tools 的上一级。统一通过 SDK 解析,SEA / npm 一致。 */
8
+ /** 项目根目录:bds-tools 的上一级。统一通过 SDK 解析。 */
9
9
  export declare const ROOT_DIR: string;
10
10
  export declare const CFG_PATH: string;
11
+ /** 运行态目录(相对数据根,勿落在 bds-tools/dist) */
12
+ export declare const STATE_DIR: string;
11
13
  export declare const LOG_PATH: string;
12
14
  export declare const VERSION_CACHE: string;
13
15
  export declare const PID_FILE: string;
16
+ /** 更新中途失败可恢复的回滚标记 */
14
17
  export declare const ROLLBACK_MARKER: string;
18
+ /** 确保 .sfmc 运行态目录存在(PID 写入等不经 writeJson 的路径需要) */
19
+ export declare function ensureStateDir(): void;
15
20
  /** 加载并解析 bds_updater.json。
16
21
  * 启动时 ensure 文件存在,避免 wizard 没跑时 bds_updater.json 缺失导致 loadConfig 抛错。 */
17
22
  export declare function loadConfig(): BdsUpdaterConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAOnC,qDAAqD;AACrD,eAAO,MAAM,QAAQ,EAAE,MAAiE,CAAC;AACzF,eAAO,MAAM,QAAQ,EAAE,MAAiD,CAAC;AACzE,eAAO,MAAM,QAAQ,EAAE,MAA4C,CAAC;AACpE,eAAO,MAAM,aAAa,EAAE,MAAqD,CAAC;AAClF,eAAO,MAAM,QAAQ,EAAE,MAA0C,CAAC;AAClE,eAAO,MAAM,eAAe,EAAE,MAA4D,CAAC;AAE3F;yEACyE;AACzE,wBAAgB,UAAU,IAAI,gBAAgB,CAQ7C;AAED,yBAAyB;AACzB,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,gBAAgB,CAAC;CACvB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,GAAG,QAAQ,CAS5D;AAED,gBAAgB;AAChB,wBAAgB,QAAQ,IAAI,IAAI,CAM/B"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAOL,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAOnC,wCAAwC;AACxC,eAAO,MAAM,QAAQ,EAAE,MAAiE,CAAC;AACzF,eAAO,MAAM,QAAQ,EAAE,MAAiD,CAAC;AAEzE,sCAAsC;AACtC,eAAO,MAAM,SAAS,EAAE,MAA2B,CAAC;AACpD,eAAO,MAAM,QAAQ,EAAE,MAAwC,CAAC;AAChE,eAAO,MAAM,aAAa,EAAE,MAAuD,CAAC;AACpF,eAAO,MAAM,QAAQ,EAAE,MAAwC,CAAC;AAChE,qBAAqB;AACrB,eAAO,MAAM,eAAe,EAAE,MAA0D,CAAC;AAEzF,kDAAkD;AAClD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;yEACyE;AACzE,wBAAgB,UAAU,IAAI,gBAAgB,CAO7C;AAED,yBAAyB;AACzB,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,gBAAgB,CAAC;CACvB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,GAAG,QAAQ,CAS5D;AAED,gBAAgB;AAChB,wBAAgB,QAAQ,IAAI,IAAI,CAM/B"}
package/dist/paths.js CHANGED
@@ -1,47 +1,61 @@
1
- /**
2
- * paths.ts — 路径常量 & 加载 bds_updater.json
3
- *
4
- * ROOT_DIR = 项目根,通过 SDK 统一解析(env SFMC_ROOT > __dirname 上溯)。
5
- * SCRIPT_DIR = bds-tools/ 内部 dist 目录,bds 的 PID / log / cache 文件落盘处。
6
- */
7
- import { configPath, ensureJsonConfig, resolveRuntimeRoot, } from "@sfmc-bds/sdk/node/config";
1
+ import {
2
+ configPath,
3
+ DEFAULT_BDS_UPDATER_CONFIG,
4
+ loadEnsuredConfig,
5
+ logFile,
6
+ resolveRuntimeRoot,
7
+ stateDir
8
+ } from "@sfmc-bds/sdk/node/config";
8
9
  import fs from "node:fs";
9
10
  import path from "node:path";
10
11
  import { fileURLToPath } from "node:url";
11
12
  const __filename = fileURLToPath(import.meta.url);
12
13
  const SCRIPT_DIR = path.dirname(__filename);
13
- /** 项目根目录:bds-tools 的上一级。统一通过 SDK 解析,SEA / npm 一致。 */
14
- export const ROOT_DIR = resolveRuntimeRoot(path.resolve(SCRIPT_DIR, "..", ".."));
15
- export const CFG_PATH = configPath(ROOT_DIR, "bds_updater.json");
16
- export const LOG_PATH = path.join(SCRIPT_DIR, "update.log");
17
- export const VERSION_CACHE = path.join(SCRIPT_DIR, ".version_cache.json");
18
- export const PID_FILE = path.join(SCRIPT_DIR, ".bds.pid");
19
- export const ROLLBACK_MARKER = path.join(SCRIPT_DIR, ".last_update_rollback.json");
20
- /** 加载并解析 bds_updater.json。
21
- * 启动时 ensure 文件存在,避免 wizard 没跑时 bds_updater.json 缺失导致 loadConfig 抛错。 */
22
- export function loadConfig() {
23
- const cfg = ensureJsonConfig(ROOT_DIR, "bds_updater.json", {});
24
- delete cfg._comment;
25
- return cfg;
14
+ const ROOT_DIR = resolveRuntimeRoot(path.resolve(SCRIPT_DIR, "..", ".."));
15
+ const CFG_PATH = configPath(ROOT_DIR, "bds_updater.json");
16
+ const STATE_DIR = stateDir(ROOT_DIR);
17
+ const LOG_PATH = logFile(ROOT_DIR, "bds-update");
18
+ const VERSION_CACHE = path.join(STATE_DIR, "bds-version-cache.json");
19
+ const PID_FILE = path.join(STATE_DIR, "bds.pid");
20
+ const ROLLBACK_MARKER = path.join(STATE_DIR, "last_update_rollback.json");
21
+ function ensureStateDir() {
22
+ fs.mkdirSync(STATE_DIR, { recursive: true });
26
23
  }
27
- export function resolvePaths(cfg) {
28
- const bds_path = path.resolve(cfg.bds_path || process.cwd());
29
- const backup_dir = path.resolve(cfg.backup_dir || path.join(bds_path, "..", "backups"));
30
- const relativeBackup = path.relative(bds_path, backup_dir);
31
- if (relativeBackup === "" || (!relativeBackup.startsWith("..") && !path.isAbsolute(relativeBackup))) {
32
- throw new Error("backup_dir must be outside bds_path so deployment cannot delete the backup");
33
- }
34
- const preserve = Array.isArray(cfg.preserve) ? cfg.preserve : [];
35
- return { bds_path, backup_dir, preserve, cfg };
24
+ function loadConfig() {
25
+ return loadEnsuredConfig(
26
+ ROOT_DIR,
27
+ "bds_updater.json",
28
+ "bds_updater",
29
+ { ...DEFAULT_BDS_UPDATER_CONFIG }
30
+ );
36
31
  }
37
- /** 删除 PID 文件 */
38
- export function clearPid() {
39
- try {
40
- if (fs.existsSync(PID_FILE))
41
- fs.unlinkSync(PID_FILE);
42
- }
43
- catch {
44
- /* ignore */
45
- }
32
+ function resolvePaths(cfg) {
33
+ const bds_path = path.resolve(cfg.bds_path || process.cwd());
34
+ const backup_dir = path.resolve(cfg.backup_dir || path.join(bds_path, "..", "backups"));
35
+ const relativeBackup = path.relative(bds_path, backup_dir);
36
+ if (relativeBackup === "" || !relativeBackup.startsWith("..") && !path.isAbsolute(relativeBackup)) {
37
+ throw new Error("backup_dir must be outside bds_path so deployment cannot delete the backup");
38
+ }
39
+ const preserve = Array.isArray(cfg.preserve) ? cfg.preserve : [];
40
+ return { bds_path, backup_dir, preserve, cfg };
46
41
  }
47
- //# sourceMappingURL=paths.js.map
42
+ function clearPid() {
43
+ try {
44
+ if (fs.existsSync(PID_FILE)) fs.unlinkSync(PID_FILE);
45
+ } catch {
46
+ }
47
+ }
48
+ export {
49
+ CFG_PATH,
50
+ LOG_PATH,
51
+ PID_FILE,
52
+ ROLLBACK_MARKER,
53
+ ROOT_DIR,
54
+ STATE_DIR,
55
+ VERSION_CACHE,
56
+ clearPid,
57
+ ensureStateDir,
58
+ loadConfig,
59
+ resolvePaths
60
+ };
61
+ //# sourceMappingURL=paths.js.map
package/dist/paths.js.map CHANGED
@@ -1 +1,7 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,kBAAkB,GAEnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,UAAU,GAAW,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AACpD,qDAAqD;AACrD,MAAM,CAAC,MAAM,QAAQ,GAAW,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AACzF,MAAM,CAAC,MAAM,QAAQ,GAAW,UAAU,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,QAAQ,GAAW,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AACpE,MAAM,CAAC,MAAM,aAAa,GAAW,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC;AAClF,MAAM,CAAC,MAAM,QAAQ,GAAW,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,eAAe,GAAW,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,4BAA4B,CAAC,CAAC;AAE3F;yEACyE;AACzE,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,gBAAgB,CAC1B,QAAQ,EACR,kBAAkB,EAClB,EAAE,CACH,CAAC;IACF,OAAO,GAAG,CAAC,QAAQ,CAAC;IACpB,OAAO,GAAG,CAAC;AACb,CAAC;AAUD,MAAM,UAAU,YAAY,CAAC,GAAqB;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IACxF,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC3D,IAAI,cAAc,KAAK,EAAE,IAAI,CAAC,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC;QACpG,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAChG,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AACjD,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/paths.ts"],
4
+ "sourcesContent": ["/**\n * paths.ts \u2014 \u8DEF\u5F84\u5E38\u91CF & \u52A0\u8F7D bds_updater.json\n *\n * ROOT_DIR = \u9879\u76EE/\u6570\u636E\u6839,\u901A\u8FC7 SDK \u7EDF\u4E00\u89E3\u6790(env SFMC_ROOT > __dirname \u4E0A\u6EAF)\u3002\n * STATE_DIR / LOG_PATH \u7B49\u8FD0\u884C\u6001\u8DEF\u5F84\u4E00\u5F8B\u8D70 SDK stateDir / logFile,\u52FF\u518D\u624B\u5199 \".sfmc\"\u3002\n */\n\nimport {\n configPath,\n DEFAULT_BDS_UPDATER_CONFIG,\n loadEnsuredConfig,\n logFile,\n resolveRuntimeRoot,\n stateDir,\n type BdsUpdaterConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst SCRIPT_DIR: string = path.dirname(__filename);\n/** \u9879\u76EE\u6839\u76EE\u5F55:bds-tools \u7684\u4E0A\u4E00\u7EA7\u3002\u7EDF\u4E00\u901A\u8FC7 SDK \u89E3\u6790\u3002 */\nexport const ROOT_DIR: string = resolveRuntimeRoot(path.resolve(SCRIPT_DIR, \"..\", \"..\"));\nexport const CFG_PATH: string = configPath(ROOT_DIR, \"bds_updater.json\");\n\n/** \u8FD0\u884C\u6001\u76EE\u5F55(\u76F8\u5BF9\u6570\u636E\u6839\uFF0C\u52FF\u843D\u5728 bds-tools/dist) */\nexport const STATE_DIR: string = stateDir(ROOT_DIR);\nexport const LOG_PATH: string = logFile(ROOT_DIR, \"bds-update\");\nexport const VERSION_CACHE: string = path.join(STATE_DIR, \"bds-version-cache.json\");\nexport const PID_FILE: string = path.join(STATE_DIR, \"bds.pid\");\n/** \u66F4\u65B0\u4E2D\u9014\u5931\u8D25\u53EF\u6062\u590D\u7684\u56DE\u6EDA\u6807\u8BB0 */\nexport const ROLLBACK_MARKER: string = path.join(STATE_DIR, \"last_update_rollback.json\");\n\n/** \u786E\u4FDD .sfmc \u8FD0\u884C\u6001\u76EE\u5F55\u5B58\u5728(PID \u5199\u5165\u7B49\u4E0D\u7ECF writeJson \u7684\u8DEF\u5F84\u9700\u8981) */\nexport function ensureStateDir(): void {\n fs.mkdirSync(STATE_DIR, { recursive: true });\n}\n\n/** \u52A0\u8F7D\u5E76\u89E3\u6790 bds_updater.json\u3002\n * \u542F\u52A8\u65F6 ensure \u6587\u4EF6\u5B58\u5728,\u907F\u514D wizard \u6CA1\u8DD1\u65F6 bds_updater.json \u7F3A\u5931\u5BFC\u81F4 loadConfig \u629B\u9519\u3002 */\nexport function loadConfig(): BdsUpdaterConfig {\n return loadEnsuredConfig(\n ROOT_DIR,\n \"bds_updater.json\",\n \"bds_updater\",\n { ...DEFAULT_BDS_UPDATER_CONFIG } as Record<string, unknown>\n ) as BdsUpdaterConfig;\n}\n\n/** \u89E3\u6790\u540E\u7684 BDS \u8DEF\u5F84 / \u5907\u4EFD\u76EE\u5F55 */\nexport interface BdsPaths {\n bds_path: string;\n backup_dir: string;\n preserve: string[];\n cfg: BdsUpdaterConfig;\n}\n\nexport function resolvePaths(cfg: BdsUpdaterConfig): BdsPaths {\n const bds_path = path.resolve(cfg.bds_path || process.cwd());\n const backup_dir = path.resolve(cfg.backup_dir || path.join(bds_path, \"..\", \"backups\"));\n const relativeBackup = path.relative(bds_path, backup_dir);\n if (relativeBackup === \"\" || (!relativeBackup.startsWith(\"..\") && !path.isAbsolute(relativeBackup))) {\n throw new Error(\"backup_dir must be outside bds_path so deployment cannot delete the backup\");\n }\n const preserve = Array.isArray(cfg.preserve) ? cfg.preserve : [];\n return { bds_path, backup_dir, preserve, cfg };\n}\n\n/** \u5220\u9664 PID \u6587\u4EF6 */\nexport function clearPid(): void {\n try {\n if (fs.existsSync(PID_FILE)) fs.unlinkSync(PID_FILE);\n } catch {\n /* ignore */\n }\n}\n"],
5
+ "mappings": "AAOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAE9B,MAAM,aAAa,cAAc,YAAY,GAAG;AAChD,MAAM,aAAqB,KAAK,QAAQ,UAAU;AAE3C,MAAM,WAAmB,mBAAmB,KAAK,QAAQ,YAAY,MAAM,IAAI,CAAC;AAChF,MAAM,WAAmB,WAAW,UAAU,kBAAkB;AAGhE,MAAM,YAAoB,SAAS,QAAQ;AAC3C,MAAM,WAAmB,QAAQ,UAAU,YAAY;AACvD,MAAM,gBAAwB,KAAK,KAAK,WAAW,wBAAwB;AAC3E,MAAM,WAAmB,KAAK,KAAK,WAAW,SAAS;AAEvD,MAAM,kBAA0B,KAAK,KAAK,WAAW,2BAA2B;AAGhF,SAAS,iBAAuB;AACrC,KAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C;AAIO,SAAS,aAA+B;AAC7C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,GAAG,2BAA2B;AAAA,EAClC;AACF;AAUO,SAAS,aAAa,KAAiC;AAC5D,QAAM,WAAW,KAAK,QAAQ,IAAI,YAAY,QAAQ,IAAI,CAAC;AAC3D,QAAM,aAAa,KAAK,QAAQ,IAAI,cAAc,KAAK,KAAK,UAAU,MAAM,SAAS,CAAC;AACtF,QAAM,iBAAiB,KAAK,SAAS,UAAU,UAAU;AACzD,MAAI,mBAAmB,MAAO,CAAC,eAAe,WAAW,IAAI,KAAK,CAAC,KAAK,WAAW,cAAc,GAAI;AACnG,UAAM,IAAI,MAAM,4EAA4E;AAAA,EAC9F;AACA,QAAM,WAAW,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,WAAW,CAAC;AAC/D,SAAO,EAAE,UAAU,YAAY,UAAU,IAAI;AAC/C;AAGO,SAAS,WAAiB;AAC/B,MAAI;AACF,QAAI,GAAG,WAAW,QAAQ,EAAG,IAAG,WAAW,QAAQ;AAAA,EACrD,QAAQ;AAAA,EAER;AACF;",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"qqutil.d.ts","sourceRoot":"","sources":["../src/qqutil.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,0BAA0B;AAC1B,wBAAgB,iBAAiB,IAAI,OAAO,CAQ3C;AA6CD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY1D;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAYlE;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;;;;;;GAMG;AAuBH,0BAA0B;AAC1B,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C;AA6CD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY1D;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAYlE;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlF"}
package/dist/qqutil.js CHANGED
@@ -1,101 +1,104 @@
1
- /**
2
- * qqutil.ts — QQ 通知工具 (基于 LLBot HTTP OneBot 11)
3
- *
4
- * 改进:
5
- * - sendTimeout 提供总超时,避免通知发送挂死主流程
6
- * - 静默模式 (失败不抛出),保证主流程不被通知干扰
7
- */
1
+ import {
2
+ configPath,
3
+ modulePath,
4
+ readJson
5
+ } from "@sfmc-bds/sdk/node/config";
8
6
  import http from "node:http";
9
- import { configPath, modulePath, readJson } from "@sfmc-bds/sdk/node/config";
10
- import { ROOT_DIR } from "./paths.js";
11
7
  import { log } from "./log.js";
8
+ import { ROOT_DIR } from "./paths.js";
12
9
  let cachedCfg = null;
13
10
  function getConfig() {
14
- if (cachedCfg)
15
- return cachedCfg;
16
- cachedCfg = (readJson(configPath(ROOT_DIR, "qq_config.json")) ?? {});
17
- return cachedCfg;
11
+ if (cachedCfg) return cachedCfg;
12
+ cachedCfg = readJson(configPath(ROOT_DIR, "qq_config.json")) ?? {};
13
+ return cachedCfg;
18
14
  }
19
- /** 检查 qq-bridge 模块是否启用 */
20
- export function isQqBridgeEnabled() {
21
- const catalog = readJson(modulePath(ROOT_DIR, "catalog.json"));
22
- const lock = readJson(modulePath(ROOT_DIR, "module-lock.json"));
23
- if (!catalog || !lock)
24
- return true; // 模块目录缺失则保守视为可用
25
- const mod = catalog.modules?.find((m) => m.id === "qq-bridge" || m.configKey === "qq_bridge");
26
- return mod ? lock.modules?.[mod.id ?? ""]?.enabled === true : false;
15
+ function isQqBridgeEnabled() {
16
+ const catalog = readJson(modulePath(ROOT_DIR, "catalog.json"));
17
+ const lock = readJson(modulePath(ROOT_DIR, "module-lock.json"));
18
+ if (!catalog || !lock) return true;
19
+ const mod = catalog.modules?.find((m) => m.id === "qq-bridge" || m.configKey === "qq_bridge");
20
+ return mod ? lock.modules?.[mod.id ?? ""]?.enabled === true : false;
27
21
  }
28
- function sendToLLBot(payload, timeoutMs = 5_000) {
29
- const cfg = getConfig();
30
- const url = new URL(cfg.llbot_http || "http://127.0.0.1:3000");
31
- const data = JSON.stringify(payload);
32
- return new Promise((resolve, reject) => {
33
- const req = http.request({
34
- hostname: url.hostname,
35
- port: url.port || 3000,
36
- path: "/send_group_msg",
37
- method: "POST",
38
- headers: {
39
- "Content-Type": "application/json",
40
- "Content-Length": Buffer.byteLength(data),
41
- },
42
- timeout: timeoutMs,
43
- }, (res) => {
44
- let body = "";
45
- res.on("data", (c) => (body += c));
46
- res.on("end", () => {
47
- if (res.statusCode === 200)
48
- resolve();
49
- else
50
- reject(new Error(`LLBot HTTP ${res.statusCode}: ${body.slice(0, 200)}`));
51
- });
52
- });
53
- req.on("timeout", () => {
54
- req.destroy(new Error(`LLBot 超时 ${timeoutMs}ms`));
22
+ function sendToLLBot(payload, timeoutMs = 5e3) {
23
+ const cfg = getConfig();
24
+ const url = new URL(cfg.llbot_http || "http://127.0.0.1:3000");
25
+ const data = JSON.stringify(payload);
26
+ return new Promise((resolve, reject) => {
27
+ const req = http.request(
28
+ {
29
+ hostname: url.hostname,
30
+ port: url.port || 3e3,
31
+ path: "/send_group_msg",
32
+ method: "POST",
33
+ headers: {
34
+ "Content-Type": "application/json",
35
+ "Content-Length": Buffer.byteLength(data)
36
+ },
37
+ timeout: timeoutMs
38
+ },
39
+ (res) => {
40
+ let body = "";
41
+ res.on("data", (c) => body += c);
42
+ res.on("end", () => {
43
+ if (res.statusCode === 200) resolve();
44
+ else reject(new Error(`LLBot HTTP ${res.statusCode}: ${body.slice(0, 200)}`));
55
45
  });
56
- req.on("error", reject);
57
- req.write(data);
58
- req.end();
46
+ }
47
+ );
48
+ req.on("timeout", () => {
49
+ req.destroy(new Error(`LLBot \u8D85\u65F6 ${timeoutMs}ms`));
59
50
  });
51
+ req.on("error", reject);
52
+ req.write(data);
53
+ req.end();
54
+ });
60
55
  }
61
56
  async function safeSend(label, fn) {
62
- try {
63
- await fn();
64
- }
65
- catch (e) {
66
- log.warn(`[QQ] ${label} 失败: ${e.message}`);
67
- }
57
+ try {
58
+ await fn();
59
+ } catch (e) {
60
+ log.warn(`[QQ] ${label} \u5931\u8D25: ${e.message}`);
61
+ }
68
62
  }
69
- export async function sendText(text) {
70
- const cfg = getConfig();
71
- if (!isQqBridgeEnabled() || !cfg.qq_group_id) {
72
- log.warn("[QQ] qq-bridge 未启用或 qq_group_id 缺失");
73
- return;
74
- }
75
- await safeSend("sendText", () => sendToLLBot({
76
- group_id: parseInt(cfg.qq_group_id ?? "0", 10),
77
- message: [{ type: "text", data: { text } }],
78
- }));
63
+ async function sendText(text) {
64
+ 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");
67
+ return;
68
+ }
69
+ await safeSend(
70
+ "sendText",
71
+ () => sendToLLBot({
72
+ group_id: parseInt(cfg.qq_group_id ?? "0", 10),
73
+ message: [{ type: "text", data: { text } }]
74
+ })
75
+ );
79
76
  }
80
- export async function sendMixed(segments) {
81
- const cfg = getConfig();
82
- if (!isQqBridgeEnabled() || !cfg.qq_group_id) {
83
- log.warn("[QQ] qq-bridge 未启用或 qq_group_id 缺失");
84
- return;
85
- }
86
- await safeSend("sendMixed", () => sendToLLBot({
87
- group_id: parseInt(cfg.qq_group_id ?? "0", 10),
88
- message: segments,
89
- }));
77
+ async function sendMixed(segments) {
78
+ 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");
81
+ return;
82
+ }
83
+ await safeSend(
84
+ "sendMixed",
85
+ () => sendToLLBot({
86
+ group_id: parseInt(cfg.qq_group_id ?? "0", 10),
87
+ message: segments
88
+ })
89
+ );
90
90
  }
91
- export async function sendWithImage(text, base64Img) {
92
- const segments = [];
93
- if (text)
94
- segments.push({ type: "text", data: { text } });
95
- if (base64Img)
96
- segments.push({ type: "image", data: { file: `base64://${base64Img}` } });
97
- if (segments.length === 0)
98
- return;
99
- await sendMixed(segments);
91
+ async function sendWithImage(text, base64Img) {
92
+ const segments = [];
93
+ if (text) segments.push({ type: "text", data: { text } });
94
+ if (base64Img) segments.push({ type: "image", data: { file: `base64://${base64Img}` } });
95
+ if (segments.length === 0) return;
96
+ await sendMixed(segments);
100
97
  }
101
- //# sourceMappingURL=qqutil.js.map
98
+ export {
99
+ isQqBridgeEnabled,
100
+ sendMixed,
101
+ sendText,
102
+ sendWithImage
103
+ };
104
+ //# sourceMappingURL=qqutil.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"qqutil.js","sourceRoot":"","sources":["../src/qqutil.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 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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",
6
+ "names": []
7
+ }
package/dist/recovery.js CHANGED
@@ -1,45 +1,34 @@
1
- /**
2
- * recovery.ts — 手动触发回滚
3
- *
4
- * 用法: node recovery.js
5
- * 读取 ROLLBACK_MARKER,然后从备份恢复 preserve 项。
6
- */
7
- import { readRollbackMarker, rollbackFromBackup } from "./rollback.js";
1
+ import { isMainModule } from "./is-main.js";
8
2
  import { log, closeLog } from "./log.js";
9
3
  import { clearPid } from "./paths.js";
4
+ import { readRollbackMarker, rollbackFromBackup } from "./rollback.js";
10
5
  async function run() {
11
- const m = readRollbackMarker();
12
- if (!m) {
13
- log.warn("未发现回滚标记,无需恢复。");
14
- return;
15
- }
16
- log.info(`发现回滚标记: 时间 ${new Date(m.timestamp).toISOString()}`);
17
- log.info(`目标: ${m.backup_dir} 恢复 ${m.preserve.length} 项到 ${m.bds_path}`);
18
- const result = rollbackFromBackup(m);
19
- if (!result.ok) {
20
- log.error(`回滚失败: ${result.reason}`);
21
- process.exit(1);
22
- }
23
- // 清理 pid 文件
24
- clearPid();
25
- log.info("回滚完成,请手动检查并启动 BDS。");
6
+ const m = readRollbackMarker();
7
+ if (!m) {
8
+ log.warn("\u672A\u53D1\u73B0\u56DE\u6EDA\u6807\u8BB0\uFF0C\u65E0\u9700\u6062\u590D\u3002");
9
+ return;
10
+ }
11
+ log.info(`\u53D1\u73B0\u56DE\u6EDA\u6807\u8BB0: \u65F6\u95F4 ${new Date(m.timestamp).toISOString()}`);
12
+ log.info(`\u76EE\u6807: \u4ECE ${m.backup_dir} \u6062\u590D ${m.preserve.length} \u9879\u5230 ${m.bds_path}`);
13
+ const result = rollbackFromBackup(m);
14
+ if (!result.ok) {
15
+ log.error(`\u56DE\u6EDA\u5931\u8D25: ${result.reason}`);
16
+ process.exit(1);
17
+ }
18
+ clearPid();
19
+ log.info("\u56DE\u6EDA\u5B8C\u6210\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u5E76\u542F\u52A8 BDS\u3002");
26
20
  }
27
21
  function isMain() {
28
- if (require.main === module)
29
- return true;
30
- const entry = process.argv[1] ?? "";
31
- return entry.endsWith("recovery.js") || entry.endsWith("recovery.ts");
22
+ return isMainModule(import.meta.url);
32
23
  }
33
24
  if (isMain()) {
34
- run()
35
- .then(() => {
36
- closeLog();
37
- process.exit(0);
38
- })
39
- .catch((e) => {
40
- log.error(`未捕获错误: ${e.message}`);
41
- closeLog();
42
- process.exit(1);
43
- });
25
+ run().then(() => {
26
+ closeLog();
27
+ process.exit(0);
28
+ }).catch((e) => {
29
+ log.error(`\u672A\u6355\u83B7\u9519\u8BEF: ${e.message}`);
30
+ closeLog();
31
+ process.exit(1);
32
+ });
44
33
  }
45
- //# sourceMappingURL=recovery.js.map
34
+ //# sourceMappingURL=recovery.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"recovery.js","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,KAAK,UAAU,GAAG;IAChB,MAAM,CAAC,GAAG,kBAAkB,EAAE,CAAC;IAC/B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC1B,OAAO;IACT,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,UAAU,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE3E,MAAM,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,YAAY;IACZ,QAAQ,EAAE,CAAC;IACX,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,MAAM;IACb,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,OAAO,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;AACxE,CAAC;AAED,IAAI,MAAM,EAAE,EAAE,CAAC;IACb,GAAG,EAAE;SACF,IAAI,CAAC,GAAG,EAAE;QACT,QAAQ,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QACX,GAAG,CAAC,KAAK,CAAC,UAAW,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5C,QAAQ,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/recovery.ts"],
4
+ "sourcesContent": ["/**\n * recovery.ts \u2014 \u624B\u52A8\u89E6\u53D1\u56DE\u6EDA\n *\n * \u7528\u6CD5: node recovery.js\n * \u8BFB\u53D6 ROLLBACK_MARKER\uFF0C\u7136\u540E\u4ECE\u5907\u4EFD\u6062\u590D preserve \u9879\u3002\n */\n\nimport { isMainModule } from \"./is-main.js\";\nimport { log, closeLog } from \"./log.js\";\nimport { clearPid } from \"./paths.js\";\nimport { readRollbackMarker, rollbackFromBackup } from \"./rollback.js\";\n\nasync function run(): Promise<void> {\n const m = readRollbackMarker();\n if (!m) {\n log.warn(\"\u672A\u53D1\u73B0\u56DE\u6EDA\u6807\u8BB0\uFF0C\u65E0\u9700\u6062\u590D\u3002\");\n return;\n }\n log.info(`\u53D1\u73B0\u56DE\u6EDA\u6807\u8BB0: \u65F6\u95F4 ${new Date(m.timestamp).toISOString()}`);\n log.info(`\u76EE\u6807: \u4ECE ${m.backup_dir} \u6062\u590D ${m.preserve.length} \u9879\u5230 ${m.bds_path}`);\n\n const result = rollbackFromBackup(m);\n if (!result.ok) {\n log.error(`\u56DE\u6EDA\u5931\u8D25: ${result.reason}`);\n process.exit(1);\n }\n // \u6E05\u7406 pid \u6587\u4EF6\n clearPid();\n log.info(\"\u56DE\u6EDA\u5B8C\u6210\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u5E76\u542F\u52A8 BDS\u3002\");\n}\n\nfunction isMain(): boolean {\n return isMainModule(import.meta.url);\n}\n\nif (isMain()) {\n run()\n .then(() => {\n closeLog();\n process.exit(0);\n })\n .catch((e) => {\n log.error(`\u672A\u6355\u83B7\u9519\u8BEF: ${(e as Error).message}`);\n closeLog();\n process.exit(1);\n });\n}\n"],
5
+ "mappings": "AAOA,SAAS,oBAAoB;AAC7B,SAAS,KAAK,gBAAgB;AAC9B,SAAS,gBAAgB;AACzB,SAAS,oBAAoB,0BAA0B;AAEvD,eAAe,MAAqB;AAClC,QAAM,IAAI,mBAAmB;AAC7B,MAAI,CAAC,GAAG;AACN,QAAI,KAAK,gFAAe;AACxB;AAAA,EACF;AACA,MAAI,KAAK,sDAAc,IAAI,KAAK,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE;AAC5D,MAAI,KAAK,wBAAS,EAAE,UAAU,iBAAO,EAAE,SAAS,MAAM,iBAAO,EAAE,QAAQ,EAAE;AAEzE,QAAM,SAAS,mBAAmB,CAAC;AACnC,MAAI,CAAC,OAAO,IAAI;AACd,QAAI,MAAM,6BAAS,OAAO,MAAM,EAAE;AAClC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,WAAS;AACT,MAAI,KAAK,0FAAoB;AAC/B;AAEA,SAAS,SAAkB;AACzB,SAAO,aAAa,YAAY,GAAG;AACrC;AAEA,IAAI,OAAO,GAAG;AACZ,MAAI,EACD,KAAK,MAAM;AACV,aAAS;AACT,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC,EACA,MAAM,CAAC,MAAM;AACZ,QAAI,MAAM,mCAAW,EAAY,OAAO,EAAE;AAC1C,aAAS;AACT,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACL;",
6
+ "names": []
7
+ }
@@ -5,7 +5,7 @@
5
5
  * 主流程任意阶段失败时,尝试反向恢复 preserves 到 BDS_PATH,
6
6
  * 然后从备份重新放回 preserve 内容,恢复旧配置。
7
7
  *
8
- * 持久化: ROLLBACK_MARKER (BDSTools/.last_update_rollback.json) 用于跨进程记录。
8
+ * 持久化: <SFMC_ROOT>/.sfmc/last_update_rollback.json 用于跨进程记录。
9
9
  */
10
10
  import { getDirSize } from "./fsx.js";
11
11
  export interface RollbackMarker {
package/dist/rollback.js CHANGED
@@ -1,87 +1,68 @@
1
- /**
2
- * rollback.ts — 回滚支持
3
- *
4
- * 在更新开始前记录: 当前 BDS 目录 + 备份目录。
5
- * 主流程任意阶段失败时,尝试反向恢复 preserves 到 BDS_PATH,
6
- * 然后从备份重新放回 preserve 内容,恢复旧配置。
7
- *
8
- * 持久化: ROLLBACK_MARKER (BDSTools/.last_update_rollback.json) 用于跨进程记录。
9
- */
10
1
  import { readJson, writeJson } from "@sfmc-bds/sdk/node/config";
11
2
  import fs from "node:fs";
12
3
  import path from "node:path";
13
4
  import { ROLLBACK_MARKER } from "./paths.js";
14
5
  import { copyDirSync, getDirSize, emptyDirSync } from "./fsx.js";
15
6
  import { log } from "./log.js";
16
- /** 在备份完成后调用: 记录快照指示符。 */
17
- export function writeRollbackMarker(marker) {
18
- try {
19
- writeJson(ROLLBACK_MARKER, marker);
20
- log.info(`[回滚] 已记录回滚标记 -> ${ROLLBACK_MARKER}`);
21
- }
22
- catch (e) {
23
- log.warn(`[回滚] 无法写入标记: ${e.message}`);
24
- }
7
+ function writeRollbackMarker(marker) {
8
+ try {
9
+ writeJson(ROLLBACK_MARKER, marker);
10
+ log.info(`[\u56DE\u6EDA] \u5DF2\u8BB0\u5F55\u56DE\u6EDA\u6807\u8BB0 -> ${ROLLBACK_MARKER}`);
11
+ } catch (e) {
12
+ log.warn(`[\u56DE\u6EDA] \u65E0\u6CD5\u5199\u5165\u6807\u8BB0: ${e.message}`);
13
+ }
25
14
  }
26
- export function clearRollbackMarker() {
27
- try {
28
- if (fs.existsSync(ROLLBACK_MARKER))
29
- fs.unlinkSync(ROLLBACK_MARKER);
30
- }
31
- catch {
32
- /* ignore */
33
- }
15
+ function clearRollbackMarker() {
16
+ try {
17
+ if (fs.existsSync(ROLLBACK_MARKER)) fs.unlinkSync(ROLLBACK_MARKER);
18
+ } catch {
19
+ }
34
20
  }
35
- export function readRollbackMarker() {
36
- return readJson(ROLLBACK_MARKER) ?? null;
21
+ function readRollbackMarker() {
22
+ return readJson(ROLLBACK_MARKER) ?? null;
37
23
  }
38
- /**
39
- * 紧急回滚: preserve 项从 backup_dir 拷回 bds_path。
40
- * 用法: 在 catch 分支调用,如果主流程失败导致 BDS 目录破坏。
41
- */
42
- export function rollbackFromBackup(marker) {
43
- const { bds_path, backup_dir, preserve } = marker;
44
- if (!fs.existsSync(backup_dir)) {
45
- return { ok: false, reason: `备份目录不存在: ${backup_dir}` };
24
+ function rollbackFromBackup(marker) {
25
+ const { bds_path, backup_dir, preserve } = marker;
26
+ if (!fs.existsSync(backup_dir)) {
27
+ return { ok: false, reason: `\u5907\u4EFD\u76EE\u5F55\u4E0D\u5B58\u5728: ${backup_dir}` };
28
+ }
29
+ log.warn(`[\u56DE\u6EDA] \u5F00\u59CB\u6062\u590D ${preserve.length} \u9879\u5230 ${bds_path}`);
30
+ for (const item of preserve) {
31
+ const src = path.join(backup_dir, item);
32
+ const dest = path.join(bds_path, item);
33
+ if (!fs.existsSync(src)) {
34
+ log.warn(`[\u56DE\u6EDA] \u8DF3\u8FC7 (\u5907\u4EFD\u4E2D\u4E0D\u5B58\u5728): ${item}`);
35
+ continue;
46
36
  }
47
- log.warn(`[回滚] 开始恢复 ${preserve.length} 项到 ${bds_path}`);
48
- for (const item of preserve) {
49
- const src = path.join(backup_dir, item);
50
- const dest = path.join(bds_path, item);
51
- if (!fs.existsSync(src)) {
52
- log.warn(`[回滚] 跳过 (备份中不存在): ${item}`);
53
- continue;
54
- }
55
- try {
56
- // 先确保目标目录存在 (BDS 目录可能已被解压覆盖为空)
57
- const destDir = path.dirname(dest);
58
- if (!fs.existsSync(destDir))
59
- fs.mkdirSync(destDir, { recursive: true });
60
- if (fs.statSync(src).isDirectory()) {
61
- // 先删除目标,再复制目录
62
- if (fs.existsSync(dest))
63
- emptyDirSync(dest);
64
- copyDirSync(src, dest);
65
- }
66
- else {
67
- fs.copyFileSync(src, dest);
68
- }
69
- log.info(`[回滚] 已恢复: ${item}`);
70
- }
71
- catch (e) {
72
- log.warn(`[回滚] 恢复失败 ${item}: ${e.message}`);
73
- }
37
+ try {
38
+ const destDir = path.dirname(dest);
39
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
40
+ if (fs.statSync(src).isDirectory()) {
41
+ if (fs.existsSync(dest)) emptyDirSync(dest);
42
+ copyDirSync(src, dest);
43
+ } else {
44
+ fs.copyFileSync(src, dest);
45
+ }
46
+ log.info(`[\u56DE\u6EDA] \u5DF2\u6062\u590D: ${item}`);
47
+ } catch (e) {
48
+ log.warn(`[\u56DE\u6EDA] \u6062\u590D\u5931\u8D25 ${item}: ${e.message}`);
74
49
  }
75
- return { ok: true };
50
+ }
51
+ return { ok: true };
76
52
  }
77
- /** 检查 BDS_PATH 中关键文件是否都还在 (更新后完整性 sanity check) */
78
- export function verifyBdsInstall(bds_path, expected) {
79
- const missing = [];
80
- for (const f of expected) {
81
- if (!fs.existsSync(path.join(bds_path, f)))
82
- missing.push(f);
83
- }
84
- return { ok: missing.length === 0, missing };
53
+ function verifyBdsInstall(bds_path, expected) {
54
+ const missing = [];
55
+ for (const f of expected) {
56
+ if (!fs.existsSync(path.join(bds_path, f))) missing.push(f);
57
+ }
58
+ return { ok: missing.length === 0, missing };
85
59
  }
86
- export { getDirSize };
87
- //# sourceMappingURL=rollback.js.map
60
+ export {
61
+ clearRollbackMarker,
62
+ getDirSize,
63
+ readRollbackMarker,
64
+ rollbackFromBackup,
65
+ verifyBdsInstall,
66
+ writeRollbackMarker
67
+ };
68
+ //# sourceMappingURL=rollback.js.map