@sfmc-bds/qq-bridge 0.1.0 → 0.1.1-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@ npm install @sfmc-bds/qq-bridge
9
9
  node node_modules/@sfmc-bds/qq-bridge/dist/index.js
10
10
  ```
11
11
 
12
- 通常由 `@sfmc-bds/cli` SEA 包统一拉起。
12
+ 通常由 `@sfmc-bds/sfmc` / `@sfmc-bds/cli` 统一拉起。
13
13
 
14
14
  ## 依赖
15
15
 
package/dist/config.js CHANGED
@@ -1,60 +1,56 @@
1
- /**
2
- * config.ts — 加载 configs/qq_config.json
3
- *
4
- * 行为与旧 index.js 保持完全一致:
5
- * - 文件不存在或解析失败: 进程退出 (旧版 process.exit(1))
6
- * - 字段缺失: 走默认值
7
- * - reload 时仅覆盖原对象 (mutate), 保留运行时引用的同一份对象
8
- */
9
- import { configPath, readJson, resolveRuntimeRoot } from "@sfmc-bds/sdk/node/config";
10
- import { dirname, resolve } from "node:path";
11
- import { fileURLToPath } from "node:url";
1
+ import {
2
+ configPath,
3
+ DEFAULT_QQ_CONFIG,
4
+ loadEnsuredConfig,
5
+ stripConfigMeta
6
+ } from "@sfmc-bds/sdk/node/config";
12
7
  import { log } from "./log.js";
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = dirname(__filename);
15
- /** 统一通过 SDK 解析项目根:env SFMC_ROOT > __dirname 上溯。SEA / npm 一致。 */
16
- export const ROOT_DIR = resolveRuntimeRoot(resolve(__dirname, "..", ".."));
17
- export const CFG_PATH = configPath(ROOT_DIR, "qq_config.json");
8
+ import { PROJECT_ROOT } from "./project-root.js";
9
+ const ROOT_DIR = PROJECT_ROOT;
10
+ const CFG_PATH = configPath(ROOT_DIR, "qq_config.json");
18
11
  function applyDefaults(raw) {
19
- return {
20
- qq_enabled: raw.qq_enabled !== false,
21
- qq_ws_port: parseInt(String(raw.qq_ws_port ?? "3002"), 10),
22
- qq_group_id: String(raw.qq_group_id ?? ""),
23
- bridge_channel_id: String(raw.bridge_channel_id ?? ""),
24
- db_host: String(raw.db_host ?? "127.0.0.1"),
25
- db_port: parseInt(String(raw.db_port ?? "3001"), 10),
26
- mctoqq_prefix: String(raw.mctoqq_prefix ?? "[MC]"),
27
- ...raw,
28
- };
12
+ const merged = { ...DEFAULT_QQ_CONFIG, ...raw };
13
+ const stripped = stripConfigMeta(merged);
14
+ return {
15
+ qq_enabled: stripped.qq_enabled !== false,
16
+ qq_ws_port: parseInt(String(stripped.qq_ws_port ?? DEFAULT_QQ_CONFIG.qq_ws_port ?? 3002), 10),
17
+ qq_group_id: String(stripped.qq_group_id ?? DEFAULT_QQ_CONFIG.qq_group_id ?? "0"),
18
+ bridge_channel_id: String(stripped.bridge_channel_id ?? DEFAULT_QQ_CONFIG.bridge_channel_id ?? ""),
19
+ db_host: String(stripped.db_host ?? "127.0.0.1"),
20
+ db_port: parseInt(String(stripped.db_port ?? "3001"), 10),
21
+ mctoqq_prefix: String(stripped.mctoqq_prefix ?? DEFAULT_QQ_CONFIG.mctoqq_prefix ?? "[MC]"),
22
+ ...stripped
23
+ };
29
24
  }
30
25
  function readFromDisk() {
31
- const raw = readJson(CFG_PATH);
32
- if (!raw)
33
- throw new Error(`配置文件不存在或无法解析: ${CFG_PATH}`);
34
- return applyDefaults(raw);
26
+ const raw = loadEnsuredConfig(
27
+ ROOT_DIR,
28
+ "qq_config.json",
29
+ "qq_config",
30
+ { ...DEFAULT_QQ_CONFIG }
31
+ );
32
+ return applyDefaults(raw);
35
33
  }
36
- /** 进程启动时加载一次。失败直接退出,与旧实现一致。 */
37
- export function loadInitialConfig() {
38
- try {
39
- return readFromDisk();
40
- }
41
- catch (e) {
42
- log.error(`无法读取配置: ${CFG_PATH}: ${e.message}`);
43
- process.exit(1);
44
- }
34
+ function loadInitialConfig() {
35
+ try {
36
+ return readFromDisk();
37
+ } catch (e) {
38
+ log.error(`\u65E0\u6CD5\u8BFB\u53D6\u914D\u7F6E: ${CFG_PATH}: ${e.message}`);
39
+ process.exit(1);
40
+ }
45
41
  }
46
- /**
47
- * 重新读取配置文件,合并到传入对象上 (mutate)。
48
- * 旧实现是 Object.assign(cfg, newCfg),保留运行时对原 cfg 对象的引用 — 同样行为。
49
- */
50
- export function reloadInto(cfg) {
51
- try {
52
- const fresh = readFromDisk();
53
- Object.assign(cfg, fresh);
54
- }
55
- catch (e) {
56
- // reload 失败不抛,旧实现也是只 log
57
- log.error(`重载配置失败: ${e.message}`);
58
- }
42
+ function reloadInto(cfg) {
43
+ try {
44
+ const fresh = readFromDisk();
45
+ Object.assign(cfg, fresh);
46
+ } catch (e) {
47
+ log.error(`\u91CD\u8F7D\u914D\u7F6E\u5931\u8D25: ${e.message}`);
48
+ }
59
49
  }
60
- //# sourceMappingURL=config.js.map
50
+ export {
51
+ CFG_PATH,
52
+ ROOT_DIR,
53
+ loadInitialConfig,
54
+ reloadInto
55
+ };
56
+ //# sourceMappingURL=config.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAG/B,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,gEAAgE;AAChE,MAAM,CAAC,MAAM,QAAQ,GAAW,kBAAkB,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AACnF,MAAM,CAAC,MAAM,QAAQ,GAAW,UAAU,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AAEvE,SAAS,aAAa,CAAC,GAA4B;IACjD,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU,KAAK,KAAK;QACpC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QAC1D,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;QAC1C,iBAAiB,EAAE,MAAM,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;QACtD,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,WAAW,CAAC;QAC3C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACpD,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,IAAI,MAAM,CAAC;QAClD,GAAG,GAAG;KACP,CAAC;AACJ,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,GAAG,GAAG,QAAQ,CAA0B,QAAQ,CAAC,CAAC;IACxD,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;IACvD,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,OAAO,YAAY,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,KAAK,CAAC,WAAW,QAAQ,KAAM,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,GAAmB;IAC5C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,yBAAyB;QACzB,GAAG,CAAC,KAAK,CAAC,WAAY,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/config.ts"],
4
+ "sourcesContent": ["/**\n * config.ts \u2014 \u52A0\u8F7D configs/qq_config.json\n *\n * \u884C\u4E3A\u4E0E\u65E7 index.js \u4FDD\u6301\u5B8C\u5168\u4E00\u81F4:\n * - \u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u89E3\u6790\u5931\u8D25: \u8FDB\u7A0B\u9000\u51FA (\u65E7\u7248 process.exit(1))\n * - \u5B57\u6BB5\u7F3A\u5931: \u8D70\u9ED8\u8BA4\u503C\n * - reload \u65F6\u4EC5\u8986\u76D6\u539F\u5BF9\u8C61 (mutate), \u4FDD\u7559\u8FD0\u884C\u65F6\u5F15\u7528\u7684\u540C\u4E00\u4EFD\u5BF9\u8C61\n */\n\nimport {\n configPath,\n DEFAULT_QQ_CONFIG,\n loadEnsuredConfig,\n stripConfigMeta,\n} from \"@sfmc-bds/sdk/node/config\";\nimport { log } from \"./log.js\";\nimport { PROJECT_ROOT } from \"./project-root.js\";\nimport type { QQBridgeConfig } from \"./types.js\";\n\n/** \u7EDF\u4E00\u901A\u8FC7 SDK \u89E3\u6790\u9879\u76EE\u6839:env SFMC_ROOT > project-root \u4E0A\u6EAF\u3002 */\nexport const ROOT_DIR: string = PROJECT_ROOT;\nexport const CFG_PATH: string = configPath(ROOT_DIR, \"qq_config.json\");\n\nfunction applyDefaults(raw: Partial<QQBridgeConfig>): QQBridgeConfig {\n /* \u4EE5 SDK DEFAULT_QQ_CONFIG \u4E3A\u552F\u4E00\u7F3A\u7701\u6743\u5A01\uFF08DRY/LSP\uFF09\uFF0C\u518D\u53E0\u8FD0\u884C\u65F6\u6D3E\u751F\u5B57\u6BB5 */\n const merged = { ...DEFAULT_QQ_CONFIG, ...raw } as Partial<QQBridgeConfig> & Record<string, unknown>;\n const stripped = stripConfigMeta(merged);\n return {\n qq_enabled: stripped.qq_enabled !== false,\n qq_ws_port: parseInt(String(stripped.qq_ws_port ?? DEFAULT_QQ_CONFIG.qq_ws_port ?? 3002), 10),\n qq_group_id: String(stripped.qq_group_id ?? DEFAULT_QQ_CONFIG.qq_group_id ?? \"0\"),\n bridge_channel_id: String(stripped.bridge_channel_id ?? DEFAULT_QQ_CONFIG.bridge_channel_id ?? \"\"),\n db_host: String(stripped.db_host ?? \"127.0.0.1\"),\n db_port: parseInt(String(stripped.db_port ?? \"3001\"), 10),\n mctoqq_prefix: String(stripped.mctoqq_prefix ?? DEFAULT_QQ_CONFIG.mctoqq_prefix ?? \"[MC]\"),\n ...stripped,\n };\n}\n\nfunction readFromDisk(): QQBridgeConfig {\n const raw = loadEnsuredConfig(\n ROOT_DIR,\n \"qq_config.json\",\n \"qq_config\",\n { ...DEFAULT_QQ_CONFIG } as Record<string, unknown>\n );\n return applyDefaults(raw as Partial<QQBridgeConfig>);\n}\n\n/** \u8FDB\u7A0B\u542F\u52A8\u65F6\u52A0\u8F7D\u4E00\u6B21\u3002\u5931\u8D25\u76F4\u63A5\u9000\u51FA,\u4E0E\u65E7\u5B9E\u73B0\u4E00\u81F4\u3002 */\nexport function loadInitialConfig(): QQBridgeConfig {\n try {\n return readFromDisk();\n } catch (e) {\n log.error(`\u65E0\u6CD5\u8BFB\u53D6\u914D\u7F6E: ${CFG_PATH}: ${(e as Error).message}`);\n process.exit(1);\n }\n}\n\n/**\n * \u91CD\u65B0\u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6,\u5408\u5E76\u5230\u4F20\u5165\u5BF9\u8C61\u4E0A (mutate)\u3002\n * \u65E7\u5B9E\u73B0\u662F Object.assign(cfg, newCfg),\u4FDD\u7559\u8FD0\u884C\u65F6\u5BF9\u539F cfg \u5BF9\u8C61\u7684\u5F15\u7528 \u2014 \u540C\u6837\u884C\u4E3A\u3002\n */\nexport function reloadInto(cfg: QQBridgeConfig): void {\n try {\n const fresh = readFromDisk();\n Object.assign(cfg, fresh);\n } catch (e) {\n // reload \u5931\u8D25\u4E0D\u629B,\u65E7\u5B9E\u73B0\u4E5F\u662F\u53EA log\n log.error(`\u91CD\u8F7D\u914D\u7F6E\u5931\u8D25: ${(e as Error).message}`);\n }\n}\n"],
5
+ "mappings": "AASA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,WAAW;AACpB,SAAS,oBAAoB;AAItB,MAAM,WAAmB;AACzB,MAAM,WAAmB,WAAW,UAAU,gBAAgB;AAErE,SAAS,cAAc,KAA8C;AAEnE,QAAM,SAAS,EAAE,GAAG,mBAAmB,GAAG,IAAI;AAC9C,QAAM,WAAW,gBAAgB,MAAM;AACvC,SAAO;AAAA,IACL,YAAY,SAAS,eAAe;AAAA,IACpC,YAAY,SAAS,OAAO,SAAS,cAAc,kBAAkB,cAAc,IAAI,GAAG,EAAE;AAAA,IAC5F,aAAa,OAAO,SAAS,eAAe,kBAAkB,eAAe,GAAG;AAAA,IAChF,mBAAmB,OAAO,SAAS,qBAAqB,kBAAkB,qBAAqB,EAAE;AAAA,IACjG,SAAS,OAAO,SAAS,WAAW,WAAW;AAAA,IAC/C,SAAS,SAAS,OAAO,SAAS,WAAW,MAAM,GAAG,EAAE;AAAA,IACxD,eAAe,OAAO,SAAS,iBAAiB,kBAAkB,iBAAiB,MAAM;AAAA,IACzF,GAAG;AAAA,EACL;AACF;AAEA,SAAS,eAA+B;AACtC,QAAM,MAAM;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,GAAG,kBAAkB;AAAA,EACzB;AACA,SAAO,cAAc,GAA8B;AACrD;AAGO,SAAS,oBAAoC;AAClD,MAAI;AACF,WAAO,aAAa;AAAA,EACtB,SAAS,GAAG;AACV,QAAI,MAAM,yCAAW,QAAQ,KAAM,EAAY,OAAO,EAAE;AACxD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAMO,SAAS,WAAW,KAA2B;AACpD,MAAI;AACF,UAAM,QAAQ,aAAa;AAC3B,WAAO,OAAO,KAAK,KAAK;AAAA,EAC1B,SAAS,GAAG;AAEV,QAAI,MAAM,yCAAY,EAAY,OAAO,EAAE;AAAA,EAC7C;AACF;",
6
+ "names": []
7
+ }
package/dist/console.js CHANGED
@@ -1,76 +1,70 @@
1
- /**
2
- * console.ts — 交互式控制台 (readline)
3
- *
4
- * 命令:
5
- * help 显示帮助
6
- * reload 重新读取 configs/qq_config.json
7
- * status 显示当前状态
8
- * stop 退出进程
9
- *
10
- * 行为与旧实现完全一致。
11
- */
12
1
  import { createInterface } from "node:readline";
13
2
  import { log } from "./log.js";
14
3
  import { reloadInto } from "./config.js";
15
4
  function showHelp() {
16
- console.log("可用命令:");
17
- console.log(" help 显示本帮助");
18
- console.log(" reload 重新读取 qq_config.json");
19
- console.log(" status 显示当前状态");
20
- console.log(" stop 停止服务");
5
+ console.log("\u53EF\u7528\u547D\u4EE4:");
6
+ console.log(" help \u2014 \u663E\u793A\u672C\u5E2E\u52A9");
7
+ console.log(" reload \u2014 \u91CD\u65B0\u8BFB\u53D6 qq_config.json");
8
+ console.log(" status \u2014 \u663E\u793A\u5F53\u524D\u72B6\u6001");
9
+ console.log(" stop \u2014 \u505C\u6B62\u670D\u52A1");
21
10
  }
22
11
  function showStatus(opts) {
23
- const { config: cfg, initialEnabled, wsPort, botSelfIdRef } = opts;
24
- console.log("=== QQBridge 状态 ===");
25
- console.log(` 启用: ${initialEnabled}`);
26
- console.log(` WS 端口: ${wsPort}`);
27
- console.log(` LLBot HTTP: (db-server 直连,不经过本进程)`);
28
- console.log(` QQ 群: ${cfg.qq_group_id || "未配置"}`);
29
- console.log(` Channel: ${cfg.bridge_channel_id || "未配置"}`);
30
- console.log(` db-server: ${cfg.db_host}:${cfg.db_port}`);
31
- console.log(` Bot self_id: ${botSelfIdRef.value || "未捕获"}`);
32
- console.log(` MC→QQ 前缀: ${cfg.mctoqq_prefix}`);
12
+ const { config: cfg, initialEnabled, wsPort, botSelfIdRef } = opts;
13
+ console.log("=== QQBridge \u72B6\u6001 ===");
14
+ console.log(` \u542F\u7528: ${initialEnabled}`);
15
+ console.log(` WS \u7AEF\u53E3: ${wsPort}`);
16
+ console.log(` LLBot HTTP: (db-server \u76F4\u8FDE,\u4E0D\u7ECF\u8FC7\u672C\u8FDB\u7A0B)`);
17
+ console.log(` QQ \u7FA4: ${cfg.qq_group_id || "\u672A\u914D\u7F6E"}`);
18
+ console.log(` Channel: ${cfg.bridge_channel_id || "\u672A\u914D\u7F6E"}`);
19
+ console.log(` db-server: ${cfg.db_host}:${cfg.db_port}`);
20
+ console.log(` Bot self_id: ${botSelfIdRef.value || "\u672A\u6355\u83B7"}`);
21
+ console.log(` MC\u2192QQ \u524D\u7F00: ${cfg.mctoqq_prefix}`);
33
22
  }
34
23
  function handleCommand(line, opts, rl) {
35
- const cmd = line.trim().toLowerCase();
36
- switch (cmd) {
37
- case "help":
38
- showHelp();
39
- return false;
40
- case "reload": {
41
- const before = {
42
- qq_group_id: opts.config.qq_group_id,
43
- bridge_channel_id: opts.config.bridge_channel_id,
44
- db_host: opts.config.db_host,
45
- db_port: opts.config.db_port,
46
- };
47
- reloadInto(opts.config);
48
- log.info(`配置已重载 (qq_group_id=${opts.config.qq_group_id}, channel=${opts.config.bridge_channel_id}, db=${opts.config.db_host}:${opts.config.db_port})`);
49
- // 静默消费未使用变量警告
50
- void before;
51
- return false;
52
- }
53
- case "status":
54
- showStatus(opts);
55
- return false;
56
- case "stop":
57
- case "exit":
58
- case "quit":
59
- log.info("正在停止...");
60
- rl.close();
61
- process.exit(0);
62
- return true; // 不可达,但满足 noImplicitReturns
63
- case "":
64
- return false;
65
- default:
66
- log.info(`未知命令: ${cmd} (输入 help 查看帮助)`);
67
- return false;
24
+ const cmd = line.trim().toLowerCase();
25
+ switch (cmd) {
26
+ case "help":
27
+ showHelp();
28
+ return false;
29
+ case "reload": {
30
+ const before = {
31
+ qq_group_id: opts.config.qq_group_id,
32
+ bridge_channel_id: opts.config.bridge_channel_id,
33
+ db_host: opts.config.db_host,
34
+ db_port: opts.config.db_port
35
+ };
36
+ reloadInto(opts.config);
37
+ log.info(
38
+ `\u914D\u7F6E\u5DF2\u91CD\u8F7D (qq_group_id=${opts.config.qq_group_id}, channel=${opts.config.bridge_channel_id}, db=${opts.config.db_host}:${opts.config.db_port})`
39
+ );
40
+ void before;
41
+ return false;
68
42
  }
43
+ case "status":
44
+ showStatus(opts);
45
+ return false;
46
+ case "stop":
47
+ case "exit":
48
+ case "quit":
49
+ log.info("\u6B63\u5728\u505C\u6B62...");
50
+ rl.close();
51
+ process.exit(0);
52
+ return true;
53
+ // 不可达,但满足 noImplicitReturns
54
+ case "":
55
+ return false;
56
+ default:
57
+ log.info(`\u672A\u77E5\u547D\u4EE4: ${cmd} (\u8F93\u5165 help \u67E5\u770B\u5E2E\u52A9)`);
58
+ return false;
59
+ }
69
60
  }
70
- export function startConsole(opts) {
71
- const rl = createInterface({ input: process.stdin, output: process.stdout });
72
- rl.on("line", (line) => {
73
- handleCommand(line, opts, rl);
74
- });
61
+ function startConsole(opts) {
62
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
63
+ rl.on("line", (line) => {
64
+ handleCommand(line, opts, rl);
65
+ });
75
66
  }
76
- //# sourceMappingURL=console.js.map
67
+ export {
68
+ startConsole
69
+ };
70
+ //# sourceMappingURL=console.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"console.js","sourceRoot":"","sources":["../src/console.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/console.ts"],
4
+ "sourcesContent": ["/**\n * console.ts \u2014 \u4EA4\u4E92\u5F0F\u63A7\u5236\u53F0 (readline)\n *\n * \u547D\u4EE4:\n * help \u663E\u793A\u5E2E\u52A9\n * reload \u91CD\u65B0\u8BFB\u53D6 configs/qq_config.json\n * status \u663E\u793A\u5F53\u524D\u72B6\u6001\n * stop \u9000\u51FA\u8FDB\u7A0B\n *\n * \u884C\u4E3A\u4E0E\u65E7\u5B9E\u73B0\u5B8C\u5168\u4E00\u81F4\u3002\n */\n\nimport { createInterface, type Interface as RLInterface } from \"node:readline\";\nimport { log } from \"./log.js\";\nimport { reloadInto } from \"./config.js\";\nimport type { QQBridgeConfig } from \"./types.js\";\n\nexport interface ConsoleOptions {\n config: QQBridgeConfig;\n initialEnabled: boolean;\n wsPort: number;\n botSelfIdRef: { value: string | null };\n}\n\nfunction showHelp(): void {\n console.log(\"\u53EF\u7528\u547D\u4EE4:\");\n console.log(\" help \u2014 \u663E\u793A\u672C\u5E2E\u52A9\");\n console.log(\" reload \u2014 \u91CD\u65B0\u8BFB\u53D6 qq_config.json\");\n console.log(\" status \u2014 \u663E\u793A\u5F53\u524D\u72B6\u6001\");\n console.log(\" stop \u2014 \u505C\u6B62\u670D\u52A1\");\n}\n\nfunction showStatus(opts: ConsoleOptions): void {\n const { config: cfg, initialEnabled, wsPort, botSelfIdRef } = opts;\n console.log(\"=== QQBridge \u72B6\u6001 ===\");\n console.log(` \u542F\u7528: ${initialEnabled}`);\n console.log(` WS \u7AEF\u53E3: ${wsPort}`);\n console.log(` LLBot HTTP: (db-server \u76F4\u8FDE,\u4E0D\u7ECF\u8FC7\u672C\u8FDB\u7A0B)`);\n console.log(` QQ \u7FA4: ${cfg.qq_group_id || \"\u672A\u914D\u7F6E\"}`);\n console.log(` Channel: ${cfg.bridge_channel_id || \"\u672A\u914D\u7F6E\"}`);\n console.log(` db-server: ${cfg.db_host}:${cfg.db_port}`);\n console.log(` Bot self_id: ${botSelfIdRef.value || \"\u672A\u6355\u83B7\"}`);\n console.log(` MC\u2192QQ \u524D\u7F00: ${cfg.mctoqq_prefix}`);\n}\n\nfunction handleCommand(line: string, opts: ConsoleOptions, rl: RLInterface): boolean {\n const cmd = line.trim().toLowerCase();\n switch (cmd) {\n case \"help\":\n showHelp();\n return false;\n case \"reload\": {\n const before = {\n qq_group_id: opts.config.qq_group_id,\n bridge_channel_id: opts.config.bridge_channel_id,\n db_host: opts.config.db_host,\n db_port: opts.config.db_port,\n };\n reloadInto(opts.config);\n log.info(\n `\u914D\u7F6E\u5DF2\u91CD\u8F7D (qq_group_id=${opts.config.qq_group_id}, channel=${opts.config.bridge_channel_id}, db=${opts.config.db_host}:${opts.config.db_port})`\n );\n // \u9759\u9ED8\u6D88\u8D39\u672A\u4F7F\u7528\u53D8\u91CF\u8B66\u544A\n void before;\n return false;\n }\n case \"status\":\n showStatus(opts);\n return false;\n case \"stop\":\n case \"exit\":\n case \"quit\":\n log.info(\"\u6B63\u5728\u505C\u6B62...\");\n rl.close();\n process.exit(0);\n return true; // \u4E0D\u53EF\u8FBE,\u4F46\u6EE1\u8DB3 noImplicitReturns\n case \"\":\n return false;\n default:\n log.info(`\u672A\u77E5\u547D\u4EE4: ${cmd} (\u8F93\u5165 help \u67E5\u770B\u5E2E\u52A9)`);\n return false;\n }\n}\n\nexport function startConsole(opts: ConsoleOptions): void {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.on(\"line\", (line) => {\n handleCommand(line, opts, rl);\n });\n}\n"],
5
+ "mappings": "AAYA,SAAS,uBAAsD;AAC/D,SAAS,WAAW;AACpB,SAAS,kBAAkB;AAU3B,SAAS,WAAiB;AACxB,UAAQ,IAAI,2BAAO;AACnB,UAAQ,IAAI,iDAAmB;AAC/B,UAAQ,IAAI,0DAAiC;AAC7C,UAAQ,IAAI,uDAAoB;AAChC,UAAQ,IAAI,2CAAkB;AAChC;AAEA,SAAS,WAAW,MAA4B;AAC9C,QAAM,EAAE,QAAQ,KAAK,gBAAgB,QAAQ,aAAa,IAAI;AAC9D,UAAQ,IAAI,+BAAqB;AACjC,UAAQ,IAAI,0BAAgB,cAAc,EAAE;AAC5C,UAAQ,IAAI,0BAAgB,MAAM,EAAE;AACpC,UAAQ,IAAI,8EAAsC;AAClD,UAAQ,IAAI,sBAAiB,IAAI,eAAe,oBAAK,EAAE;AACvD,UAAQ,IAAI,kBAAkB,IAAI,qBAAqB,oBAAK,EAAE;AAC9D,UAAQ,IAAI,kBAAkB,IAAI,OAAO,IAAI,IAAI,OAAO,EAAE;AAC1D,UAAQ,IAAI,kBAAkB,aAAa,SAAS,oBAAK,EAAE;AAC3D,UAAQ,IAAI,+BAAgB,IAAI,aAAa,EAAE;AACjD;AAEA,SAAS,cAAc,MAAc,MAAsB,IAA0B;AACnF,QAAM,MAAM,KAAK,KAAK,EAAE,YAAY;AACpC,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,eAAS;AACT,aAAO;AAAA,IACT,KAAK,UAAU;AACb,YAAM,SAAS;AAAA,QACb,aAAa,KAAK,OAAO;AAAA,QACzB,mBAAmB,KAAK,OAAO;AAAA,QAC/B,SAAS,KAAK,OAAO;AAAA,QACrB,SAAS,KAAK,OAAO;AAAA,MACvB;AACA,iBAAW,KAAK,MAAM;AACtB,UAAI;AAAA,QACF,+CAAsB,KAAK,OAAO,WAAW,aAAa,KAAK,OAAO,iBAAiB,QAAQ,KAAK,OAAO,OAAO,IAAI,KAAK,OAAO,OAAO;AAAA,MAC3I;AAEA,WAAK;AACL,aAAO;AAAA,IACT;AAAA,IACA,KAAK;AACH,iBAAW,IAAI;AACf,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,UAAI,KAAK,6BAAS;AAClB,SAAG,MAAM;AACT,cAAQ,KAAK,CAAC;AACd,aAAO;AAAA;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,UAAI,KAAK,6BAAS,GAAG,+CAAiB;AACtC,aAAO;AAAA,EACX;AACF;AAEO,SAAS,aAAa,MAA4B;AACvD,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,KAAG,GAAG,QAAQ,CAAC,SAAS;AACtB,kBAAc,MAAM,MAAM,EAAE;AAAA,EAC9B,CAAC;AACH;",
6
+ "names": []
7
+ }
package/dist/dbserver.js CHANGED
@@ -1,83 +1,72 @@
1
- /**
2
- * dbserver.ts — 转发 OneBot 群消息到 db-server /api/sfmc/messages
3
- *
4
- * 与旧实现保持行为一致: 仅 POST 200 视为成功,否则抛错; 失败不重试 (主流程不阻塞)。
5
- * 超时: 与 db-server 内部 HTTP 风格一致,使用 req.on("timeout") + req.destroy。
6
- */
7
1
  import { request as httpRequest } from "node:http";
