@sfmc-bds/db-server 0.2.0-beta.4 → 0.2.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +663 -0
- package/dist/domain/bridge.d.ts +57 -23
- package/dist/domain/bridge.d.ts.map +1 -1
- package/dist/domain/bridge.js +77 -6
- package/dist/domain/bridge.js.map +2 -2
- package/dist/domain/bridge.test.d.ts +2 -0
- package/dist/domain/bridge.test.d.ts.map +1 -0
- package/dist/domain/bridge.test.js +87 -0
- package/dist/domain/bridge.test.js.map +7 -0
- package/dist/domain/economy.d.ts +38 -7
- package/dist/domain/economy.d.ts.map +1 -1
- package/dist/domain/economy.js.map +2 -2
- package/dist/domain/messages-bridge-filter.test.d.ts +5 -0
- package/dist/domain/messages-bridge-filter.test.d.ts.map +1 -0
- package/dist/domain/messages-bridge-filter.test.js +20 -0
- package/dist/domain/messages-bridge-filter.test.js.map +7 -0
- package/dist/domain/qq-bind-status.test.d.ts +2 -0
- package/dist/domain/qq-bind-status.test.d.ts.map +1 -0
- package/dist/domain/qq-bind-status.test.js +211 -0
- package/dist/domain/qq-bind-status.test.js.map +7 -0
- package/dist/domain/qq-events.d.ts +84 -0
- package/dist/domain/qq-events.d.ts.map +1 -0
- package/dist/domain/qq-events.js +193 -0
- package/dist/domain/qq-events.js.map +7 -0
- package/dist/domain/qq-events.test.d.ts +5 -0
- package/dist/domain/qq-events.test.d.ts.map +1 -0
- package/dist/domain/qq-events.test.js +170 -0
- package/dist/domain/qq-events.test.js.map +7 -0
- package/dist/domain/qq-join.test.d.ts +2 -0
- package/dist/domain/qq-join.test.d.ts.map +1 -0
- package/dist/domain/qq-join.test.js +353 -0
- package/dist/domain/qq-join.test.js.map +7 -0
- package/dist/domain/schema.d.ts +17 -19
- package/dist/domain/schema.d.ts.map +1 -1
- package/dist/domain/schema.js +69 -0
- package/dist/domain/schema.js.map +2 -2
- package/dist/domain/system-status.d.ts +75 -0
- package/dist/domain/system-status.d.ts.map +1 -0
- package/dist/domain/system-status.js +181 -0
- package/dist/domain/system-status.js.map +7 -0
- package/dist/domain/system-status.test.d.ts +5 -0
- package/dist/domain/system-status.test.d.ts.map +1 -0
- package/dist/domain/system-status.test.js +19 -0
- package/dist/domain/system-status.test.js.map +7 -0
- package/dist/domain/transaction.d.ts +5 -4
- package/dist/domain/transaction.d.ts.map +1 -1
- package/dist/domain/transaction.js.map +2 -2
- package/dist/env.d.ts +7 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +55 -3
- package/dist/env.js.map +2 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +105 -19
- package/dist/index.js.map +2 -2
- package/dist/lib/idempotency-store.d.ts +17 -11
- package/dist/lib/idempotency-store.d.ts.map +1 -1
- package/dist/lib/idempotency-store.js.map +2 -2
- package/dist/lib/idempotency.d.ts +3 -4
- package/dist/lib/idempotency.d.ts.map +1 -1
- package/dist/lib/idempotency.js.map +2 -2
- package/dist/lib/module-state.d.ts +38 -8
- package/dist/lib/module-state.d.ts.map +1 -1
- package/dist/lib/module-state.js.map +2 -2
- package/dist/lib/order-by.d.ts +8 -6
- package/dist/lib/order-by.d.ts.map +1 -1
- package/dist/lib/order-by.js.map +2 -2
- package/dist/lib/sql-helpers.d.ts +25 -13
- package/dist/lib/sql-helpers.d.ts.map +1 -1
- package/dist/lib/sql-helpers.js.map +2 -2
- package/dist/lib/sqlite.d.ts +14 -5
- package/dist/lib/sqlite.d.ts.map +1 -1
- package/dist/lib/sqlite.js.map +2 -2
- package/dist/manifest-loader.d.ts +5 -2
- package/dist/manifest-loader.d.ts.map +1 -1
- package/dist/manifest-loader.js +16 -6
- package/dist/manifest-loader.js.map +2 -2
- package/dist/manifest.d.ts +1 -2
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +13 -8
- package/dist/manifest.js.map +2 -2
- package/dist/project-root.d.ts +1 -1
- package/dist/project-root.d.ts.map +1 -1
- package/dist/project-root.js +2 -2
- package/dist/project-root.js.map +2 -2
- package/dist/routes/_shared.d.ts +14 -5
- package/dist/routes/_shared.d.ts.map +1 -1
- package/dist/routes/_shared.js.map +2 -2
- package/dist/routes/config.d.ts +8 -11
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +17 -23
- package/dist/routes/config.js.map +2 -2
- package/dist/routes/db-routes.d.ts +6 -0
- package/dist/routes/db-routes.d.ts.map +1 -1
- package/dist/routes/db-routes.js.map +2 -2
- package/dist/routes/messages.d.ts +6 -2
- package/dist/routes/messages.d.ts.map +1 -1
- package/dist/routes/messages.js +17 -3
- package/dist/routes/messages.js.map +2 -2
- package/dist/routes/module-config-routes.d.ts +13 -9
- package/dist/routes/module-config-routes.d.ts.map +1 -1
- package/dist/routes/module-config-routes.js.map +2 -2
- package/dist/routes/modules.d.ts +6 -0
- package/dist/routes/modules.d.ts.map +1 -1
- package/dist/routes/modules.js.map +2 -2
- package/dist/routes/qq-bind.d.ts +24 -0
- package/dist/routes/qq-bind.d.ts.map +1 -0
- package/dist/routes/qq-bind.js +179 -0
- package/dist/routes/qq-bind.js.map +7 -0
- package/dist/routes/qq-events.d.ts +20 -0
- package/dist/routes/qq-events.d.ts.map +1 -0
- package/dist/routes/qq-events.js +39 -0
- package/dist/routes/qq-events.js.map +7 -0
- package/dist/routes/qq-join.d.ts +46 -0
- package/dist/routes/qq-join.d.ts.map +1 -0
- package/dist/routes/qq-join.js +277 -0
- package/dist/routes/qq-join.js.map +7 -0
- package/dist/routes/service-routes.d.ts +6 -0
- package/dist/routes/service-routes.d.ts.map +1 -1
- package/dist/routes/service-routes.js.map +2 -2
- package/dist/routes/status.d.ts +19 -0
- package/dist/routes/status.d.ts.map +1 -0
- package/dist/routes/status.js +74 -0
- package/dist/routes/status.js.map +7 -0
- package/dist/schema-registry.d.ts +16 -15
- package/dist/schema-registry.d.ts.map +1 -1
- package/dist/schema-registry.js +7 -1
- package/dist/schema-registry.js.map +2 -2
- package/dist/server.d.ts +19 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js.map +2 -2
- package/dist/service-registry.d.ts +39 -9
- package/dist/service-registry.d.ts.map +1 -1
- package/dist/service-registry.js +30 -2
- package/dist/service-registry.js.map +2 -2
- package/dist/services/builtin-handlers.d.ts +27 -7
- package/dist/services/builtin-handlers.d.ts.map +1 -1
- package/dist/services/builtin-handlers.js.map +2 -2
- package/dist/tx-runner.d.ts +29 -3
- package/dist/tx-runner.d.ts.map +1 -1
- package/dist/tx-runner.js +29 -3
- package/dist/tx-runner.js.map +2 -2
- package/package.json +17 -15
package/dist/domain/bridge.d.ts
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* domain/bridge.ts — MC → QQ
|
|
3
|
-
*
|
|
4
|
-
* db-server 收到 SAPI 上报的消息后,直接调 LLBot HTTP `/send_group_msg`
|
|
5
|
-
* 把消息转发到 QQ 群。不再走中间 qq-bridge 进程。
|
|
2
|
+
* domain/bridge.ts — MC → QQ 桥接(双后端)
|
|
6
3
|
*
|
|
7
4
|
* 数据流:
|
|
8
5
|
* SAPI ──POST──→ db-server:3001/api/sfmc/messages
|
|
9
|
-
* └─ 写库 + forwardToQQBridge()
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* - 无 DB 事务(本文件不操作 SQLite,只做 HTTP 出站转发)
|
|
6
|
+
* └─ 写库 + forwardToQQBridge()
|
|
7
|
+
* ├─ llbot → LLBot:3004/send_group_msg
|
|
8
|
+
* └─ official → OpenAPI /v2/groups/{openid}/messages
|
|
13
9
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* - forwardToQQBridge() 转发单条 MC 消息到 LLBot;失败仅 warn,不抛错
|
|
10
|
+
* 事件推送复用 sendGroupOutbound()(正文原样,不加聊天前缀)。
|
|
11
|
+
* 失败仅 warn,不抛错、不重试(与历史 LLBot 行为一致)。
|
|
17
12
|
*/
|
|
13
|
+
import { type QqOfficialCredentials } from "@sfmc-bds/sdk/node/qq-official";
|
|
14
|
+
import type { QQBackend } from "@sfmc-bds/sdk/node/config";
|
|
18
15
|
type LLBotConfig = {
|
|
19
16
|
host: string;
|
|
20
17
|
port: number;
|
|
@@ -22,27 +19,64 @@ type LLBotConfig = {
|
|
|
22
19
|
groupId: string;
|
|
23
20
|
prefix: string;
|
|
24
21
|
};
|
|
22
|
+
export type OfficialOutboundConfig = {
|
|
23
|
+
backend: "official";
|
|
24
|
+
creds: QqOfficialCredentials;
|
|
25
|
+
groupOpenid: string;
|
|
26
|
+
prefix: string;
|
|
27
|
+
};
|
|
28
|
+
export type LlbotOutboundConfig = {
|
|
29
|
+
backend: "llbot";
|
|
30
|
+
llbot: LLBotConfig;
|
|
31
|
+
};
|
|
32
|
+
export type OutboundConfig = OfficialOutboundConfig | LlbotOutboundConfig;
|
|
25
33
|
/**
|
|
26
|
-
* 构造
|
|
27
|
-
*
|
|
34
|
+
* 构造 LLBot 桥接配置对象。
|
|
35
|
+
*
|
|
36
|
+
* @param env 环境变量或配置字典。
|
|
37
|
+
* @returns 规范化的 LLBotConfig 配置。
|
|
28
38
|
*/
|
|
29
39
|
export declare function makeLLBotConfig(env: {
|
|
30
40
|
LLBOT_HOST: string;
|
|
31
41
|
LLBOT_PORT: number;
|
|
32
42
|
LLBOT_TOKEN: string;
|
|
33
43
|
QQ_GROUP_ID: string;
|
|
44
|
+
MCTOQQ_PREFIX?: string;
|
|
34
45
|
}): LLBotConfig;
|
|
35
46
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* @
|
|
39
|
-
* @
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
* 根据环境变量与配置组装出站配置(支持 official 官方开放平台与 llbot 双后端)。
|
|
48
|
+
*
|
|
49
|
+
* @param env 环境变量与配置字典。
|
|
50
|
+
* @returns 规范化的 OutboundConfig 出站配置。
|
|
51
|
+
*/
|
|
52
|
+
export declare function makeOutboundConfig(env: {
|
|
53
|
+
QQ_BACKEND: QQBackend;
|
|
54
|
+
LLBOT_HOST: string;
|
|
55
|
+
LLBOT_PORT: number;
|
|
56
|
+
LLBOT_TOKEN: string;
|
|
57
|
+
QQ_GROUP_ID: string;
|
|
58
|
+
QQ_APP_ID: string;
|
|
59
|
+
QQ_APP_SECRET: string;
|
|
60
|
+
QQ_SANDBOX: boolean;
|
|
61
|
+
QQ_GROUP_OPENID: string;
|
|
62
|
+
MCTOQQ_PREFIX: string;
|
|
63
|
+
}): OutboundConfig;
|
|
64
|
+
/**
|
|
65
|
+
* 将文本内容直接发送至目标 QQ 群(供服务器事件通知使用,不附加玩家聊天前缀)。
|
|
66
|
+
*
|
|
67
|
+
* @param config 出站配置对象。
|
|
68
|
+
* @param text 待发送的文本内容。
|
|
69
|
+
*/
|
|
70
|
+
export declare function sendGroupOutbound(config: OutboundConfig | LLBotConfig, text: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* 将游戏内玩家聊天消息附加前缀后转发至 QQ 群。
|
|
73
|
+
*
|
|
74
|
+
* @param config 出站配置对象。
|
|
75
|
+
* @param channelId 来源频道 ID。
|
|
76
|
+
* @param fromName 消息发送者玩家名称。
|
|
77
|
+
* @param content 聊天消息正文。
|
|
78
|
+
* @param fromId 发送者唯一标识(如 XUID)。
|
|
45
79
|
*/
|
|
46
|
-
export declare function forwardToQQBridge(config: LLBotConfig, channelId: string, fromName: string, content: string, fromId: string): void;
|
|
80
|
+
export declare function forwardToQQBridge(config: OutboundConfig | LLBotConfig, channelId: string, fromName: string, content: string, fromId: string): void;
|
|
47
81
|
export {};
|
|
48
82
|
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/domain/bridge.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/domain/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,qBAAqB,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,sBAAsB,GAAG,mBAAmB,CAAC;AAE1E;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,WAAW,CAQd;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE;IACtC,UAAU,EAAE,SAAS,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,cAAc,CAkBjB;AAoED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAW1F;AAwBD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,cAAc,GAAG,WAAW,EACpC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,IAAI,CAYN"}
|
package/dist/domain/bridge.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { request } from "node:http";
|
|
2
|
+
import {
|
|
3
|
+
sendGroupTextMessage
|
|
4
|
+
} from "@sfmc-bds/sdk/node/qq-official";
|
|
2
5
|
import { log } from "../lib/log.js";
|
|
3
6
|
function makeLLBotConfig(env) {
|
|
4
7
|
return {
|
|
@@ -6,15 +9,32 @@ function makeLLBotConfig(env) {
|
|
|
6
9
|
port: env.LLBOT_PORT,
|
|
7
10
|
token: env.LLBOT_TOKEN,
|
|
8
11
|
groupId: env.QQ_GROUP_ID,
|
|
9
|
-
prefix: "[MC]"
|
|
12
|
+
prefix: env.MCTOQQ_PREFIX ?? "[MC]"
|
|
10
13
|
};
|
|
11
14
|
}
|
|
12
|
-
function
|
|
15
|
+
function makeOutboundConfig(env) {
|
|
16
|
+
if (env.QQ_BACKEND === "llbot") {
|
|
17
|
+
return {
|
|
18
|
+
backend: "llbot",
|
|
19
|
+
llbot: makeLLBotConfig(env)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
backend: "official",
|
|
24
|
+
creds: {
|
|
25
|
+
appId: env.QQ_APP_ID,
|
|
26
|
+
appSecret: env.QQ_APP_SECRET,
|
|
27
|
+
sandbox: env.QQ_SANDBOX
|
|
28
|
+
},
|
|
29
|
+
groupOpenid: env.QQ_GROUP_OPENID,
|
|
30
|
+
prefix: env.MCTOQQ_PREFIX || "[MC]"
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function sendViaLlbot(config, text, logCtx) {
|
|
13
34
|
if (!config.groupId || config.groupId === "0") {
|
|
14
|
-
log.warn(`QQ \u7FA4\u672A\u914D\u7F6E (qq_group_id),\u8DF3\u8FC7 MC\u2192QQ
|
|
35
|
+
log.warn(`QQ \u7FA4\u672A\u914D\u7F6E (qq_group_id),\u8DF3\u8FC7 MC\u2192QQ (${logCtx})`);
|
|
15
36
|
return;
|
|
16
37
|
}
|
|
17
|
-
const text = `${config.prefix} ${fromName}: ${content}`;
|
|
18
38
|
const payload = JSON.stringify({
|
|
19
39
|
group_id: parseInt(config.groupId, 10),
|
|
20
40
|
message: [{ type: "text", data: { text } }]
|
|
@@ -40,7 +60,7 @@ function forwardToQQBridge(config, channelId, fromName, content, fromId) {
|
|
|
40
60
|
res.on("end", () => {
|
|
41
61
|
if (res.statusCode !== 200) {
|
|
42
62
|
log.warn(
|
|
43
|
-
`LLBot send_group_msg \u2192 ${res.statusCode}: ${String(body).slice(0, 200)} (
|
|
63
|
+
`LLBot send_group_msg \u2192 ${res.statusCode}: ${String(body).slice(0, 200)} (${logCtx})`
|
|
44
64
|
);
|
|
45
65
|
}
|
|
46
66
|
});
|
|
@@ -52,8 +72,59 @@ function forwardToQQBridge(config, channelId, fromName, content, fromId) {
|
|
|
52
72
|
req.write(payload);
|
|
53
73
|
req.end();
|
|
54
74
|
}
|
|
75
|
+
function sendViaOfficial(config, text, logCtx) {
|
|
76
|
+
if (!config.groupOpenid) {
|
|
77
|
+
log.warn(`\u5B98\u65B9\u7FA4 openid \u672A\u914D\u7F6E (qq_group_openid),\u8DF3\u8FC7 MC\u2192QQ (${logCtx})`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!config.creds.appId || !config.creds.appSecret) {
|
|
81
|
+
log.warn(`\u5B98\u65B9 AppID/Secret \u672A\u914D\u7F6E,\u8DF3\u8FC7 MC\u2192QQ (${logCtx})`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
void sendGroupTextMessage(config.creds, {
|
|
85
|
+
groupOpenid: config.groupOpenid,
|
|
86
|
+
content: text
|
|
87
|
+
}).then((result) => {
|
|
88
|
+
if (!result.ok) {
|
|
89
|
+
log.warn(`\u5B98\u65B9\u53D1\u7FA4\u5931\u8D25: ${result.error} (${logCtx}, status=${result.status})`);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function sendGroupOutbound(config, text) {
|
|
94
|
+
const logCtx = "outbound";
|
|
95
|
+
if (!("backend" in config)) {
|
|
96
|
+
sendViaLlbot(config, text, logCtx);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (config.backend === "llbot") {
|
|
100
|
+
sendViaLlbot(config.llbot, text, logCtx);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
sendViaOfficial(config, text, logCtx);
|
|
104
|
+
}
|
|
105
|
+
function forwardViaLlbot(config, channelId, fromName, content, fromId) {
|
|
106
|
+
const text = `${config.prefix} ${fromName}: ${content}`;
|
|
107
|
+
sendViaLlbot(config, text, `from=${fromId}, channel=${channelId}`);
|
|
108
|
+
}
|
|
109
|
+
function forwardViaOfficial(config, channelId, fromName, content, fromId) {
|
|
110
|
+
const text = `${config.prefix} ${fromName}: ${content}`;
|
|
111
|
+
sendViaOfficial(config, text, `from=${fromId}, channel=${channelId}`);
|
|
112
|
+
}
|
|
113
|
+
function forwardToQQBridge(config, channelId, fromName, content, fromId) {
|
|
114
|
+
if (!("backend" in config)) {
|
|
115
|
+
forwardViaLlbot(config, channelId, fromName, content, fromId);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (config.backend === "llbot") {
|
|
119
|
+
forwardViaLlbot(config.llbot, channelId, fromName, content, fromId);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
forwardViaOfficial(config, channelId, fromName, content, fromId);
|
|
123
|
+
}
|
|
55
124
|
export {
|
|
56
125
|
forwardToQQBridge,
|
|
57
|
-
makeLLBotConfig
|
|
126
|
+
makeLLBotConfig,
|
|
127
|
+
makeOutboundConfig,
|
|
128
|
+
sendGroupOutbound
|
|
58
129
|
};
|
|
59
130
|
//# sourceMappingURL=bridge.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/domain/bridge.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * domain/bridge.ts \u2014 MC \u2192 QQ \u6865\u63A5\
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * domain/bridge.ts \u2014 MC \u2192 QQ \u6865\u63A5\uFF08\u53CC\u540E\u7AEF\uFF09\n *\n * \u6570\u636E\u6D41:\n * SAPI \u2500\u2500POST\u2500\u2500\u2192 db-server:3001/api/sfmc/messages\n * \u2514\u2500 \u5199\u5E93 + forwardToQQBridge()\n * \u251C\u2500 llbot \u2192 LLBot:3004/send_group_msg\n * \u2514\u2500 official \u2192 OpenAPI /v2/groups/{openid}/messages\n *\n * \u4E8B\u4EF6\u63A8\u9001\u590D\u7528 sendGroupOutbound()\uFF08\u6B63\u6587\u539F\u6837\uFF0C\u4E0D\u52A0\u804A\u5929\u524D\u7F00\uFF09\u3002\n * \u5931\u8D25\u4EC5 warn\uFF0C\u4E0D\u629B\u9519\u3001\u4E0D\u91CD\u8BD5\uFF08\u4E0E\u5386\u53F2 LLBot \u884C\u4E3A\u4E00\u81F4\uFF09\u3002\n */\n\nimport { request } from \"node:http\";\nimport {\n sendGroupTextMessage,\n type QqOfficialCredentials,\n} from \"@sfmc-bds/sdk/node/qq-official\";\nimport type { QQBackend } from \"@sfmc-bds/sdk/node/config\";\n\nimport { log } from \"../lib/log.js\";\n\ntype LLBotConfig = {\n host: string;\n port: number;\n token: string;\n groupId: string;\n prefix: string;\n};\n\nexport type OfficialOutboundConfig = {\n backend: \"official\";\n creds: QqOfficialCredentials;\n groupOpenid: string;\n prefix: string;\n};\n\nexport type LlbotOutboundConfig = {\n backend: \"llbot\";\n llbot: LLBotConfig;\n};\n\nexport type OutboundConfig = OfficialOutboundConfig | LlbotOutboundConfig;\n\n/**\n * \u6784\u9020 LLBot \u6865\u63A5\u914D\u7F6E\u5BF9\u8C61\u3002\n *\n * @param env \u73AF\u5883\u53D8\u91CF\u6216\u914D\u7F6E\u5B57\u5178\u3002\n * @returns \u89C4\u8303\u5316\u7684 LLBotConfig \u914D\u7F6E\u3002\n */\nexport function makeLLBotConfig(env: {\n LLBOT_HOST: string;\n LLBOT_PORT: number;\n LLBOT_TOKEN: string;\n QQ_GROUP_ID: string;\n MCTOQQ_PREFIX?: string;\n}): LLBotConfig {\n return {\n host: env.LLBOT_HOST,\n port: env.LLBOT_PORT,\n token: env.LLBOT_TOKEN,\n groupId: env.QQ_GROUP_ID,\n prefix: env.MCTOQQ_PREFIX ?? \"[MC]\",\n };\n}\n\n/**\n * \u6839\u636E\u73AF\u5883\u53D8\u91CF\u4E0E\u914D\u7F6E\u7EC4\u88C5\u51FA\u7AD9\u914D\u7F6E\uFF08\u652F\u6301 official \u5B98\u65B9\u5F00\u653E\u5E73\u53F0\u4E0E llbot \u53CC\u540E\u7AEF\uFF09\u3002\n *\n * @param env \u73AF\u5883\u53D8\u91CF\u4E0E\u914D\u7F6E\u5B57\u5178\u3002\n * @returns \u89C4\u8303\u5316\u7684 OutboundConfig \u51FA\u7AD9\u914D\u7F6E\u3002\n */\nexport function makeOutboundConfig(env: {\n QQ_BACKEND: QQBackend;\n LLBOT_HOST: string;\n LLBOT_PORT: number;\n LLBOT_TOKEN: string;\n QQ_GROUP_ID: string;\n QQ_APP_ID: string;\n QQ_APP_SECRET: string;\n QQ_SANDBOX: boolean;\n QQ_GROUP_OPENID: string;\n MCTOQQ_PREFIX: string;\n}): OutboundConfig {\n\n if (env.QQ_BACKEND === \"llbot\") {\n return {\n backend: \"llbot\",\n llbot: makeLLBotConfig(env),\n };\n }\n return {\n backend: \"official\",\n creds: {\n appId: env.QQ_APP_ID,\n appSecret: env.QQ_APP_SECRET,\n sandbox: env.QQ_SANDBOX,\n },\n groupOpenid: env.QQ_GROUP_OPENID,\n prefix: env.MCTOQQ_PREFIX || \"[MC]\",\n };\n}\n\nfunction sendViaLlbot(config: LLBotConfig, text: string, logCtx: string): void {\n if (!config.groupId || config.groupId === \"0\") {\n log.warn(`QQ \u7FA4\u672A\u914D\u7F6E (qq_group_id),\u8DF3\u8FC7 MC\u2192QQ (${logCtx})`);\n return;\n }\n\n const payload = JSON.stringify({\n group_id: parseInt(config.groupId, 10),\n message: [{ type: \"text\", data: { text } }],\n });\n\n const headers: Record<string, string | number> = {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(payload),\n };\n if (config.token) {\n headers[\"Authorization\"] = `Bearer ${config.token}`;\n }\n\n const req = request(\n {\n hostname: config.host,\n port: config.port,\n path: \"/send_group_msg\",\n method: \"POST\",\n headers,\n },\n (res) => {\n let body = \"\";\n res.on(\"data\", (c) => (body += c));\n res.on(\"end\", () => {\n if (res.statusCode !== 200) {\n log.warn(\n `LLBot send_group_msg \u2192 ${res.statusCode}: ${String(body).slice(0, 200)} (${logCtx})`\n );\n }\n });\n }\n );\n req.on(\"error\", (err) => {\n log.warn(`LLBot \u4E0D\u53EF\u8FBE (${config.host}:${config.port}): ${err.message}`);\n });\n req.write(payload);\n req.end();\n}\n\nfunction sendViaOfficial(config: OfficialOutboundConfig, text: string, logCtx: string): void {\n if (!config.groupOpenid) {\n log.warn(`\u5B98\u65B9\u7FA4 openid \u672A\u914D\u7F6E (qq_group_openid),\u8DF3\u8FC7 MC\u2192QQ (${logCtx})`);\n return;\n }\n if (!config.creds.appId || !config.creds.appSecret) {\n log.warn(`\u5B98\u65B9 AppID/Secret \u672A\u914D\u7F6E,\u8DF3\u8FC7 MC\u2192QQ (${logCtx})`);\n return;\n }\n\n void sendGroupTextMessage(config.creds, {\n groupOpenid: config.groupOpenid,\n content: text,\n }).then((result) => {\n if (!result.ok) {\n log.warn(`\u5B98\u65B9\u53D1\u7FA4\u5931\u8D25: ${result.error} (${logCtx}, status=${result.status})`);\n }\n });\n}\n\n/**\n * \u5C06\u6587\u672C\u5185\u5BB9\u76F4\u63A5\u53D1\u9001\u81F3\u76EE\u6807 QQ \u7FA4\uFF08\u4F9B\u670D\u52A1\u5668\u4E8B\u4EF6\u901A\u77E5\u4F7F\u7528\uFF0C\u4E0D\u9644\u52A0\u73A9\u5BB6\u804A\u5929\u524D\u7F00\uFF09\u3002\n *\n * @param config \u51FA\u7AD9\u914D\u7F6E\u5BF9\u8C61\u3002\n * @param text \u5F85\u53D1\u9001\u7684\u6587\u672C\u5185\u5BB9\u3002\n */\nexport function sendGroupOutbound(config: OutboundConfig | LLBotConfig, text: string): void {\n const logCtx = \"outbound\";\n if (!(\"backend\" in config)) {\n sendViaLlbot(config, text, logCtx);\n return;\n }\n if (config.backend === \"llbot\") {\n sendViaLlbot(config.llbot, text, logCtx);\n return;\n }\n sendViaOfficial(config, text, logCtx);\n}\n\nfunction forwardViaLlbot(\n config: LLBotConfig,\n channelId: string,\n fromName: string,\n content: string,\n fromId: string\n): void {\n const text = `${config.prefix} ${fromName}: ${content}`;\n sendViaLlbot(config, text, `from=${fromId}, channel=${channelId}`);\n}\n\nfunction forwardViaOfficial(\n config: OfficialOutboundConfig,\n channelId: string,\n fromName: string,\n content: string,\n fromId: string\n): void {\n const text = `${config.prefix} ${fromName}: ${content}`;\n sendViaOfficial(config, text, `from=${fromId}, channel=${channelId}`);\n}\n\n/**\n * \u5C06\u6E38\u620F\u5185\u73A9\u5BB6\u804A\u5929\u6D88\u606F\u9644\u52A0\u524D\u7F00\u540E\u8F6C\u53D1\u81F3 QQ \u7FA4\u3002\n *\n * @param config \u51FA\u7AD9\u914D\u7F6E\u5BF9\u8C61\u3002\n * @param channelId \u6765\u6E90\u9891\u9053 ID\u3002\n * @param fromName \u6D88\u606F\u53D1\u9001\u8005\u73A9\u5BB6\u540D\u79F0\u3002\n * @param content \u804A\u5929\u6D88\u606F\u6B63\u6587\u3002\n * @param fromId \u53D1\u9001\u8005\u552F\u4E00\u6807\u8BC6\uFF08\u5982 XUID\uFF09\u3002\n */\nexport function forwardToQQBridge(\n config: OutboundConfig | LLBotConfig,\n channelId: string,\n fromName: string,\n content: string,\n fromId: string\n): void {\n\n // \u517C\u5BB9\u65E7\u8C03\u7528\uFF1A\u76F4\u63A5\u4F20 LLBotConfig\n if (!(\"backend\" in config)) {\n forwardViaLlbot(config, channelId, fromName, content, fromId);\n return;\n }\n if (config.backend === \"llbot\") {\n forwardViaLlbot(config.llbot, channelId, fromName, content, fromId);\n return;\n }\n forwardViaOfficial(config, channelId, fromName, content, fromId);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.test.d.ts","sourceRoot":"","sources":["../../src/domain/bridge.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { makeLLBotConfig, makeOutboundConfig, forwardToQQBridge } from "./bridge.js";
|
|
4
|
+
test("makeOutboundConfig\uFF1Aofficial / llbot \u5206\u652F", () => {
|
|
5
|
+
const official = makeOutboundConfig({
|
|
6
|
+
QQ_BACKEND: "official",
|
|
7
|
+
LLBOT_HOST: "127.0.0.1",
|
|
8
|
+
LLBOT_PORT: 3004,
|
|
9
|
+
LLBOT_TOKEN: "",
|
|
10
|
+
QQ_GROUP_ID: "123",
|
|
11
|
+
QQ_APP_ID: "app",
|
|
12
|
+
QQ_APP_SECRET: "sec",
|
|
13
|
+
QQ_SANDBOX: true,
|
|
14
|
+
QQ_GROUP_OPENID: "GOPEN",
|
|
15
|
+
MCTOQQ_PREFIX: "[MC]"
|
|
16
|
+
});
|
|
17
|
+
assert.equal(official.backend, "official");
|
|
18
|
+
if (official.backend === "official") {
|
|
19
|
+
assert.equal(official.groupOpenid, "GOPEN");
|
|
20
|
+
assert.equal(official.creds.sandbox, true);
|
|
21
|
+
assert.equal(official.prefix, "[MC]");
|
|
22
|
+
}
|
|
23
|
+
const llbot = makeOutboundConfig({
|
|
24
|
+
QQ_BACKEND: "llbot",
|
|
25
|
+
LLBOT_HOST: "127.0.0.1",
|
|
26
|
+
LLBOT_PORT: 3004,
|
|
27
|
+
LLBOT_TOKEN: "t",
|
|
28
|
+
QQ_GROUP_ID: "99",
|
|
29
|
+
QQ_APP_ID: "",
|
|
30
|
+
QQ_APP_SECRET: "",
|
|
31
|
+
QQ_SANDBOX: false,
|
|
32
|
+
QQ_GROUP_OPENID: "",
|
|
33
|
+
MCTOQQ_PREFIX: "[X]"
|
|
34
|
+
});
|
|
35
|
+
assert.equal(llbot.backend, "llbot");
|
|
36
|
+
if (llbot.backend === "llbot") {
|
|
37
|
+
assert.equal(llbot.llbot.groupId, "99");
|
|
38
|
+
assert.equal(llbot.llbot.prefix, "[X]");
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
test("makeLLBotConfig \u4F7F\u7528 mctoqq_prefix", () => {
|
|
42
|
+
const cfg = makeLLBotConfig({
|
|
43
|
+
LLBOT_HOST: "h",
|
|
44
|
+
LLBOT_PORT: 1,
|
|
45
|
+
LLBOT_TOKEN: "",
|
|
46
|
+
QQ_GROUP_ID: "1",
|
|
47
|
+
MCTOQQ_PREFIX: "[P]"
|
|
48
|
+
});
|
|
49
|
+
assert.equal(cfg.prefix, "[P]");
|
|
50
|
+
});
|
|
51
|
+
test("forwardToQQBridge official\uFF1A\u7F3A group_openid \u4E0D\u629B\u9519", () => {
|
|
52
|
+
assert.doesNotThrow(() => {
|
|
53
|
+
forwardToQQBridge(
|
|
54
|
+
{
|
|
55
|
+
backend: "official",
|
|
56
|
+
creds: { appId: "a", appSecret: "s" },
|
|
57
|
+
groupOpenid: "",
|
|
58
|
+
prefix: "[MC]"
|
|
59
|
+
},
|
|
60
|
+
"ch",
|
|
61
|
+
"Steve",
|
|
62
|
+
"hi",
|
|
63
|
+
"xuid"
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
test("forwardToQQBridge llbot\uFF1A\u7F3A\u7FA4\u53F7\u4E0D\u629B\u9519", () => {
|
|
68
|
+
assert.doesNotThrow(() => {
|
|
69
|
+
forwardToQQBridge(
|
|
70
|
+
{
|
|
71
|
+
backend: "llbot",
|
|
72
|
+
llbot: {
|
|
73
|
+
host: "127.0.0.1",
|
|
74
|
+
port: 3004,
|
|
75
|
+
token: "",
|
|
76
|
+
groupId: "0",
|
|
77
|
+
prefix: "[MC]"
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"ch",
|
|
81
|
+
"Steve",
|
|
82
|
+
"hi",
|
|
83
|
+
"xuid"
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=bridge.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/domain/bridge.test.ts"],
|
|
4
|
+
"sourcesContent": ["import assert from \"node:assert/strict\";\r\nimport test from \"node:test\";\r\nimport { makeLLBotConfig, makeOutboundConfig, forwardToQQBridge } from \"./bridge.js\";\r\n\r\ntest(\"makeOutboundConfig\uFF1Aofficial / llbot \u5206\u652F\", () => {\r\n const official = makeOutboundConfig({\r\n QQ_BACKEND: \"official\",\r\n LLBOT_HOST: \"127.0.0.1\",\r\n LLBOT_PORT: 3004,\r\n LLBOT_TOKEN: \"\",\r\n QQ_GROUP_ID: \"123\",\r\n QQ_APP_ID: \"app\",\r\n QQ_APP_SECRET: \"sec\",\r\n QQ_SANDBOX: true,\r\n QQ_GROUP_OPENID: \"GOPEN\",\r\n MCTOQQ_PREFIX: \"[MC]\",\r\n });\r\n assert.equal(official.backend, \"official\");\r\n if (official.backend === \"official\") {\r\n assert.equal(official.groupOpenid, \"GOPEN\");\r\n assert.equal(official.creds.sandbox, true);\r\n assert.equal(official.prefix, \"[MC]\");\r\n }\r\n\r\n const llbot = makeOutboundConfig({\r\n QQ_BACKEND: \"llbot\",\r\n LLBOT_HOST: \"127.0.0.1\",\r\n LLBOT_PORT: 3004,\r\n LLBOT_TOKEN: \"t\",\r\n QQ_GROUP_ID: \"99\",\r\n QQ_APP_ID: \"\",\r\n QQ_APP_SECRET: \"\",\r\n QQ_SANDBOX: false,\r\n QQ_GROUP_OPENID: \"\",\r\n MCTOQQ_PREFIX: \"[X]\",\r\n });\r\n assert.equal(llbot.backend, \"llbot\");\r\n if (llbot.backend === \"llbot\") {\r\n assert.equal(llbot.llbot.groupId, \"99\");\r\n assert.equal(llbot.llbot.prefix, \"[X]\");\r\n }\r\n});\r\n\r\ntest(\"makeLLBotConfig \u4F7F\u7528 mctoqq_prefix\", () => {\r\n const cfg = makeLLBotConfig({\r\n LLBOT_HOST: \"h\",\r\n LLBOT_PORT: 1,\r\n LLBOT_TOKEN: \"\",\r\n QQ_GROUP_ID: \"1\",\r\n MCTOQQ_PREFIX: \"[P]\",\r\n });\r\n assert.equal(cfg.prefix, \"[P]\");\r\n});\r\n\r\ntest(\"forwardToQQBridge official\uFF1A\u7F3A group_openid \u4E0D\u629B\u9519\", () => {\r\n assert.doesNotThrow(() => {\r\n forwardToQQBridge(\r\n {\r\n backend: \"official\",\r\n creds: { appId: \"a\", appSecret: \"s\" },\r\n groupOpenid: \"\",\r\n prefix: \"[MC]\",\r\n },\r\n \"ch\",\r\n \"Steve\",\r\n \"hi\",\r\n \"xuid\"\r\n );\r\n });\r\n});\r\n\r\ntest(\"forwardToQQBridge llbot\uFF1A\u7F3A\u7FA4\u53F7\u4E0D\u629B\u9519\", () => {\r\n assert.doesNotThrow(() => {\r\n forwardToQQBridge(\r\n {\r\n backend: \"llbot\",\r\n llbot: {\r\n host: \"127.0.0.1\",\r\n port: 3004,\r\n token: \"\",\r\n groupId: \"0\",\r\n prefix: \"[MC]\",\r\n },\r\n },\r\n \"ch\",\r\n \"Steve\",\r\n \"hi\",\r\n \"xuid\"\r\n );\r\n });\r\n});\r\n\r"],
|
|
5
|
+
"mappings": "AAAA,OAAO,YAAY;AACnB,OAAO,UAAU;AACjB,SAAS,iBAAiB,oBAAoB,yBAAyB;AAEvE,KAAK,yDAA0C,MAAM;AACnD,QAAM,WAAW,mBAAmB;AAAA,IAClC,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,aAAa;AAAA,IACb,WAAW;AAAA,IACX,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB,CAAC;AACD,SAAO,MAAM,SAAS,SAAS,UAAU;AACzC,MAAI,SAAS,YAAY,YAAY;AACnC,WAAO,MAAM,SAAS,aAAa,OAAO;AAC1C,WAAO,MAAM,SAAS,MAAM,SAAS,IAAI;AACzC,WAAO,MAAM,SAAS,QAAQ,MAAM;AAAA,EACtC;AAEA,QAAM,QAAQ,mBAAmB;AAAA,IAC/B,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,aAAa;AAAA,IACb,WAAW;AAAA,IACX,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB,CAAC;AACD,SAAO,MAAM,MAAM,SAAS,OAAO;AACnC,MAAI,MAAM,YAAY,SAAS;AAC7B,WAAO,MAAM,MAAM,MAAM,SAAS,IAAI;AACtC,WAAO,MAAM,MAAM,MAAM,QAAQ,KAAK;AAAA,EACxC;AACF,CAAC;AAED,KAAK,8CAAoC,MAAM;AAC7C,QAAM,MAAM,gBAAgB;AAAA,IAC1B,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,aAAa;AAAA,IACb,eAAe;AAAA,EACjB,CAAC;AACD,SAAO,MAAM,IAAI,QAAQ,KAAK;AAChC,CAAC;AAED,KAAK,0EAAiD,MAAM;AAC1D,SAAO,aAAa,MAAM;AACxB;AAAA,MACE;AAAA,QACE,SAAS;AAAA,QACT,OAAO,EAAE,OAAO,KAAK,WAAW,IAAI;AAAA,QACpC,aAAa;AAAA,QACb,QAAQ;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AACH,CAAC;AAED,KAAK,qEAAkC,MAAM;AAC3C,SAAO,aAAa,MAAM;AACxB;AAAA,MACE;AAAA,QACE,SAAS;AAAA,QACT,OAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM;AAAA,UACN,OAAO;AAAA,UACP,SAAS;AAAA,UACT,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AACH,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/domain/economy.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ export interface EconomyTransactionRow {
|
|
|
50
50
|
reason: string;
|
|
51
51
|
created_at: number;
|
|
52
52
|
idempotency_key: string;
|
|
53
|
-
/** JS
|
|
53
|
+
/** 兼容 JS 领域模型访问的驼峰别名字段。 */
|
|
54
54
|
actorId?: string;
|
|
55
55
|
type?: string;
|
|
56
56
|
referenceType?: string;
|
|
@@ -95,7 +95,7 @@ export interface EconomyTransactionRow {
|
|
|
95
95
|
reason: string;
|
|
96
96
|
created_at: number;
|
|
97
97
|
idempotency_key: string;
|
|
98
|
-
/** JS
|
|
98
|
+
/** 兼容 JS 领域模型访问的驼峰别名字段。 */
|
|
99
99
|
actorId?: string;
|
|
100
100
|
type?: string;
|
|
101
101
|
referenceType?: string;
|
|
@@ -159,12 +159,24 @@ export type ApplyEconomyResult = {
|
|
|
159
159
|
*/
|
|
160
160
|
export declare function applyEconomySteps(query: AnyQuery, data: ApplyEconomyInput): ApplyEconomyResult;
|
|
161
161
|
/**
|
|
162
|
-
*
|
|
162
|
+
* 独立经济事务包装。若指定 `alreadyInTx: true` 则复用外层事务(不再单独开启 BEGIN)。
|
|
163
|
+
*
|
|
164
|
+
* @param query 数据库查询执行函数。
|
|
165
|
+
* @param db 数据库连接实例。
|
|
166
|
+
* @param data 经济操作输入参数。
|
|
167
|
+
* @param opts 可选事务参数。
|
|
168
|
+
* @returns 经济变动结果。
|
|
163
169
|
*/
|
|
164
170
|
export declare function applyEconomyTransaction(query: AnyQuery, db: DatabaseSync, data: ApplyEconomyInput, opts?: {
|
|
165
171
|
alreadyInTx?: boolean;
|
|
166
172
|
}): ApplyEconomyResult;
|
|
167
|
-
/**
|
|
173
|
+
/**
|
|
174
|
+
* 列出日常任务列表(默认仅查询 active 状态且尚未过期的任务)。
|
|
175
|
+
*
|
|
176
|
+
* @param query 数据库查询执行函数。
|
|
177
|
+
* @param filter 过滤条件(可指定状态或是否包含已过期任务)。
|
|
178
|
+
* @returns 任务行记录数组。
|
|
179
|
+
*/
|
|
168
180
|
export declare function listDailyTasks(query: AnyQuery, filter?: {
|
|
169
181
|
status?: string;
|
|
170
182
|
includeExpired?: boolean;
|
|
@@ -174,14 +186,28 @@ export interface SubmitDailyTaskInput {
|
|
|
174
186
|
taskId: string;
|
|
175
187
|
quantity: number;
|
|
176
188
|
}
|
|
177
|
-
/**
|
|
189
|
+
/**
|
|
190
|
+
* 日常任务提交核心逻辑(无显式事务控制,供内部或外层事务调用)。
|
|
191
|
+
*
|
|
192
|
+
* @param query 数据库查询执行函数。
|
|
193
|
+
* @param data 任务提交数据(玩家 ID、任务 ID、提交数量)。
|
|
194
|
+
* @returns 提交结果(含奖励金额、更新后的余额及版本号)。
|
|
195
|
+
*/
|
|
178
196
|
export declare function submitDailyTaskSteps(query: AnyQuery, data: SubmitDailyTaskInput): TxResult<{
|
|
179
197
|
transactionId: string;
|
|
180
198
|
reward: number;
|
|
181
199
|
balance: number;
|
|
182
200
|
balanceVersion: number;
|
|
183
201
|
}>;
|
|
184
|
-
/**
|
|
202
|
+
/**
|
|
203
|
+
* 日常任务提交事务包装(可作为独立 IMMEDIATE 事务运行,或嵌入外层现有事务)。
|
|
204
|
+
*
|
|
205
|
+
* @param query 数据库查询执行函数。
|
|
206
|
+
* @param db 数据库连接实例。
|
|
207
|
+
* @param data 任务提交数据。
|
|
208
|
+
* @param opts 可选配置项。
|
|
209
|
+
* @returns 任务提交事务结果。
|
|
210
|
+
*/
|
|
185
211
|
export declare function submitDailyTaskTx(query: AnyQuery, db: DatabaseSync, data: SubmitDailyTaskInput, opts?: {
|
|
186
212
|
alreadyInTx?: boolean;
|
|
187
213
|
}): TxResult<{
|
|
@@ -190,7 +216,12 @@ export declare function submitDailyTaskTx(query: AnyQuery, db: DatabaseSync, dat
|
|
|
190
216
|
balance: number;
|
|
191
217
|
balanceVersion: number;
|
|
192
218
|
}>;
|
|
193
|
-
/**
|
|
219
|
+
/**
|
|
220
|
+
* 获取月度或全局经济统计指标白皮书(优先读取 `sfmc_economy_stats` 统计表,无缓存时现场聚合计算)。
|
|
221
|
+
*
|
|
222
|
+
* @param query 数据库查询执行函数。
|
|
223
|
+
* @returns 包含发行总量、销毁总量、现存总量与活跃账户数的统计快照。
|
|
224
|
+
*/
|
|
194
225
|
export declare function monthlyEconomyStats(query: AnyQuery): {
|
|
195
226
|
id: string;
|
|
196
227
|
total_issued: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"economy.d.ts","sourceRoot":"","sources":["../../src/domain/economy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,YAAY;AACZ,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,WAAW;AACX,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IAExB,
|
|
1
|
+
{"version":3,"file":"economy.d.ts","sourceRoot":"","sources":["../../src/domain/economy.ts"],"names":[],"mappings":"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"}
|