8
2
  import { log } from "./log.js";
9
- const REQUEST_TIMEOUT_MS = 5_000;
3
+ const REQUEST_TIMEOUT_MS = 5e3;
10
4
  function postJSON(url, body, timeoutMs) {
11
- const payload = JSON.stringify(body);
12
- const options = {
13
- hostname: url.hostname,
14
- port: url.port || "3001",
15
- path: url.pathname,
16
- method: "POST",
17
- headers: {
18
- "Content-Type": "application/json",
19
- "Content-Length": Buffer.byteLength(payload),
20
- },
21
- timeout: timeoutMs,
22
- };
23
- return new Promise((resolve, reject) => {
24
- const req = httpRequest(options, (res) => {
25
- let buf = "";
26
- res.setEncoding("utf-8");
27
- res.on("data", (chunk) => {
28
- buf += chunk;
29
- });
30
- res.on("end", () => {
31
- const code = res.statusCode ?? 0;
32
- if (code >= 200 && code < 300) {
33
- try {
34
- resolve(JSON.parse(buf));
35
- }
36
- catch {
37
- // 允许返回非 JSON: 仍视为成功,作为 void 抛出
38
- resolve(buf);
39
- }
40
- }
41
- else {
42
- reject(new Error(`db-server ${code}: ${buf.slice(0, 200)}`));
43
- }
44
- });
45
- });
46
- req.on("timeout", () => {
47
- req.destroy(new Error(`db-server 超时 ${timeoutMs}ms`));
48
- });
49
- req.on("error", reject);
50
- req.write(payload);
51
- req.end();
5
+ const payload = JSON.stringify(body);
6
+ const options = {
7
+ hostname: url.hostname,
8
+ port: url.port || "3001",
9
+ path: url.pathname,
10
+ method: "POST",
11
+ headers: {
12
+ "Content-Type": "application/json",
13
+ "Content-Length": Buffer.byteLength(payload)
14
+ },
15
+ timeout: timeoutMs
16
+ };
17
+ return new Promise((resolve, reject) => {
18
+ const req = httpRequest(options, (res) => {
19
+ let buf = "";
20
+ res.setEncoding("utf-8");
21
+ res.on("data", (chunk) => {
22
+ buf += chunk;
23
+ });
24
+ res.on("end", () => {
25
+ const code = res.statusCode ?? 0;
26
+ if (code >= 200 && code < 300) {
27
+ try {
28
+ resolve(JSON.parse(buf));
29
+ } catch {
30
+ resolve(buf);
31
+ }
32
+ } else {
33
+ reject(new Error(`db-server ${code}: ${buf.slice(0, 200)}`));
34
+ }
35
+ });
52
36
  });
37
+ req.on("timeout", () => {
38
+ req.destroy(new Error(`db-server \u8D85\u65F6 ${timeoutMs}ms`));
39
+ });
40
+ req.on("error", reject);
41
+ req.write(payload);
42
+ req.end();
43
+ });
53
44
  }
54
- /**
55
- * 构造一条 IncomingChatMessage 并 POST 到 db-server。
56
- * fromid 形如 `qq_<user_id>`,与旧实现保持完全一致。
57
- */
58
- export async function forwardGroupMessage(cfg, fromId, fromName, content, now = Date.now()) {
59
- const message = {
60
- id: `${fromId}_${now}`,
61
- channelId: cfg.channelId,
62
- fromid: fromId,
63
- fromName,
64
- type: "text",
65
- content,
66
- showTimestamp: true,
67
- timestamp: now,
68
- };
69
- const body = { messages: [message] };
70
- const url = new URL(`http://${cfg.host}:${cfg.port}/api/sfmc/messages`);
71
- await postJSON(url, body, REQUEST_TIMEOUT_MS);
45
+ async function forwardGroupMessage(cfg, fromId, fromName, content, now = Date.now()) {
46
+ const message = {
47
+ id: `${fromId}_${now}`,
48
+ channelId: cfg.channelId,
49
+ fromid: fromId,
50
+ fromName,
51
+ type: "text",
52
+ content,
53
+ showTimestamp: true,
54
+ timestamp: now
55
+ };
56
+ const body = { messages: [message] };
57
+ const url = new URL(`http://${cfg.host}:${cfg.port}/api/sfmc/messages`);
58
+ await postJSON(url, body, REQUEST_TIMEOUT_MS);
72
59
  }
73
- /** 包装 try/catch,失败仅 log (与旧实现一致,不抛给主循环) */
74
- export async function tryForward(cfg, fromId, fromName, content) {
75
- try {
76
- await forwardGroupMessage(cfg, fromId, fromName, content);
77
- log.info(`QQ MC: ${fromName}: ${content.slice(0, 60)}`);
78
- }
79
- catch (e) {
80
- log.error(`转发到 db-server 失败: ${e.message}`);
81
- }
60
+ async function tryForward(cfg, fromId, fromName, content) {
61
+ try {
62
+ await forwardGroupMessage(cfg, fromId, fromName, content);
63
+ log.info(`QQ \u2192 MC: ${fromName}: ${content.slice(0, 60)}`);
64
+ } catch (e) {
65
+ log.error(`\u8F6C\u53D1\u5230 db-server \u5931\u8D25: ${e.message}`);
66
+ }
82
67
  }
83
- //# sourceMappingURL=dbserver.js.map
68
+ export {
69
+ forwardGroupMessage,
70
+ tryForward
71
+ };
72
+ //# sourceMappingURL=dbserver.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"dbserver.js","sourceRoot":"","sources":["../src/dbserver.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/dbserver.ts"],
4
+ "sourcesContent": ["/**\n * dbserver.ts \u2014 \u8F6C\u53D1 OneBot \u7FA4\u6D88\u606F\u5230 db-server /api/sfmc/messages\n *\n * \u4E0E\u65E7\u5B9E\u73B0\u4FDD\u6301\u884C\u4E3A\u4E00\u81F4: \u4EC5 POST 200 \u89C6\u4E3A\u6210\u529F,\u5426\u5219\u629B\u9519; \u5931\u8D25\u4E0D\u91CD\u8BD5 (\u4E3B\u6D41\u7A0B\u4E0D\u963B\u585E)\u3002\n * \u8D85\u65F6: \u4E0E db-server \u5185\u90E8 HTTP \u98CE\u683C\u4E00\u81F4,\u4F7F\u7528 req.on(\"timeout\") + req.destroy\u3002\n */\n\nimport { request as httpRequest, type RequestOptions } from \"node:http\";\nimport { log } from \"./log.js\";\nimport type { IncomingChatMessage, PostMessagesBody } from \"./types.js\";\n\nexport interface DBServerConfig {\n host: string;\n port: number;\n channelId: string;\n}\n\nconst REQUEST_TIMEOUT_MS = 5_000;\n\nfunction postJSON<T>(url: URL, body: unknown, timeoutMs: number): Promise<T> {\n const payload = JSON.stringify(body);\n const options: RequestOptions = {\n hostname: url.hostname,\n port: url.port || \"3001\",\n path: url.pathname,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(payload),\n },\n timeout: timeoutMs,\n };\n return new Promise<T>((resolve, reject) => {\n const req = httpRequest(options, (res) => {\n let buf = \"\";\n res.setEncoding(\"utf-8\");\n res.on(\"data\", (chunk: string) => {\n buf += chunk;\n });\n res.on(\"end\", () => {\n const code = res.statusCode ?? 0;\n if (code >= 200 && code < 300) {\n try {\n resolve(JSON.parse(buf) as T);\n } catch {\n // \u5141\u8BB8\u8FD4\u56DE\u975E JSON: \u4ECD\u89C6\u4E3A\u6210\u529F,\u4F5C\u4E3A void \u629B\u51FA\n resolve(buf as unknown as T);\n }\n } else {\n reject(new Error(`db-server ${code}: ${buf.slice(0, 200)}`));\n }\n });\n });\n req.on(\"timeout\", () => {\n req.destroy(new Error(`db-server \u8D85\u65F6 ${timeoutMs}ms`));\n });\n req.on(\"error\", reject);\n req.write(payload);\n req.end();\n });\n}\n\n/**\n * \u6784\u9020\u4E00\u6761 IncomingChatMessage \u5E76 POST \u5230 db-server\u3002\n * fromid \u5F62\u5982 `qq_<user_id>`,\u4E0E\u65E7\u5B9E\u73B0\u4FDD\u6301\u5B8C\u5168\u4E00\u81F4\u3002\n */\nexport async function forwardGroupMessage(\n cfg: DBServerConfig,\n fromId: string,\n fromName: string,\n content: string,\n now: number = Date.now()\n): Promise<void> {\n const message: IncomingChatMessage = {\n id: `${fromId}_${now}`,\n channelId: cfg.channelId,\n fromid: fromId,\n fromName,\n type: \"text\",\n content,\n showTimestamp: true,\n timestamp: now,\n };\n const body: PostMessagesBody = { messages: [message] };\n const url = new URL(`http://${cfg.host}:${cfg.port}/api/sfmc/messages`);\n await postJSON<unknown>(url, body, REQUEST_TIMEOUT_MS);\n}\n\n/** \u5305\u88C5 try/catch,\u5931\u8D25\u4EC5 log (\u4E0E\u65E7\u5B9E\u73B0\u4E00\u81F4,\u4E0D\u629B\u7ED9\u4E3B\u5FAA\u73AF)\u3002 */\nexport async function tryForward(\n cfg: DBServerConfig,\n fromId: string,\n fromName: string,\n content: string\n): Promise<void> {\n try {\n await forwardGroupMessage(cfg, fromId, fromName, content);\n log.info(`QQ \u2192 MC: ${fromName}: ${content.slice(0, 60)}`);\n } catch (e) {\n log.error(`\u8F6C\u53D1\u5230 db-server \u5931\u8D25: ${(e as Error).message}`);\n }\n}\n"],
5
+ "mappings": "AAOA,SAAS,WAAW,mBAAwC;AAC5D,SAAS,WAAW;AASpB,MAAM,qBAAqB;AAE3B,SAAS,SAAY,KAAU,MAAe,WAA+B;AAC3E,QAAM,UAAU,KAAK,UAAU,IAAI;AACnC,QAAM,UAA0B;AAAA,IAC9B,UAAU,IAAI;AAAA,IACd,MAAM,IAAI,QAAQ;AAAA,IAClB,MAAM,IAAI;AAAA,IACV,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,kBAAkB,OAAO,WAAW,OAAO;AAAA,IAC7C;AAAA,IACA,SAAS;AAAA,EACX;AACA,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,UAAM,MAAM,YAAY,SAAS,CAAC,QAAQ;AACxC,UAAI,MAAM;AACV,UAAI,YAAY,OAAO;AACvB,UAAI,GAAG,QAAQ,CAAC,UAAkB;AAChC,eAAO;AAAA,MACT,CAAC;AACD,UAAI,GAAG,OAAO,MAAM;AAClB,cAAM,OAAO,IAAI,cAAc;AAC/B,YAAI,QAAQ,OAAO,OAAO,KAAK;AAC7B,cAAI;AACF,oBAAQ,KAAK,MAAM,GAAG,CAAM;AAAA,UAC9B,QAAQ;AAEN,oBAAQ,GAAmB;AAAA,UAC7B;AAAA,QACF,OAAO;AACL,iBAAO,IAAI,MAAM,aAAa,IAAI,KAAK,IAAI,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;AAAA,QAC7D;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AACD,QAAI,GAAG,WAAW,MAAM;AACtB,UAAI,QAAQ,IAAI,MAAM,0BAAgB,SAAS,IAAI,CAAC;AAAA,IACtD,CAAC;AACD,QAAI,GAAG,SAAS,MAAM;AACtB,QAAI,MAAM,OAAO;AACjB,QAAI,IAAI;AAAA,EACV,CAAC;AACH;AAMA,eAAsB,oBACpB,KACA,QACA,UACA,SACA,MAAc,KAAK,IAAI,GACR;AACf,QAAM,UAA+B;AAAA,IACnC,IAAI,GAAG,MAAM,IAAI,GAAG;AAAA,IACpB,WAAW,IAAI;AAAA,IACf,QAAQ;AAAA,IACR;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,eAAe;AAAA,IACf,WAAW;AAAA,EACb;AACA,QAAM,OAAyB,EAAE,UAAU,CAAC,OAAO,EAAE;AACrD,QAAM,MAAM,IAAI,IAAI,UAAU,IAAI,IAAI,IAAI,IAAI,IAAI,oBAAoB;AACtE,QAAM,SAAkB,KAAK,MAAM,kBAAkB;AACvD;AAGA,eAAsB,WACpB,KACA,QACA,UACA,SACe;AACf,MAAI;AACF,UAAM,oBAAoB,KAAK,QAAQ,UAAU,OAAO;AACxD,QAAI,KAAK,iBAAY,QAAQ,KAAK,QAAQ,MAAM,GAAG,EAAE,CAAC,EAAE;AAAA,EAC1D,SAAS,GAAG;AACV,QAAI,MAAM,8CAAsB,EAAY,OAAO,EAAE;AAAA,EACvD;AACF;",
6
+ "names": []
7
+ }
package/dist/index.js CHANGED
@@ -1,58 +1,41 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * index.ts — QQ ↔ MC 桥接进程入口
4
- *
5
- * 端口: 3002 (默认) — WebSocket (LLBot reverse-ws)
6
- *
7
- * 数据流:
8
- * QQ → MC: LLBot ──WS:3002──→ qq-bridge ──POST──→ db-server:3001/api/sfmc/messages
9
- * MC → QQ: SAPI ──POST──→ db-server:3001 ──(内部)──→ LLBot:3004/send_group_msg
10
- *
11
- * 注意: 本进程只做 WS 入口,不再起 HTTP server。MC→QQ 由 db-server 直连 LLBot
12
- * (见 db-server/src/domain/bridge.ts:forwardToQQBridge)
13
- *
14
- * 循环防护:
15
- * 1. 跳过 sender.user_id === botSelfId 的回声
16
- * (botSelfId 通过 LLBot 的 lifecycle 元事件捕获)
17
- * 2. 5 秒内同 message_id 短期去重 (防 race)
18
- */
19
2
  import { loadInitialConfig } from "./config.js";
20
3
  import { OneBotDispatcher } from "./onebot.js";
21
4
  import { startWsServer } from "./ws-server.js";
22
5
  import { startConsole } from "./console.js";
23
6
  import { log } from "./log.js";
24
7
  async function main() {
25
- const cfg = loadInitialConfig();
26
- if (!cfg.qq_enabled) {
27
- log.info("已禁用 (qq_enabled = false)");
28
- process.exit(0);
8
+ const cfg = loadInitialConfig();
9
+ if (!cfg.qq_enabled) {
10
+ log.info("\u5DF2\u7981\u7528 (qq_enabled = false)");
11
+ process.exit(0);
12
+ }
13
+ const botSelfIdRef = { value: null };
14
+ const dispatcher = new OneBotDispatcher({
15
+ qqGroupId: cfg.qq_group_id,
16
+ db: {
17
+ host: cfg.db_host,
18
+ port: cfg.db_port,
19
+ channelId: cfg.bridge_channel_id
29
20
  }
30
- // 让控制台 status 命令读到 bot 当前的 self_id
31
- const botSelfIdRef = { value: null };
32
- const dispatcher = new OneBotDispatcher({
33
- qqGroupId: cfg.qq_group_id,
34
- db: {
35
- host: cfg.db_host,
36
- port: cfg.db_port,
37
- channelId: cfg.bridge_channel_id,
38
- },
39
- });
40
- // botSelfId 通过 dispatcher 内部维护; 控制台读 self_id 时取最新值
41
- Object.defineProperty(botSelfIdRef, "value", {
42
- get: () => dispatcher.selfId,
43
- });
44
- await startWsServer({ port: cfg.qq_ws_port, dispatcher });
45
- log.info(`等待 LLBot 连接 (主群: ${cfg.qq_group_id || "未配置"}, channel: ${cfg.bridge_channel_id || "未配置"}, db: ${cfg.db_host}:${cfg.db_port})`);
46
- startConsole({
47
- config: cfg,
48
- initialEnabled: cfg.qq_enabled,
49
- wsPort: cfg.qq_ws_port,
50
- botSelfIdRef,
51
- });
52
- log.info("启动完成");
21
+ });
22
+ Object.defineProperty(botSelfIdRef, "value", {
23
+ get: () => dispatcher.selfId
24
+ });
25
+ await startWsServer({ port: cfg.qq_ws_port, dispatcher });
26
+ log.info(
27
+ `\u7B49\u5F85 LLBot \u8FDE\u63A5 (\u4E3B\u7FA4: ${cfg.qq_group_id || "\u672A\u914D\u7F6E"}, channel: ${cfg.bridge_channel_id || "\u672A\u914D\u7F6E"}, db: ${cfg.db_host}:${cfg.db_port})`
28
+ );
29
+ startConsole({
30
+ config: cfg,
31
+ initialEnabled: cfg.qq_enabled,
32
+ wsPort: cfg.qq_ws_port,
33
+ botSelfIdRef
34
+ });
35
+ log.info("\u542F\u52A8\u5B8C\u6210");
53
36
  }
54
37
  main().catch((e) => {
55
- log.error(`未捕获异常: ${e.message}`);
56
- process.exit(1);
38
+ log.error(`\u672A\u6355\u83B7\u5F02\u5E38: ${e.message}`);
39
+ process.exit(1);
57
40
  });
58
- //# sourceMappingURL=index.js.map
41
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1,7 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAG/B,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAmB,iBAAiB,EAAE,CAAC;IAEhD,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QACpB,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,mCAAmC;IACnC,MAAM,YAAY,GAA6B,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAE/D,MAAM,UAAU,GAAG,IAAI,gBAAgB,CAAC;QACtC,SAAS,EAAE,GAAG,CAAC,WAAW;QAC1B,EAAE,EAAE;YACF,IAAI,EAAE,GAAG,CAAC,OAAO;YACjB,IAAI,EAAE,GAAG,CAAC,OAAO;YACjB,SAAS,EAAE,GAAG,CAAC,iBAAiB;SACjC;KACF,CAAC,CAAC;IAEH,mDAAmD;IACnD,MAAM,CAAC,cAAc,CAAC,YAAY,EAAE,OAAO,EAAE;QAC3C,GAAG,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM;KAC7B,CAAC,CAAC;IAEH,MAAM,aAAa,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;IAE1D,GAAG,CAAC,IAAI,CACN,oBAAoB,GAAG,CAAC,WAAW,IAAI,KAAK,cAAc,GAAG,CAAC,iBAAiB,IAAI,KAAK,SAAS,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,GAAG,CAC/H,CAAC;IAEF,YAAY,CAAC;QACX,MAAM,EAAE,GAAG;QACX,cAAc,EAAE,GAAG,CAAC,UAAU;QAC9B,MAAM,EAAE,GAAG,CAAC,UAAU;QACtB,YAAY;KACb,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACnB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACjB,GAAG,CAAC,KAAK,CAAC,UAAW,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["#!/usr/bin/env node\n/**\n * index.ts \u2014 QQ \u2194 MC \u6865\u63A5\u8FDB\u7A0B\u5165\u53E3\n *\n * \u7AEF\u53E3: 3002 (\u9ED8\u8BA4) \u2014 WebSocket (LLBot reverse-ws)\n *\n * \u6570\u636E\u6D41:\n * QQ \u2192 MC: LLBot \u2500\u2500WS:3002\u2500\u2500\u2192 qq-bridge \u2500\u2500POST\u2500\u2500\u2192 db-server:3001/api/sfmc/messages\n * MC \u2192 QQ: SAPI \u2500\u2500POST\u2500\u2500\u2192 db-server:3001 \u2500\u2500(\u5185\u90E8)\u2500\u2500\u2192 LLBot:3004/send_group_msg\n *\n * \u6CE8\u610F: \u672C\u8FDB\u7A0B\u53EA\u505A WS \u5165\u53E3,\u4E0D\u518D\u8D77 HTTP server\u3002MC\u2192QQ \u7531 db-server \u76F4\u8FDE LLBot\n * (\u89C1 db-server/src/domain/bridge.ts:forwardToQQBridge)\n *\n * \u5FAA\u73AF\u9632\u62A4:\n * 1. \u8DF3\u8FC7 sender.user_id === botSelfId \u7684\u56DE\u58F0\n * (botSelfId \u901A\u8FC7 LLBot \u7684 lifecycle \u5143\u4E8B\u4EF6\u6355\u83B7)\n * 2. 5 \u79D2\u5185\u540C message_id \u77ED\u671F\u53BB\u91CD (\u9632 race)\n */\n\nimport { loadInitialConfig } from \"./config.js\";\nimport { OneBotDispatcher } from \"./onebot.js\";\nimport { startWsServer } from \"./ws-server.js\";\nimport { startConsole } from \"./console.js\";\nimport { log } from \"./log.js\";\nimport type { QQBridgeConfig } from \"./types.js\";\n\nasync function main(): Promise<void> {\n const cfg: QQBridgeConfig = loadInitialConfig();\n\n if (!cfg.qq_enabled) {\n log.info(\"\u5DF2\u7981\u7528 (qq_enabled = false)\");\n process.exit(0);\n }\n\n // \u8BA9\u63A7\u5236\u53F0 status \u547D\u4EE4\u8BFB\u5230 bot \u5F53\u524D\u7684 self_id\n const botSelfIdRef: { value: string | null } = { value: null };\n\n const dispatcher = new OneBotDispatcher({\n qqGroupId: cfg.qq_group_id,\n db: {\n host: cfg.db_host,\n port: cfg.db_port,\n channelId: cfg.bridge_channel_id,\n },\n });\n\n // botSelfId \u901A\u8FC7 dispatcher \u5185\u90E8\u7EF4\u62A4; \u63A7\u5236\u53F0\u8BFB self_id \u65F6\u53D6\u6700\u65B0\u503C\n Object.defineProperty(botSelfIdRef, \"value\", {\n get: () => dispatcher.selfId,\n });\n\n await startWsServer({ port: cfg.qq_ws_port, dispatcher });\n\n log.info(\n `\u7B49\u5F85 LLBot \u8FDE\u63A5 (\u4E3B\u7FA4: ${cfg.qq_group_id || \"\u672A\u914D\u7F6E\"}, channel: ${cfg.bridge_channel_id || \"\u672A\u914D\u7F6E\"}, db: ${cfg.db_host}:${cfg.db_port})`\n );\n\n startConsole({\n config: cfg,\n initialEnabled: cfg.qq_enabled,\n wsPort: cfg.qq_ws_port,\n botSelfIdRef,\n });\n\n log.info(\"\u542F\u52A8\u5B8C\u6210\");\n}\n\nmain().catch((e) => {\n log.error(`\u672A\u6355\u83B7\u5F02\u5E38: ${(e as Error).message}`);\n process.exit(1);\n});\n"],
5
+ "mappings": ";AAmBA,SAAS,yBAAyB;AAClC,SAAS,wBAAwB;AACjC,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAC7B,SAAS,WAAW;AAGpB,eAAe,OAAsB;AACnC,QAAM,MAAsB,kBAAkB;AAE9C,MAAI,CAAC,IAAI,YAAY;AACnB,QAAI,KAAK,yCAA0B;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,eAAyC,EAAE,OAAO,KAAK;AAE7D,QAAM,aAAa,IAAI,iBAAiB;AAAA,IACtC,WAAW,IAAI;AAAA,IACf,IAAI;AAAA,MACF,MAAM,IAAI;AAAA,MACV,MAAM,IAAI;AAAA,MACV,WAAW,IAAI;AAAA,IACjB;AAAA,EACF,CAAC;AAGD,SAAO,eAAe,cAAc,SAAS;AAAA,IAC3C,KAAK,MAAM,WAAW;AAAA,EACxB,CAAC;AAED,QAAM,cAAc,EAAE,MAAM,IAAI,YAAY,WAAW,CAAC;AAExD,MAAI;AAAA,IACF,kDAAoB,IAAI,eAAe,oBAAK,cAAc,IAAI,qBAAqB,oBAAK,SAAS,IAAI,OAAO,IAAI,IAAI,OAAO;AAAA,EAC7H;AAEA,eAAa;AAAA,IACX,QAAQ;AAAA,IACR,gBAAgB,IAAI;AAAA,IACpB,QAAQ,IAAI;AAAA,IACZ;AAAA,EACF,CAAC;AAED,MAAI,KAAK,0BAAM;AACjB;AAEA,KAAK,EAAE,MAAM,CAAC,MAAM;AAClB,MAAI,MAAM,mCAAW,EAAY,OAAO,EAAE;AAC1C,UAAQ,KAAK,CAAC;AAChB,CAAC;",
6
+ "names": []
7
+ }
package/dist/log.js CHANGED
@@ -1,15 +1,11 @@
1
- /**
2
- * log.ts qq-bridge 统一日志实例
3
- *
4
- * 通过 @sfmc-bds/logs 共享包接入,source = "qq"。
5
- * sfmc 主进程通过捕获本进程 stdout 汇聚展示。
6
- *
7
- * bare 模式: stdout 只输出纯 text,不加时间戳/source/level 前缀
8
- * (由 sfmc 的 formatLog 统一添加,避免重复)。error 走 stderr。
9
- */
10
- import { createLogger, createStdoutSink } from "@sfmc-bds/sdk/logs";
11
- export const log = createLogger({
12
- source: "qq",
13
- sinks: [createStdoutSink({ bare: true })],
1
+ import { createNodeServiceLogger } from "@sfmc-bds/sdk/logs";
2
+ import { logFile } from "@sfmc-bds/sdk/node/config";
3
+ import { PROJECT_ROOT } from "./project-root.js";
4
+ const log = createNodeServiceLogger({
5
+ source: "qq",
6
+ logPath: logFile(PROJECT_ROOT, "qq")
14
7
  });
15
- //# sourceMappingURL=log.js.map
8
+ export {
9
+ log
10
+ };
11
+ //# sourceMappingURL=log.js.map
package/dist/log.js.map CHANGED
@@ -1 +1,7 @@
1
- {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEpE,MAAM,CAAC,MAAM,GAAG,GAAG,YAAY,CAAC;IAC9B,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;CAC1C,CAAC,CAAC"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/log.ts"],
4
+ "sourcesContent": ["/**\n * log.ts \u2014 qq-bridge \u7EDF\u4E00\u65E5\u5FD7\u5B9E\u4F8B\n *\n * stdout bare + \u843D\u76D8 `<SFMC_ROOT>/.sfmc/logs/qq.log`\u3002\n * bare: \u53EA\u8F93\u51FA\u7EAF text,\u7531 sfmc \u6355\u83B7\u540E\u7EDF\u4E00\u52A0\u524D\u7F00;error \u8D70 stderr\u3002\n */\n\nimport { createNodeServiceLogger } from \"@sfmc-bds/sdk/logs\";\nimport { logFile } from \"@sfmc-bds/sdk/node/config\";\nimport { PROJECT_ROOT } from \"./project-root.js\";\n\nexport const log = createNodeServiceLogger({\n source: \"qq\",\n logPath: logFile(PROJECT_ROOT, \"qq\"),\n});\n"],
5
+ "mappings": "AAOA,SAAS,+BAA+B;AACxC,SAAS,eAAe;AACxB,SAAS,oBAAoB;AAEtB,MAAM,MAAM,wBAAwB;AAAA,EACzC,QAAQ;AAAA,EACR,SAAS,QAAQ,cAAc,IAAI;AACrC,CAAC;",
6
+ "names": []
7
+ }