@sfmc-bds/qq-bridge 0.1.1-beta.3 → 0.2.0-beta.4
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 +14 -3
- package/dist/commands/db-api.js +89 -0
- package/dist/commands/db-api.js.map +7 -0
- package/dist/commands/handlers.js +660 -0
- package/dist/commands/handlers.js.map +7 -0
- package/dist/commands/index.js +55 -0
- package/dist/commands/index.js.map +7 -0
- package/dist/commands/interaction-router.js +149 -0
- package/dist/commands/interaction-router.js.map +7 -0
- package/dist/commands/join-settings-ui.js +108 -0
- package/dist/commands/join-settings-ui.js.map +7 -0
- package/dist/commands/join-settings-ui.test.js +43 -0
- package/dist/commands/join-settings-ui.test.js.map +7 -0
- package/dist/commands/menu-format.js +45 -0
- package/dist/commands/menu-format.js.map +7 -0
- package/dist/commands/menu-panel-sync.js +130 -0
- package/dist/commands/menu-panel-sync.js.map +7 -0
- package/dist/commands/menu-panel-sync.test.js +27 -0
- package/dist/commands/menu-panel-sync.test.js.map +7 -0
- package/dist/commands/pending.js +33 -0
- package/dist/commands/pending.js.map +7 -0
- package/dist/commands/registry.js +40 -0
- package/dist/commands/registry.js.map +7 -0
- package/dist/commands/render.js +46 -0
- package/dist/commands/render.js.map +7 -0
- package/dist/commands/render.test.js +44 -0
- package/dist/commands/render.test.js.map +7 -0
- package/dist/commands/reply-llbot.js +63 -0
- package/dist/commands/reply-llbot.js.map +7 -0
- package/dist/commands/reply-official.js +66 -0
- package/dist/commands/reply-official.js.map +7 -0
- package/dist/commands/router.js +53 -0
- package/dist/commands/router.js.map +7 -0
- package/dist/commands/router.test.js +92 -0
- package/dist/commands/router.test.js.map +7 -0
- package/dist/commands/types.js +1 -0
- package/dist/commands/types.js.map +7 -0
- package/dist/config.js +12 -2
- package/dist/config.js.map +2 -2
- package/dist/console.js +40 -20
- package/dist/console.js.map +2 -2
- package/dist/index.js +117 -20
- package/dist/index.js.map +2 -2
- package/dist/llbot-ws-api.js +90 -0
- package/dist/llbot-ws-api.js.map +7 -0
- package/dist/llbot-ws-api.test.js +32 -0
- package/dist/llbot-ws-api.test.js.map +7 -0
- package/dist/official/events.js +136 -0
- package/dist/official/events.js.map +7 -0
- package/dist/official/events.test.js +123 -0
- package/dist/official/events.test.js.map +7 -0
- package/dist/official/gateway.js +226 -0
- package/dist/official/gateway.js.map +7 -0
- package/dist/onebot.js +23 -5
- package/dist/onebot.js.map +2 -2
- package/dist/project-root.js +2 -2
- package/dist/project-root.js.map +2 -2
- package/dist/runtime-status.js +45 -0
- package/dist/runtime-status.js.map +7 -0
- package/dist/ws-server.js +4 -0
- package/dist/ws-server.js.map +2 -2
- package/package.json +6 -5
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/commands/handlers.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * commands/handlers.ts \u2014 \u5185\u7F6E menu / ping / whoami / status / online / bind / join / kick / group\n */\n\nimport {\n getGroupBotState,\n getGroupInfo,\n sendGroupMessage,\n} from \"@sfmc-bds/sdk/node/qq-official\";\nimport {\n fetchBindMe,\n fetchJoinPending,\n fetchJoinSettings,\n fetchSfmcStatus,\n postAdminKick,\n postBindRequest,\n postBindUnbind,\n postJoinDecide,\n postJoinRequest,\n postJoinSettings,\n type DbEndpoint,\n} from \"./db-api.js\";\nimport { buildJoinSettingsPanel, settingsFromResponse } from \"./join-settings-ui.js\";\nimport { formatCommandMenu } from \"./menu-format.js\";\nimport type { CommandRegistry } from \"./registry.js\";\nimport type { CommandContext, CommandHandler, CommandResult } from \"./types.js\";\n\nfunction formatUptime(startedAt: number): string {\n const ms = Math.max(0, Date.now() - startedAt);\n const s = Math.floor(ms / 1000);\n const m = Math.floor(s / 60);\n const h = Math.floor(m / 60);\n if (h > 0) return `${h}h ${m % 60}m`;\n if (m > 0) return `${m}m ${s % 60}s`;\n return `${s}s`;\n}\n\nfunction dbEp(ctx: CommandContext): DbEndpoint | null {\n const host = ctx.runtimeInfo.dbHost;\n const port = ctx.runtimeInfo.dbPort;\n if (!host || !port) return null;\n return { host, port };\n}\n\nfunction isAdmin(ctx: CommandContext): boolean {\n const admins = ctx.runtimeInfo.adminOpenids ?? [];\n if (admins.length > 0 && admins.includes(ctx.inbound.userId)) return true;\n // \u7FA4\u7BA1\uFF1A\u6865\u4FA7\u5148\u653E\u884C\uFF1Bdb \u518D\u6309 treat_group_admins_as_admins \u9274\u6743\n return ctx.inbound.isGroupAdmin === true;\n}\n\nfunction asGroupAdminField(ctx: CommandContext): boolean {\n return ctx.inbound.isGroupAdmin === true;\n}\n\n/** \u62C9\u53D6\u5B98\u65B9\u7FA4 info + bot_state\uFF1B\u5931\u8D25\u8FD4\u56DE\u63D0\u793A\u884C */\nasync function fetchQqGroupLines(ctx: CommandContext): Promise<string[]> {\n const creds = ctx.runtimeInfo.officialCreds;\n const gid = ctx.runtimeInfo.groupOpenid || ctx.inbound.groupId;\n if (!creds || !gid || ctx.inbound.backend !== \"official\") return [];\n const lines: string[] = [];\n try {\n const [infoRes, stateRes] = await Promise.all([\n getGroupInfo(creds, gid),\n getGroupBotState(creds, gid),\n ]);\n if (infoRes.ok && infoRes.json && typeof infoRes.json === \"object\") {\n const j = infoRes.json as Record<string, unknown>;\n lines.push(`QQ\u7FA4\uFF1A${j.group_name ?? \"\u2014\"} \u00B7 \u6210\u5458 ${j.group_member_num ?? \"\u2014\"}`);\n } else if (!infoRes.ok) {\n const hint = /11253/.test(infoRes.error || infoRes.body || \"\")\n ? \"\u7FA4\u4FE1\u606F\u63A5\u53E3\u672A\u5F00\u901A\u767D\u540D\u5355(11253)\"\n : `\u7FA4\u4FE1\u606F\u5931\u8D25\uFF1A${(infoRes.error || \"\").slice(0, 60)}`;\n lines.push(hint);\n }\n if (stateRes.ok && stateRes.json && typeof stateRes.json === \"object\") {\n const j = stateRes.json as Record<string, unknown>;\n lines.push(\n `\u673A\u5668\u4EBA\uFF1A\u89D2\u8272=${j.member_role ?? \"\u2014\"} \u00B7 \u4E3B\u52A8\u63A8\u9001=${j.allow_proactive_msg === true ? \"\u5F00\" : \"\u5173\"} \u00B7 \u6536\u6D88\u606F=${j.recv_msg_setting ?? \"\u2014\"}`\n );\n }\n } catch (e) {\n lines.push(`\u7FA4\u4FE1\u606F\u5F02\u5E38\uFF1A${(e as Error).message}`);\n }\n return lines;\n}\n\nexport function createMenuHandler(registry: CommandRegistry): CommandHandler {\n return (): CommandResult => {\n const cmds = registry.userMenu().filter((c) => c.name !== \"menu\");\n return formatCommandMenu({\n title: \"SFMC \u6307\u4EE4\",\n subtitle: \"\u70B9\u6309\u94AE\u6216\u53D1\u540D\u79F0/\u7F16\u53F7\uFF1B\u7BA1\u7406\u5458\u53D1\u300C\u7BA1\u7406\u300D\u6253\u5F00\u7BA1\u7406\u83DC\u5355\u3002\",\n cmds,\n idPrefix: \"cmd\",\n footerMd: \"_\u5B98\u65B9\u4EC5 @\u673A\u5668\u4EBA \u89E6\u53D1\uFF1B\u6E38\u620F\u804A\u5929\u9700\u914D\u7F6E `bridge_channel_id`\u3002_\",\n footerText: \"\u5B98\u65B9\u4EC5 @\u673A\u5668\u4EBA \u89E6\u53D1\uFF1B\u6E38\u620F\u804A\u5929\u9700\u914D\u7F6E bridge_channel_id\u3002\",\n });\n };\n}\n\n/** \u7BA1\u7406\u5B50\u83DC\u5355\uFF1A\u4EC5\u7BA1\u7406\u5458\uFF1B\u5217\u51FA adminMenu \u6307\u4EE4 */\nexport function createAdminMenuHandler(registry: CommandRegistry): CommandHandler {\n return (ctx: CommandContext): CommandResult => {\n if (!isAdmin(ctx)) {\n return { text: \"\u4EC5\u7BA1\u7406\u5458\u53EF\u6253\u5F00\u7BA1\u7406\u83DC\u5355\uFF08\u9700\u5728 qq_admin_openids\uFF0C\u6216\u5F00\u542F\u7FA4\u7BA1\u89C6\u4F5C\u7BA1\u7406\u5458\uFF09\" };\n }\n const cmds = registry.adminMenu();\n if (cmds.length === 0) {\n return { text: \"\u6682\u65E0\u7BA1\u7406\u6307\u4EE4\" };\n }\n return formatCommandMenu({\n title: \"SFMC \u7BA1\u7406\",\n subtitle: \"\u4EE5\u4E0B\u4E3A\u7BA1\u7406\u6307\u4EE4\uFF1B\u4E5F\u53EF\u76F4\u63A5\u53D1\u300C\u8E22\u4EBA\u300D\u300C\u5F85\u5BA1\u300D\u7B49\u89E6\u53D1\u8BCD\u3002\",\n cmds,\n idPrefix: \"adm\",\n footerMd: \"_\u654F\u611F\u64CD\u4F5C\u8BF7\u786E\u8BA4\u5BF9\u8C61\u6B63\u786E\u3002_\",\n footerText: \"\u654F\u611F\u64CD\u4F5C\u8BF7\u786E\u8BA4\u5BF9\u8C61\u6B63\u786E\u3002\",\n });\n };\n}\n\nexport const pingHandler: CommandHandler = (ctx: CommandContext): CommandResult => {\n const { runtimeInfo, startedAt, inbound } = ctx;\n const parts = [\"pong\", `backend=${inbound.backend}`, `uptime=${formatUptime(startedAt)}`];\n if (inbound.backend === \"official\") {\n parts.push(`sandbox=${runtimeInfo.sandbox ? \"true\" : \"false\"}`);\n if (runtimeInfo.appIdHint) parts.push(`app=${runtimeInfo.appIdHint}`);\n }\n return { text: parts.join(\" \u00B7 \") };\n};\n\nexport const whoamiHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n const { inbound } = ctx;\n const lines = [`\u4F60\u662F ${inbound.userName}`, `id=${inbound.userId}`, `group=${inbound.groupId}`];\n const ep = dbEp(ctx);\n if (ep) {\n try {\n const me = await fetchBindMe(ep, inbound.userId);\n if (me.bound && me.binding) {\n lines.push(`\u5DF2\u7ED1\u5B9A MC\uFF1A${me.binding.player_name || \"?\"} (${me.binding.player_xuid || \"?\"})`);\n } else {\n lines.push(\"\u672A\u7ED1\u5B9A MC\uFF08\u53D1\u9001\u300C\u7ED1\u5B9A\u300D\u83B7\u53D6\u9A8C\u8BC1\u7801\uFF09\");\n }\n } catch {\n lines.push(\"\u7ED1\u5B9A\u67E5\u8BE2\u5931\u8D25\uFF08db-server \u4E0D\u53EF\u8FBE\uFF09\");\n }\n }\n return { text: lines.join(\"\\n\") };\n};\n\nexport const statusHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n const ep = dbEp(ctx);\n if (!ep) return { text: \"status\uFF1A\u672A\u914D\u7F6E db_host/db_port\" };\n try {\n const st = await fetchSfmcStatus(ep);\n const n = Array.isArray(st.online) ? st.online.length : 0;\n const day = st.world?.day != null ? String(st.world.day) : \"\u2014\";\n const diff = st.world?.difficulty ? String(st.world.difficulty) : \"\u2014\";\n const age =\n typeof st.updatedAt === \"number\" ? `${Math.max(0, Math.floor((Date.now() - st.updatedAt) / 1000))}s\u524D` : \"\u2014\";\n const host = st.host;\n const bds = st.processes?.bds;\n const db = st.processes?.db;\n const hostUp = host?.uptimeText || \"\u2014\";\n const bdsLine =\n bds?.state === \"running\"\n ? `\u8FD0\u884C\u4E2D \u00B7 ${bds.uptimeText || \"\u2014\"}${bds.pid ? ` (PID ${bds.pid})` : \"\"}`\n : \"\u672A\u8FD0\u884C\";\n const mem =\n host?.memory != null\n ? `${host.memory.usedMb ?? \"\u2014\"}/${host.memory.totalMb ?? \"\u2014\"} MB (${host.memory.usedPercent ?? \"\u2014\"}%)`\n : \"\u2014\";\n const cpu =\n host?.cpu != null ? `${host.cpu.cores ?? \"\u2014\"} \u6838 \u00B7 ${host.cpu.model || \"\u2014\"}` : \"\u2014\";\n const machine = host\n ? `${host.hostname || \"\u2014\"} \u00B7 ${host.platform || \"\u2014\"}/${host.arch || \"\u2014\"} ${host.release || \"\"}`.trim()\n : \"\u2014\";\n const note = st.note ? `\\n${st.note}` : n === 0 ? \"\\n\u6682\u65E0\u5728\u7EBF\u73A9\u5BB6\u6570\u636E\" : \"\";\n const qqLines = await fetchQqGroupLines(ctx);\n const text = [\n \"\u670D\u52A1\u5668\u72B6\u6001\",\n `\u5728\u7EBF\uFF1A${n} \u4EBA`,\n `\u4E16\u754C\u65E5\uFF1A${day}`,\n `\u96BE\u5EA6\uFF1A${diff}`,\n `\u4E3B\u673A\uFF1A${machine}`,\n `\u4E3B\u673A\u8FD0\u884C\uFF1A${hostUp}`,\n `BDS\uFF1A${bdsLine}`,\n `\u5185\u5B58\uFF1A${mem}`,\n `CPU\uFF1A${cpu}`,\n `db-server\uFF1A${db?.uptimeText || \"\u2014\"}${db?.pid ? ` (PID ${db.pid})` : \"\"}`,\n ...qqLines,\n `\u6570\u636E\uFF1A${age}${note}`,\n ].join(\"\\n\");\n const markdown = [\n \"## \u670D\u52A1\u5668\u72B6\u6001\",\n \"\",\n `- **\u5728\u7EBF**\uFF1A${n} \u4EBA`,\n `- **\u4E16\u754C\u65E5**\uFF1A${day}`,\n `- **\u96BE\u5EA6**\uFF1A${diff}`,\n `- **\u4E3B\u673A**\uFF1A${machine}`,\n `- **\u4E3B\u673A\u8FD0\u884C**\uFF1A${hostUp}`,\n `- **BDS**\uFF1A${bdsLine}`,\n `- **\u5185\u5B58**\uFF1A${mem}`,\n `- **CPU**\uFF1A${cpu}`,\n `- **db-server**\uFF1A${db?.uptimeText || \"\u2014\"}${db?.pid ? ` (PID ${db.pid})` : \"\"}`,\n ...qqLines.map((l) => `- ${l}`),\n `- **\u6570\u636E**\uFF1A${age}`,\n note ? `\\n_${(st.note || \"\u6682\u65E0\u5728\u7EBF\u73A9\u5BB6\u6570\u636E\").trim()}_` : \"\",\n ]\n .filter((line) => line !== \"\")\n .join(\"\\n\");\n return { text, markdown };\n } catch (e) {\n return { text: `status \u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\nconst ONLINE_CAP = 30;\n\nexport const onlineHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n const ep = dbEp(ctx);\n if (!ep) return { text: \"online\uFF1A\u672A\u914D\u7F6E db_host/db_port\" };\n try {\n const st = await fetchSfmcStatus(ep);\n const list = Array.isArray(st.online) ? st.online : [];\n if (list.length === 0) {\n return { text: st.note || \"\u6682\u65E0\u5728\u7EBF\u73A9\u5BB6\" };\n }\n const shown = list.slice(0, ONLINE_CAP);\n const names = shown.map((p, i) => `${i + 1}. ${p.name || p.id || \"?\"}`).join(\"\\n\");\n const more = list.length > ONLINE_CAP ? `\\n\u2026\u53E6\u6709 ${list.length - ONLINE_CAP} \u4EBA\u672A\u5217\u51FA` : \"\";\n return { text: `\u5728\u7EBF ${list.length} \u4EBA\\n${names}${more}` };\n } catch (e) {\n return { text: `online \u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\nexport const bindHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n const ep = dbEp(ctx);\n if (!ep) return { text: \"\u7ED1\u5B9A\uFF1A\u672A\u914D\u7F6E db_host/db_port\" };\n try {\n const { status, data } = await postBindRequest(ep, {\n openid: ctx.inbound.userId,\n qq_backend: ctx.inbound.backend,\n });\n if (status === 409 || data.error === \"already_bound\") {\n return {\n text: `\u4F60\u5DF2\u7ED1\u5B9A MC \u73A9\u5BB6\u300C${data.player_name || \"?\"}\u300D\u3002\u5982\u9700\u6362\u7ED1\u8BF7\u5148\u53D1\u9001\u300C\u89E3\u7ED1\u300D\u3002`,\n };\n }\n if (!data.success || !data.code) {\n return { text: `\u7533\u8BF7\u7ED1\u5B9A\u5931\u8D25\uFF1A${data.error || `HTTP ${status}`}` };\n }\n return {\n text: `\u7ED1\u5B9A\u7801\uFF1A${data.code}\\n\u8BF7\u5728\u6E38\u620F\u5185\u8F93\u5165 !bind\uFF0C\u7136\u540E\u5728 60 \u79D2\u5185\u53D1\u9001\u6B64\u6570\u5B57\u7801\uFF08\u4E0D\u8981\u5E26 !\uFF09\u3002`,\n markdown: `## \u7ED1\u5B9A\u7801 \\`${data.code}\\`\\n\\n1. \u6E38\u620F\u5185\u6267\u884C **!bind**\\n2. \u5728 **60 \u79D2\u5185**\u53D1\u9001\u672C\u6570\u5B57\u7801\uFF08\u4E0D\u8981\u5E26 \\`!\\`\uFF09\\n\\n_\u8D85\u65F6\u8BF7\u91CD\u65B0\u7533\u8BF7_`,\n };\n } catch (e) {\n return { text: `\u7ED1\u5B9A\u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\nexport const unbindHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n const ep = dbEp(ctx);\n if (!ep) return { text: \"\u89E3\u7ED1\uFF1A\u672A\u914D\u7F6E db_host/db_port\" };\n try {\n const { data } = await postBindUnbind(ep, { openid: ctx.inbound.userId });\n if (data.unbound) return { text: \"\u5DF2\u89E3\u9664 QQ\u2194MC \u7ED1\u5B9A\u3002\" };\n return { text: \"\u5F53\u524D\u6CA1\u6709\u7ED1\u5B9A\u8BB0\u5F55\u3002\" };\n } catch (e) {\n return { text: `\u89E3\u7ED1\u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\nexport const groupInfoHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n const lines = await fetchQqGroupLines(ctx);\n if (lines.length === 0) {\n return { text: \"\u7FA4\u4FE1\u606F\u4EC5\u5B98\u65B9\u540E\u7AEF\u53EF\u7528\uFF0C\u4E14\u9700\u914D\u7F6E qq_group_openid / \u51ED\u8BC1\u3002\" };\n }\n return { text: [\"QQ \u7FA4\u4FE1\u606F\", ...lines].join(\"\\n\") };\n};\n\nexport const joinHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n const ep = dbEp(ctx);\n if (!ep) return { text: \"\u7533\u8BF7\u5165\u670D\uFF1A\u672A\u914D\u7F6E db_host/db_port\" };\n let playerName = ctx.inbound.text.replace(/^\\/?(\u7533\u8BF7\u5165\u670D|join)\\s*/i, \"\").trim();\n if (!playerName) {\n try {\n const me = await fetchBindMe(ep, ctx.inbound.userId);\n if (me.bound && me.binding?.player_name) playerName = String(me.binding.player_name);\n } catch {\n /* ignore */\n }\n }\n if (!playerName) {\n return { text: \"\u7528\u6CD5\uFF1A\u7533\u8BF7\u5165\u670D <\u73A9\u5BB6\u540D>\\n\uFF08\u5DF2\u7ED1\u5B9A\u53EF\u7701\u7565\u540D\u5B57\uFF09\" };\n }\n try {\n const { data } = await postJoinRequest(ep, {\n openid: ctx.inbound.userId,\n player_name: playerName,\n qq_backend: ctx.inbound.backend,\n });\n if (!data.success || !data.id) {\n if (data.error === \"join_allowlist_disabled\") {\n return { text: \"\u5165\u670D\u767D\u540D\u5355\u5DF2\u5173\u95ED\uFF08\u7BA1\u7406\u5458\u53EF\u53D1\u300C\u914D\u7F6E \u767D\u540D\u5355 \u5F00\u300D\uFF09\" };\n }\n return { text: `\u7533\u8BF7\u5931\u8D25\uFF1A${data.error || \"unknown\"}` };\n }\n if (data.auto_approved || data.status === \"approved\") {\n return {\n text: data.note\n ? `\u300C${playerName}\u300D${data.note}`\n : `\u5DF2\u81EA\u52A8\u901A\u8FC7\u300C${playerName}\u300D\u5165\u670D\uFF0C\u7B49\u5F85 BDS \u5199\u5165\u767D\u540D\u5355`,\n };\n }\n const admins = ctx.runtimeInfo.adminOpenids ?? [];\n const creds = ctx.runtimeInfo.officialCreds;\n const gid = ctx.runtimeInfo.groupOpenid || ctx.inbound.groupId;\n if (creds && gid && admins.length > 0 && ctx.inbound.backend === \"official\") {\n void sendGroupMessage(creds, {\n groupOpenid: gid,\n msgType: 2,\n markdown: `## \u5165\u670D\u7533\u8BF7\\n\\n\u73A9\u5BB6 **${playerName}**\\n\u7533\u8BF7\u4EBA \\`${ctx.inbound.userId.slice(0, 8)}\u2026\\`\\n\u8BF7\u6C42 id=\\`${data.id}\\``,\n keyboardButtons: [\n {\n id: `ap_${data.id}`,\n label: \"\u901A\u8FC7\",\n data: `join:approve:${data.id}`,\n actionType: 1,\n style: 1,\n permission: { type: 0, specify_user_ids: admins },\n },\n {\n id: `rj_${data.id}`,\n label: \"\u62D2\u7EDD\",\n data: `join:reject:${data.id}`,\n actionType: 1,\n style: 0,\n permission: { type: 0, specify_user_ids: admins },\n },\n ],\n }).catch(() => undefined);\n }\n const note = data.note ? `\\n${data.note}` : admins.length === 0 ? \"\\n\u672A\u914D\u7F6E qq_admin_openids\uFF0C\u7BA1\u7406\u5458\u6536\u4E0D\u5230\u901A\u77E5\" : \"\";\n return {\n text: `\u5DF2\u63D0\u4EA4\u5165\u670D\u7533\u8BF7\u300C${playerName}\u300D${note}`,\n buttons:\n ctx.inbound.backend === \"llbot\" && admins.length > 0\n ? [\n { id: \"a\", label: `\u901A\u8FC7 ${playerName}`, command: `/approve ${data.id}` },\n { id: \"r\", label: `\u62D2\u7EDD ${playerName}`, command: `/reject ${data.id}` },\n ]\n : undefined,\n };\n } catch (e) {\n return { text: `\u7533\u8BF7\u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\nfunction parseOnOff(raw: string): boolean | null {\n const s = raw.trim().toLowerCase();\n if ([\"\u5F00\", \"\u5F00\u542F\", \"on\", \"true\", \"1\", \"yes\"].includes(s)) return true;\n if ([\"\u5173\", \"\u5173\u95ED\", \"off\", \"false\", \"0\", \"no\"].includes(s)) return false;\n return null;\n}\n\n/** \u7BA1\u7406\u5458\u67E5\u770B/\u5207\u6362 qq-link \u5165\u670D\u5F00\u5173\uFF08\u4E92\u52A8\u6309\u94AE\u9762\u677F\uFF09 */\nexport const joinConfigHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n if (!isAdmin(ctx)) return { text: \"\u4EC5\u7BA1\u7406\u5458\u53EF\u914D\u7F6E\u5165\u670D\u5F00\u5173\uFF08qq_admin_openids / \u7FA4\u7BA1\u89C6\u4F5C\u7BA1\u7406\u5458\uFF09\" };\n const ep = dbEp(ctx);\n if (!ep) return { text: \"\u914D\u7F6E\uFF1A\u672A\u8FDE\u63A5 db\" };\n\n const admins = ctx.runtimeInfo.adminOpenids ?? [];\n const rest = ctx.inbound.text.replace(/^\\/?(\u914D\u7F6E|config|\u5165\u670D\u914D\u7F6E)\\s*/i, \"\").trim();\n if (!rest) {\n try {\n const data = await fetchJoinSettings(ep);\n if (data.success === false) return { text: `\u8BFB\u53D6\u5931\u8D25\uFF1A${data.error || \"unknown\"}` };\n return buildJoinSettingsPanel({\n settings: settingsFromResponse(data),\n backend: ctx.inbound.backend,\n adminOpenids: admins,\n });\n } catch (e) {\n return { text: `\u8BFB\u53D6\u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n }\n\n if (/^(\u7FA4\u7BA1|\u7FA4\u7BA1\u7406\u5458|treat|group.?admin)/i.test(rest)) {\n return {\n text: \"\u300C\u7FA4\u7BA1\u89C6\u4F5C\u7BA1\u7406\u5458\u300D\u53EA\u80FD\u6539 configs/qq_link.json \u7684 treat_group_admins_as_admins\uFF0C\u7FA4\u804A\u4E0D\u53EF\u6539\u3002\u53D1\u300C\u914D\u7F6E\u300D\u53EF\u67E5\u770B\u5F53\u524D\u503C\u3002\",\n };\n }\n\n const m = /^(\u767D\u540D\u5355|allowlist|\u5BA1\u6279|approval)\\s+(\\S+)/i.exec(rest);\n if (!m) {\n return { text: \"\u7528\u6CD5\uFF1A\u914D\u7F6E\\n\u3000\u3000\u3000\u6216\u70B9\u9762\u677F\u6309\u94AE\u5207\u6362\u767D\u540D\u5355/\u5BA1\u6279\" };\n }\n const which = m[1]!.toLowerCase();\n const onOff = parseOnOff(m[2]!);\n if (onOff === null) return { text: \"\u8BF7\u4F7F\u7528 \u5F00/\u5173\uFF08\u6216 on/off\uFF09\" };\n\n const body: {\n openid: string;\n as_group_admin?: boolean;\n allowlist_enabled?: boolean;\n require_approval?: boolean;\n } = {\n openid: ctx.inbound.userId,\n as_group_admin: asGroupAdminField(ctx),\n };\n if (which === \"\u767D\u540D\u5355\" || which === \"allowlist\") body.allowlist_enabled = onOff;\n else body.require_approval = onOff;\n\n try {\n const { data } = await postJoinSettings(ep, body);\n if (data.success === false) {\n if (data.error === \"not_admin\") {\n return { text: \"\u65E0\u6743\u9650\uFF08\u7FA4\u7BA1\u9700 configs/qq_link.json \u4E2D treat_group_admins_as_admins=true\uFF09\" };\n }\n if (data.error === \"immutable_field\") {\n return { text: data.note || \"\u8BE5\u5B57\u6BB5\u4E0D\u53EF\u7ECF\u7FA4\u804A\u4FEE\u6539\" };\n }\n return { text: `\u4FDD\u5B58\u5931\u8D25\uFF1A${data.error || \"unknown\"}` };\n }\n return buildJoinSettingsPanel({\n settings: settingsFromResponse(data),\n backend: ctx.inbound.backend,\n adminOpenids: admins,\n prefix: \"\u5DF2\u4FDD\u5B58\",\n });\n } catch (e) {\n return { text: `\u4FDD\u5B58\u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\nexport const pendingHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n if (!isAdmin(ctx)) return { text: \"\u4EC5\u7BA1\u7406\u5458\u53EF\u67E5\u770B\u5F85\u5BA1\u5217\u8868\uFF08\u914D\u7F6E qq_admin_openids\uFF09\" };\n const ep = dbEp(ctx);\n if (!ep) return { text: \"\u5F85\u5BA1\uFF1A\u672A\u914D\u7F6E db\" };\n try {\n const data = await fetchJoinPending(ep, ctx.inbound.userId, asGroupAdminField(ctx));\n if (data.error) {\n if (data.error === \"not_admin\") {\n return { text: \"\u65E0\u6743\u9650\uFF08\u7FA4\u7BA1\u9700 treat_group_admins_as_admins=true\uFF09\" };\n }\n return { text: `\u5F85\u5BA1\u5931\u8D25\uFF1A${data.error}` };\n }\n const list = data.pending ?? [];\n if (list.length === 0) return { text: \"\u6682\u65E0\u5F85\u5BA1\u5165\u670D\u7533\u8BF7\" };\n const lines = list.map((r, i) => `${i + 1}. ${r.player_name || \"?\"} (${r.id})`);\n return { text: `\u5F85\u5BA1 ${list.length} \u6761\\n${lines.join(\"\\n\")}` };\n } catch (e) {\n return { text: `\u5F85\u5BA1\u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\nexport const approveHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n if (!isAdmin(ctx)) return { text: \"\u4EC5\u7BA1\u7406\u5458\u53EF\u5BA1\u6279\" };\n const ep = dbEp(ctx);\n if (!ep) return { text: \"\u672A\u914D\u7F6E db\" };\n const id = ctx.inbound.text.replace(/^\\/?(approve|\u901A\u8FC7)\\s*/i, \"\").trim();\n if (!id) return { text: \"\u7528\u6CD5\uFF1A\u901A\u8FC7 <\u7533\u8BF7id>\" };\n try {\n const { data } = await postJoinDecide(ep, {\n id,\n decision: \"approve\",\n decided_by: ctx.inbound.userId,\n as_group_admin: asGroupAdminField(ctx),\n });\n if (data.success === false && data.error === \"not_admin\") {\n return { text: \"\u65E0\u6743\u9650\uFF08\u7FA4\u7BA1\u9700 treat_group_admins_as_admins=true\uFF09\" };\n }\n return { text: data.success === false ? `\u5931\u8D25\uFF1A${data.error}` : `\u5DF2\u901A\u8FC7\u300C${data.player_name || id}\u300D` };\n } catch (e) {\n return { text: `\u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\nexport const rejectHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n if (!isAdmin(ctx)) return { text: \"\u4EC5\u7BA1\u7406\u5458\u53EF\u5BA1\u6279\" };\n const ep = dbEp(ctx);\n if (!ep) return { text: \"\u672A\u914D\u7F6E db\" };\n const id = ctx.inbound.text.replace(/^\\/?(reject|\u62D2\u7EDD)\\s*/i, \"\").trim();\n if (!id) return { text: \"\u7528\u6CD5\uFF1A\u62D2\u7EDD <\u7533\u8BF7id>\" };\n try {\n const { data } = await postJoinDecide(ep, {\n id,\n decision: \"reject\",\n decided_by: ctx.inbound.userId,\n as_group_admin: asGroupAdminField(ctx),\n });\n if (data.success === false && data.error === \"not_admin\") {\n return { text: \"\u65E0\u6743\u9650\uFF08\u7FA4\u7BA1\u9700 treat_group_admins_as_admins=true\uFF09\" };\n }\n return { text: data.success === false ? `\u5931\u8D25\uFF1A${data.error}` : `\u5DF2\u62D2\u7EDD\u300C${data.player_name || id}\u300D` };\n } catch (e) {\n return { text: `\u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\n/** \u9891\u9053 + \u8F7B\u91CF\u81EA\u68C0\uFF08\u4EBA\u4EBA\u53EF\u7528\uFF09 */\nexport const channelHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n const id = String(ctx.runtimeInfo.bridgeChannelId ?? \"\").trim();\n const lines: string[] = [\n \"\u3010\u804A\u5929\u4E92\u901A\u3011\",\n id ? `\u9891\u9053\uFF1A${id}` : \"\u9891\u9053\uFF1A\u672A\u914D\u7F6E\uFF08\u8BF7\u8BBE qq_config.json \u2192 bridge_channel_id \u5E76\u91CD\u542F db/qq/BDS\uFF09\",\n `\u540E\u7AEF\uFF1A${ctx.inbound.backend}${ctx.runtimeInfo.sandbox ? \" \u00B7 sandbox\" : \"\"}`,\n ];\n const ep = dbEp(ctx);\n if (!ep) {\n lines.push(\"db\uFF1A\u672A\u914D\u7F6E db_host/db_port\");\n } else {\n try {\n const st = await fetchSfmcStatus(ep);\n const bds = st.processes?.bds;\n const db = st.processes?.db;\n lines.push(`db-server\uFF1A${db?.state === \"stopped\" || db?.running === false ? \"\u672A\u8FD0\u884C\" : db?.uptimeText || \"\u53EF\u8FBE\"}${db?.pid ? ` (PID ${db.pid})` : \"\"}`);\n lines.push(\n `BDS\uFF1A${bds?.state === \"running\" || bds?.running === true ? `\u8FD0\u884C\u4E2D \u00B7 ${bds.uptimeText || \"\u2014\"}` : \"\u672A\u8FD0\u884C\"}`\n );\n } catch (e) {\n lines.push(`db\uFF1A\u4E0D\u53EF\u8FBE\uFF08${(e as Error).message}\uFF09`);\n }\n }\n lines.push(\"\u63D0\u793A\uFF1A\u5B98\u65B9\u4EC5 @\u673A\u5668\u4EBA \u7684\u975E\u6307\u4EE4\u6D88\u606F\u8FDB\u6E38\u620F\uFF1B\u6E38\u620F\u804A\u5929\u63A8\u7FA4\u8D70 MC\u2192QQ\u3002\");\n const text = lines.join(\"\\n\");\n return {\n text,\n markdown: text\n .split(\"\\n\")\n .map((l, i) => (i === 0 ? `## ${l.replace(/\u3010|\u3011/g, \"\")}` : `- ${l}`))\n .join(\"\\n\"),\n };\n};\n\n/** \u7BA1\u7406\u4FA7\u66F4\u5B8C\u6574\u7684\u81EA\u68C0 */\nexport const doctorHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n if (!isAdmin(ctx)) return { text: \"\u4EC5\u7BA1\u7406\u5458\u53EF\u6267\u884C\u81EA\u68C0\" };\n const base = await channelHandler(ctx);\n const extra: string[] = [\"\", \"\u3010\u7BA1\u7406\u81EA\u68C0\u3011\"];\n const admins = ctx.runtimeInfo.adminOpenids ?? [];\n extra.push(`\u7BA1\u7406\u5458 openid \u6570\uFF1A${admins.length}${admins.length === 0 ? \"\uFF08\u7A7A\u5219\u65E0\u6CD5\u5BA1\u6279/\u8E22\u4EBA\uFF09\" : \"\"}`);\n extra.push(`\u7FA4 openid\uFF1A${ctx.runtimeInfo.groupOpenid ? \"\u5DF2\u914D\u7F6E\" : \"\u672A\u914D\u7F6E\"}`);\n if (ctx.inbound.backend === \"official\") {\n extra.push(`\u51ED\u8BC1\uFF1A${ctx.runtimeInfo.officialCreds ? \"\u5DF2\u6CE8\u5165\" : \"\u7F3A\u5931\"}`);\n }\n const text = `${base.text}\\n${extra.join(\"\\n\")}`;\n return { text, markdown: `${base.markdown ?? base.text}\\n\\n### \u7BA1\u7406\u81EA\u68C0\\n\\n${extra.filter(Boolean).map((l) => `- ${l}`).join(\"\\n\")}` };\n};\n\nexport const kickHandler: CommandHandler = async (ctx: CommandContext): Promise<CommandResult> => {\n if (!isAdmin(ctx)) return { text: \"\u4EC5\u7BA1\u7406\u5458\u53EF\u8E22\u4EBA\uFF08\u914D\u7F6E qq_admin_openids\uFF09\" };\n const ep = dbEp(ctx);\n if (!ep) return { text: \"\u8E22\u4EBA\uFF1A\u672A\u914D\u7F6E db\" };\n const target = ctx.inbound.text.replace(/^\\/?(\u8E22\u4EBA|kick)\\s*/i, \"\").trim();\n if (!target) return { text: \"\u7528\u6CD5\uFF1A\u8E22\u4EBA <\u73A9\u5BB6\u540D>\" };\n try {\n const { data } = await postAdminKick(ep, {\n openid: ctx.inbound.userId,\n target_name: target,\n reason: \"QQ \u7BA1\u7406\u5458\u8E22\u51FA\",\n as_group_admin: asGroupAdminField(ctx),\n });\n if (!data.success) {\n if (data.error === \"not_admin\") {\n return { text: \"\u65E0\u6743\u9650\uFF08\u7FA4\u7BA1\u9700 treat_group_admins_as_admins=true\uFF09\" };\n }\n return { text: `\u8E22\u4EBA\u5165\u961F\u5931\u8D25\uFF1A${data.error || \"unknown\"}` };\n }\n return { text: `\u5DF2\u5C06\u300C${target}\u300D\u8E22\u4EBA\u8BF7\u6C42\u5165\u961F\uFF0C\u7B49\u5F85 BDS \u6267\u884C\u3002` };\n } catch (e) {\n return { text: `\u8E22\u4EBA\u5931\u8D25\uFF1A${(e as Error).message}` };\n }\n};\n\n/** \u6CE8\u518C\u5185\u7F6E\u6307\u4EE4\uFF08\u542B\u8FD0\u7EF4\u4E0E\u7ED1\u5B9A / \u5165\u670D\uFF09 */\nexport function registerBuiltinCommands(registry: CommandRegistry): void {\n registry.register({\n name: \"menu\",\n aliases: [\"\u83DC\u5355\", \"help\", \"\u5E2E\u52A9\", \"/help\", \"/\u83DC\u5355\", \"/menu\"],\n description: \"\u663E\u793A\u6307\u4EE4\u83DC\u5355\",\n handler: createMenuHandler(registry),\n });\n registry.register({\n name: \"ping\",\n aliases: [\"/ping\"],\n description: \"\u8FDE\u901A\u6027\u63A2\u6D4B\",\n handler: pingHandler,\n });\n registry.register({\n name: \"whoami\",\n aliases: [\"/whoami\", \"\u6211\u7684\u7ED1\u5B9A\"],\n description: \"\u67E5\u770B QQ id \u4E0E MC \u7ED1\u5B9A\",\n handler: whoamiHandler,\n });\n registry.register({\n name: \"status\",\n aliases: [\"\u72B6\u6001\", \"/status\", \"/\u72B6\u6001\"],\n description: \"\u670D\u52A1\u5668\u72B6\u6001\u6458\u8981\",\n handler: statusHandler,\n });\n registry.register({\n name: \"online\",\n aliases: [\"\u5728\u7EBF\", \"/online\", \"/\u5728\u7EBF\"],\n description: \"\u5728\u7EBF\u73A9\u5BB6\u540D\u5355\",\n handler: onlineHandler,\n });\n registry.register({\n name: \"bind\",\n aliases: [\"\u7ED1\u5B9A\", \"/bind\", \"/\u7ED1\u5B9A\"],\n description: \"\u7533\u8BF7 QQ\u2194MC \u7ED1\u5B9A\u7801\",\n handler: bindHandler,\n });\n registry.register({\n name: \"unbind\",\n aliases: [\"\u89E3\u7ED1\", \"/unbind\", \"/\u89E3\u7ED1\"],\n description: \"\u89E3\u9664 QQ\u2194MC \u7ED1\u5B9A\",\n handler: unbindHandler,\n });\n registry.register({\n name: \"join\",\n aliases: [\"\u7533\u8BF7\u5165\u670D\", \"/join\", \"/\u7533\u8BF7\u5165\u670D\"],\n description: \"\u7533\u8BF7\u52A0\u5165\u670D\u52A1\u5668\u767D\u540D\u5355\",\n handler: joinHandler,\n });\n registry.register({\n name: \"channel\",\n aliases: [\"\u9891\u9053\", \"/channel\", \"/\u9891\u9053\"],\n description: \"\u804A\u5929\u4E92\u901A\u9891\u9053\u4E0E\u8FDE\u901A\u81EA\u68C0\",\n handler: channelHandler,\n });\n registry.register({\n name: \"admin\",\n aliases: [\"\u7BA1\u7406\", \"/admin\", \"/\u7BA1\u7406\"],\n description: \"\u7BA1\u7406\u5B50\u83DC\u5355\uFF08\u7BA1\u7406\u5458\uFF09\",\n handler: createAdminMenuHandler(registry),\n });\n // \u2014\u2014 \u4EE5\u4E0B\u4EC5\u51FA\u73B0\u5728\u300C\u7BA1\u7406\u300D\u5B50\u83DC\u5355\uFF1B\u89E6\u53D1\u8BCD\u4ECD\u53EF\u76F4\u63A5\u8C03\u7528 \u2014\u2014\n registry.register({\n name: \"doctor\",\n aliases: [\"\u81EA\u68C0\", \"/doctor\", \"/\u81EA\u68C0\"],\n description: \"\u7BA1\u7406\u4FA7\u8FDE\u901A/\u914D\u7F6E\u81EA\u68C0\",\n handler: doctorHandler,\n adminMenu: true,\n });\n registry.register({\n name: \"group\",\n aliases: [\"\u7FA4\u4FE1\u606F\", \"/group\", \"/\u7FA4\u4FE1\u606F\"],\n description: \"QQ \u7FA4 OpenAPI \u6458\u8981\",\n handler: groupInfoHandler,\n adminMenu: true,\n });\n registry.register({\n name: \"config\",\n aliases: [\"\u914D\u7F6E\", \"\u5165\u670D\u914D\u7F6E\", \"/config\", \"/\u914D\u7F6E\"],\n description: \"\u5165\u670D\u767D\u540D\u5355/\u5BA1\u6279\u5F00\u5173\uFF08\u7BA1\u7406\u5458\uFF09\",\n handler: joinConfigHandler,\n adminMenu: true,\n });\n registry.register({\n name: \"pending\",\n aliases: [\"\u5F85\u5BA1\", \"/pending\", \"/\u5F85\u5BA1\"],\n description: \"\u5F85\u5BA1\u5165\u670D\u5217\u8868\uFF08\u7BA1\u7406\u5458\uFF09\",\n handler: pendingHandler,\n adminMenu: true,\n });\n registry.register({\n name: \"approve\",\n aliases: [\"\u901A\u8FC7\", \"/approve\", \"/\u901A\u8FC7\"],\n description: \"\u901A\u8FC7\u5165\u670D\u7533\u8BF7\uFF08\u7BA1\u7406\u5458\uFF09\",\n handler: approveHandler,\n adminMenu: true,\n });\n registry.register({\n name: \"reject\",\n aliases: [\"\u62D2\u7EDD\", \"/reject\", \"/\u62D2\u7EDD\"],\n description: \"\u62D2\u7EDD\u5165\u670D\u7533\u8BF7\uFF08\u7BA1\u7406\u5458\uFF09\",\n handler: rejectHandler,\n adminMenu: true,\n });\n registry.register({\n name: \"kick\",\n aliases: [\"\u8E22\u4EBA\", \"/kick\", \"/\u8E22\u4EBA\"],\n description: \"\u8E22\u51FA\u6E38\u620F\u5185\u73A9\u5BB6\uFF08\u7BA1\u7406\u5458\uFF09\",\n handler: kickHandler,\n adminMenu: true,\n });\n}\n\n"],
|
|
5
|
+
"mappings": "AAIA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,wBAAwB,4BAA4B;AAC7D,SAAS,yBAAyB;AAIlC,SAAS,aAAa,WAA2B;AAC/C,QAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,SAAS;AAC7C,QAAM,IAAI,KAAK,MAAM,KAAK,GAAI;AAC9B,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,MAAI,IAAI,EAAG,QAAO,GAAG,CAAC,KAAK,IAAI,EAAE;AACjC,MAAI,IAAI,EAAG,QAAO,GAAG,CAAC,KAAK,IAAI,EAAE;AACjC,SAAO,GAAG,CAAC;AACb;AAEA,SAAS,KAAK,KAAwC;AACpD,QAAM,OAAO,IAAI,YAAY;AAC7B,QAAM,OAAO,IAAI,YAAY;AAC7B,MAAI,CAAC,QAAQ,CAAC,KAAM,QAAO;AAC3B,SAAO,EAAE,MAAM,KAAK;AACtB;AAEA,SAAS,QAAQ,KAA8B;AAC7C,QAAM,SAAS,IAAI,YAAY,gBAAgB,CAAC;AAChD,MAAI,OAAO,SAAS,KAAK,OAAO,SAAS,IAAI,QAAQ,MAAM,EAAG,QAAO;AAErE,SAAO,IAAI,QAAQ,iBAAiB;AACtC;AAEA,SAAS,kBAAkB,KAA8B;AACvD,SAAO,IAAI,QAAQ,iBAAiB;AACtC;AAGA,eAAe,kBAAkB,KAAwC;AACvE,QAAM,QAAQ,IAAI,YAAY;AAC9B,QAAM,MAAM,IAAI,YAAY,eAAe,IAAI,QAAQ;AACvD,MAAI,CAAC,SAAS,CAAC,OAAO,IAAI,QAAQ,YAAY,WAAY,QAAO,CAAC;AAClE,QAAM,QAAkB,CAAC;AACzB,MAAI;AACF,UAAM,CAAC,SAAS,QAAQ,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC5C,aAAa,OAAO,GAAG;AAAA,MACvB,iBAAiB,OAAO,GAAG;AAAA,IAC7B,CAAC;AACD,QAAI,QAAQ,MAAM,QAAQ,QAAQ,OAAO,QAAQ,SAAS,UAAU;AAClE,YAAM,IAAI,QAAQ;AAClB,YAAM,KAAK,iBAAO,EAAE,cAAc,QAAG,sBAAS,EAAE,oBAAoB,QAAG,EAAE;AAAA,IAC3E,WAAW,CAAC,QAAQ,IAAI;AACtB,YAAM,OAAO,QAAQ,KAAK,QAAQ,SAAS,QAAQ,QAAQ,EAAE,IACzD,8EACA,wCAAU,QAAQ,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC;AAC/C,YAAM,KAAK,IAAI;AAAA,IACjB;AACA,QAAI,SAAS,MAAM,SAAS,QAAQ,OAAO,SAAS,SAAS,UAAU;AACrE,YAAM,IAAI,SAAS;AACnB,YAAM;AAAA,QACJ,wCAAU,EAAE,eAAe,QAAG,kCAAW,EAAE,wBAAwB,OAAO,WAAM,QAAG,4BAAU,EAAE,oBAAoB,QAAG;AAAA,MACxH;AAAA,IACF;AAAA,EACF,SAAS,GAAG;AACV,UAAM,KAAK,uCAAU,EAAY,OAAO,EAAE;AAAA,EAC5C;AACA,SAAO;AACT;AAEO,SAAS,kBAAkB,UAA2C;AAC3E,SAAO,MAAqB;AAC1B,UAAM,OAAO,SAAS,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM;AAChE,WAAO,kBAAkB;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AACF;AAGO,SAAS,uBAAuB,UAA2C;AAChF,SAAO,CAAC,QAAuC;AAC7C,QAAI,CAAC,QAAQ,GAAG,GAAG;AACjB,aAAO,EAAE,MAAM,gLAA8C;AAAA,IAC/D;AACA,UAAM,OAAO,SAAS,UAAU;AAChC,QAAI,KAAK,WAAW,GAAG;AACrB,aAAO,EAAE,MAAM,uCAAS;AAAA,IAC1B;AACA,WAAO,kBAAkB;AAAA,MACvB,OAAO;AAAA,MACP,UAAU;AAAA,MACV;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AACF;AAEO,MAAM,cAA8B,CAAC,QAAuC;AACjF,QAAM,EAAE,aAAa,WAAW,QAAQ,IAAI;AAC5C,QAAM,QAAQ,CAAC,QAAQ,WAAW,QAAQ,OAAO,IAAI,UAAU,aAAa,SAAS,CAAC,EAAE;AACxF,MAAI,QAAQ,YAAY,YAAY;AAClC,UAAM,KAAK,WAAW,YAAY,UAAU,SAAS,OAAO,EAAE;AAC9D,QAAI,YAAY,UAAW,OAAM,KAAK,OAAO,YAAY,SAAS,EAAE;AAAA,EACtE;AACA,SAAO,EAAE,MAAM,MAAM,KAAK,QAAK,EAAE;AACnC;AAEO,MAAM,gBAAgC,OAAO,QAAgD;AAClG,QAAM,EAAE,QAAQ,IAAI;AACpB,QAAM,QAAQ,CAAC,gBAAM,QAAQ,QAAQ,IAAI,MAAM,QAAQ,MAAM,IAAI,SAAS,QAAQ,OAAO,EAAE;AAC3F,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,IAAI;AACN,QAAI;AACF,YAAM,KAAK,MAAM,YAAY,IAAI,QAAQ,MAAM;AAC/C,UAAI,GAAG,SAAS,GAAG,SAAS;AAC1B,cAAM,KAAK,8BAAU,GAAG,QAAQ,eAAe,GAAG,KAAK,GAAG,QAAQ,eAAe,GAAG,GAAG;AAAA,MACzF,OAAO;AACL,cAAM,KAAK,qGAAqB;AAAA,MAClC;AAAA,IACF,QAAQ;AACN,YAAM,KAAK,8EAAuB;AAAA,IACpC;AAAA,EACF;AACA,SAAO,EAAE,MAAM,MAAM,KAAK,IAAI,EAAE;AAClC;AAEO,MAAM,gBAAgC,OAAO,QAAgD;AAClG,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,iDAA6B;AACrD,MAAI;AACF,UAAM,KAAK,MAAM,gBAAgB,EAAE;AACnC,UAAM,IAAI,MAAM,QAAQ,GAAG,MAAM,IAAI,GAAG,OAAO,SAAS;AACxD,UAAM,MAAM,GAAG,OAAO,OAAO,OAAO,OAAO,GAAG,MAAM,GAAG,IAAI;AAC3D,UAAM,OAAO,GAAG,OAAO,aAAa,OAAO,GAAG,MAAM,UAAU,IAAI;AAClE,UAAM,MACJ,OAAO,GAAG,cAAc,WAAW,GAAG,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,IAAI,IAAI,GAAG,aAAa,GAAI,CAAC,CAAC,YAAO;AAC1G,UAAM,OAAO,GAAG;AAChB,UAAM,MAAM,GAAG,WAAW;AAC1B,UAAM,KAAK,GAAG,WAAW;AACzB,UAAM,SAAS,MAAM,cAAc;AACnC,UAAM,UACJ,KAAK,UAAU,YACX,2BAAS,IAAI,cAAc,QAAG,GAAG,IAAI,MAAM,SAAS,IAAI,GAAG,MAAM,EAAE,KACnE;AACN,UAAM,MACJ,MAAM,UAAU,OACZ,GAAG,KAAK,OAAO,UAAU,QAAG,IAAI,KAAK,OAAO,WAAW,QAAG,QAAQ,KAAK,OAAO,eAAe,QAAG,OAChG;AACN,UAAM,MACJ,MAAM,OAAO,OAAO,GAAG,KAAK,IAAI,SAAS,QAAG,gBAAQ,KAAK,IAAI,SAAS,QAAG,KAAK;AAChF,UAAM,UAAU,OACZ,GAAG,KAAK,YAAY,QAAG,SAAM,KAAK,YAAY,QAAG,IAAI,KAAK,QAAQ,QAAG,IAAI,KAAK,WAAW,EAAE,GAAG,KAAK,IACnG;AACJ,UAAM,OAAO,GAAG,OAAO;AAAA,EAAK,GAAG,IAAI,KAAK,MAAM,IAAI,uDAAe;AACjE,UAAM,UAAU,MAAM,kBAAkB,GAAG;AAC3C,UAAM,OAAO;AAAA,MACX;AAAA,MACA,qBAAM,CAAC;AAAA,MACP,2BAAO,GAAG;AAAA,MACV,qBAAM,IAAI;AAAA,MACV,qBAAM,OAAO;AAAA,MACb,iCAAQ,MAAM;AAAA,MACd,YAAO,OAAO;AAAA,MACd,qBAAM,GAAG;AAAA,MACT,YAAO,GAAG;AAAA,MACV,kBAAa,IAAI,cAAc,QAAG,GAAG,IAAI,MAAM,SAAS,GAAG,GAAG,MAAM,EAAE;AAAA,MACtE,GAAG;AAAA,MACH,qBAAM,GAAG,GAAG,IAAI;AAAA,IAClB,EAAE,KAAK,IAAI;AACX,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA,2BAAY,CAAC;AAAA,MACb,iCAAa,GAAG;AAAA,MAChB,2BAAY,IAAI;AAAA,MAChB,2BAAY,OAAO;AAAA,MACnB,uCAAc,MAAM;AAAA,MACpB,kBAAa,OAAO;AAAA,MACpB,2BAAY,GAAG;AAAA,MACf,kBAAa,GAAG;AAAA,MAChB,wBAAmB,IAAI,cAAc,QAAG,GAAG,IAAI,MAAM,SAAS,GAAG,GAAG,MAAM,EAAE;AAAA,MAC5E,GAAG,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AAAA,MAC9B,2BAAY,GAAG;AAAA,MACf,OAAO;AAAA,IAAO,GAAG,QAAQ,oDAAY,KAAK,CAAC,MAAM;AAAA,IACnD,EACG,OAAO,CAAC,SAAS,SAAS,EAAE,EAC5B,KAAK,IAAI;AACZ,WAAO,EAAE,MAAM,SAAS;AAAA,EAC1B,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,4BAAc,EAAY,OAAO,GAAG;AAAA,EACrD;AACF;AAEA,MAAM,aAAa;AAEZ,MAAM,gBAAgC,OAAO,QAAgD;AAClG,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,iDAA6B;AACrD,MAAI;AACF,UAAM,KAAK,MAAM,gBAAgB,EAAE;AACnC,UAAM,OAAO,MAAM,QAAQ,GAAG,MAAM,IAAI,GAAG,SAAS,CAAC;AACrD,QAAI,KAAK,WAAW,GAAG;AACrB,aAAO,EAAE,MAAM,GAAG,QAAQ,uCAAS;AAAA,IACrC;AACA,UAAM,QAAQ,KAAK,MAAM,GAAG,UAAU;AACtC,UAAM,QAAQ,MAAM,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK,IAAI;AACjF,UAAM,OAAO,KAAK,SAAS,aAAa;AAAA,qBAAS,KAAK,SAAS,UAAU,8BAAU;AACnF,WAAO,EAAE,MAAM,gBAAM,KAAK,MAAM;AAAA,EAAO,KAAK,GAAG,IAAI,GAAG;AAAA,EACxD,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,4BAAc,EAAY,OAAO,GAAG;AAAA,EACrD;AACF;AAEO,MAAM,cAA8B,OAAO,QAAgD;AAChG,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,uDAAyB;AACjD,MAAI;AACF,UAAM,EAAE,QAAQ,KAAK,IAAI,MAAM,gBAAgB,IAAI;AAAA,MACjD,QAAQ,IAAI,QAAQ;AAAA,MACpB,YAAY,IAAI,QAAQ;AAAA,IAC1B,CAAC;AACD,QAAI,WAAW,OAAO,KAAK,UAAU,iBAAiB;AACpD,aAAO;AAAA,QACL,MAAM,iDAAc,KAAK,eAAe,GAAG;AAAA,MAC7C;AAAA,IACF;AACA,QAAI,CAAC,KAAK,WAAW,CAAC,KAAK,MAAM;AAC/B,aAAO,EAAE,MAAM,6CAAU,KAAK,SAAS,QAAQ,MAAM,EAAE,GAAG;AAAA,IAC5D;AACA,WAAO;AAAA,MACL,MAAM,2BAAO,KAAK,IAAI;AAAA;AAAA,MACtB,UAAU,2BAAY,KAAK,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IACjC;AAAA,EACF,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,iCAAS,EAAY,OAAO,GAAG;AAAA,EAChD;AACF;AAEO,MAAM,gBAAgC,OAAO,QAAgD;AAClG,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,uDAAyB;AACjD,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,eAAe,IAAI,EAAE,QAAQ,IAAI,QAAQ,OAAO,CAAC;AACxE,QAAI,KAAK,QAAS,QAAO,EAAE,MAAM,mDAAgB;AACjD,WAAO,EAAE,MAAM,yDAAY;AAAA,EAC7B,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,iCAAS,EAAY,OAAO,GAAG;AAAA,EAChD;AACF;AAEO,MAAM,mBAAmC,OAAO,QAAgD;AACrG,QAAM,QAAQ,MAAM,kBAAkB,GAAG;AACzC,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,EAAE,MAAM,kIAAwC;AAAA,EACzD;AACA,SAAO,EAAE,MAAM,CAAC,yBAAU,GAAG,KAAK,EAAE,KAAK,IAAI,EAAE;AACjD;AAEO,MAAM,cAA8B,OAAO,QAAgD;AAChG,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,mEAA2B;AACnD,MAAI,aAAa,IAAI,QAAQ,KAAK,QAAQ,uBAAuB,EAAE,EAAE,KAAK;AAC1E,MAAI,CAAC,YAAY;AACf,QAAI;AACF,YAAM,KAAK,MAAM,YAAY,IAAI,IAAI,QAAQ,MAAM;AACnD,UAAI,GAAG,SAAS,GAAG,SAAS,YAAa,cAAa,OAAO,GAAG,QAAQ,WAAW;AAAA,IACrF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,MAAI,CAAC,YAAY;AACf,WAAO,EAAE,MAAM,gIAA4B;AAAA,EAC7C;AACA,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,gBAAgB,IAAI;AAAA,MACzC,QAAQ,IAAI,QAAQ;AAAA,MACpB,aAAa;AAAA,MACb,YAAY,IAAI,QAAQ;AAAA,IAC1B,CAAC;AACD,QAAI,CAAC,KAAK,WAAW,CAAC,KAAK,IAAI;AAC7B,UAAI,KAAK,UAAU,2BAA2B;AAC5C,eAAO,EAAE,MAAM,+IAA4B;AAAA,MAC7C;AACA,aAAO,EAAE,MAAM,iCAAQ,KAAK,SAAS,SAAS,GAAG;AAAA,IACnD;AACA,QAAI,KAAK,iBAAiB,KAAK,WAAW,YAAY;AACpD,aAAO;AAAA,QACL,MAAM,KAAK,OACP,SAAI,UAAU,SAAI,KAAK,IAAI,KAC3B,uCAAS,UAAU;AAAA,MACzB;AAAA,IACF;AACA,UAAM,SAAS,IAAI,YAAY,gBAAgB,CAAC;AAChD,UAAM,QAAQ,IAAI,YAAY;AAC9B,UAAM,MAAM,IAAI,YAAY,eAAe,IAAI,QAAQ;AACvD,QAAI,SAAS,OAAO,OAAO,SAAS,KAAK,IAAI,QAAQ,YAAY,YAAY;AAC3E,WAAK,iBAAiB,OAAO;AAAA,QAC3B,aAAa;AAAA,QACb,SAAS;AAAA,QACT,UAAU;AAAA;AAAA,iBAAmB,UAAU;AAAA,uBAAa,IAAI,QAAQ,OAAO,MAAM,GAAG,CAAC,CAAC;AAAA,oBAAgB,KAAK,EAAE;AAAA,QACzG,iBAAiB;AAAA,UACf;AAAA,YACE,IAAI,MAAM,KAAK,EAAE;AAAA,YACjB,OAAO;AAAA,YACP,MAAM,gBAAgB,KAAK,EAAE;AAAA,YAC7B,YAAY;AAAA,YACZ,OAAO;AAAA,YACP,YAAY,EAAE,MAAM,GAAG,kBAAkB,OAAO;AAAA,UAClD;AAAA,UACA;AAAA,YACE,IAAI,MAAM,KAAK,EAAE;AAAA,YACjB,OAAO;AAAA,YACP,MAAM,eAAe,KAAK,EAAE;AAAA,YAC5B,YAAY;AAAA,YACZ,OAAO;AAAA,YACP,YAAY,EAAE,MAAM,GAAG,kBAAkB,OAAO;AAAA,UAClD;AAAA,QACF;AAAA,MACF,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,IAC1B;AACA,UAAM,OAAO,KAAK,OAAO;AAAA,EAAK,KAAK,IAAI,KAAK,OAAO,WAAW,IAAI,gGAAoC;AACtG,WAAO;AAAA,MACL,MAAM,mDAAW,UAAU,SAAI,IAAI;AAAA,MACnC,SACE,IAAI,QAAQ,YAAY,WAAW,OAAO,SAAS,IAC/C;AAAA,QACE,EAAE,IAAI,KAAK,OAAO,gBAAM,UAAU,IAAI,SAAS,YAAY,KAAK,EAAE,GAAG;AAAA,QACrE,EAAE,IAAI,KAAK,OAAO,gBAAM,UAAU,IAAI,SAAS,WAAW,KAAK,EAAE,GAAG;AAAA,MACtE,IACA;AAAA,IACR;AAAA,EACF,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,iCAAS,EAAY,OAAO,GAAG;AAAA,EAChD;AACF;AAEA,SAAS,WAAW,KAA6B;AAC/C,QAAM,IAAI,IAAI,KAAK,EAAE,YAAY;AACjC,MAAI,CAAC,UAAK,gBAAM,MAAM,QAAQ,KAAK,KAAK,EAAE,SAAS,CAAC,EAAG,QAAO;AAC9D,MAAI,CAAC,UAAK,gBAAM,OAAO,SAAS,KAAK,IAAI,EAAE,SAAS,CAAC,EAAG,QAAO;AAC/D,SAAO;AACT;AAGO,MAAM,oBAAoC,OAAO,QAAgD;AACtG,MAAI,CAAC,QAAQ,GAAG,EAAG,QAAO,EAAE,MAAM,8IAA0C;AAC5E,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,0CAAY;AAEpC,QAAM,SAAS,IAAI,YAAY,gBAAgB,CAAC;AAChD,QAAM,OAAO,IAAI,QAAQ,KAAK,QAAQ,4BAA4B,EAAE,EAAE,KAAK;AAC3E,MAAI,CAAC,MAAM;AACT,QAAI;AACF,YAAM,OAAO,MAAM,kBAAkB,EAAE;AACvC,UAAI,KAAK,YAAY,MAAO,QAAO,EAAE,MAAM,iCAAQ,KAAK,SAAS,SAAS,GAAG;AAC7E,aAAO,uBAAuB;AAAA,QAC5B,UAAU,qBAAqB,IAAI;AAAA,QACnC,SAAS,IAAI,QAAQ;AAAA,QACrB,cAAc;AAAA,MAChB,CAAC;AAAA,IACH,SAAS,GAAG;AACV,aAAO,EAAE,MAAM,iCAAS,EAAY,OAAO,GAAG;AAAA,IAChD;AAAA,EACF;AAEA,MAAI,iCAAiC,KAAK,IAAI,GAAG;AAC/C,WAAO;AAAA,MACL,MAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,IAAI,wCAAwC,KAAK,IAAI;AAC3D,MAAI,CAAC,GAAG;AACN,WAAO,EAAE,MAAM,oIAA2B;AAAA,EAC5C;AACA,QAAM,QAAQ,EAAE,CAAC,EAAG,YAAY;AAChC,QAAM,QAAQ,WAAW,EAAE,CAAC,CAAE;AAC9B,MAAI,UAAU,KAAM,QAAO,EAAE,MAAM,4DAAoB;AAEvD,QAAM,OAKF;AAAA,IACF,QAAQ,IAAI,QAAQ;AAAA,IACpB,gBAAgB,kBAAkB,GAAG;AAAA,EACvC;AACA,MAAI,UAAU,wBAAS,UAAU,YAAa,MAAK,oBAAoB;AAAA,MAClE,MAAK,mBAAmB;AAE7B,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,iBAAiB,IAAI,IAAI;AAChD,QAAI,KAAK,YAAY,OAAO;AAC1B,UAAI,KAAK,UAAU,aAAa;AAC9B,eAAO,EAAE,MAAM,iHAAoE;AAAA,MACrF;AACA,UAAI,KAAK,UAAU,mBAAmB;AACpC,eAAO,EAAE,MAAM,KAAK,QAAQ,+DAAa;AAAA,MAC3C;AACA,aAAO,EAAE,MAAM,iCAAQ,KAAK,SAAS,SAAS,GAAG;AAAA,IACnD;AACA,WAAO,uBAAuB;AAAA,MAC5B,UAAU,qBAAqB,IAAI;AAAA,MACnC,SAAS,IAAI,QAAQ;AAAA,MACrB,cAAc;AAAA,MACd,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,iCAAS,EAAY,OAAO,GAAG;AAAA,EAChD;AACF;AAEO,MAAM,iBAAiC,OAAO,QAAgD;AACnG,MAAI,CAAC,QAAQ,GAAG,EAAG,QAAO,EAAE,MAAM,8GAAmC;AACrE,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,0CAAY;AACpC,MAAI;AACF,UAAM,OAAO,MAAM,iBAAiB,IAAI,IAAI,QAAQ,QAAQ,kBAAkB,GAAG,CAAC;AAClF,QAAI,KAAK,OAAO;AACd,UAAI,KAAK,UAAU,aAAa;AAC9B,eAAO,EAAE,MAAM,qFAA6C;AAAA,MAC9D;AACA,aAAO,EAAE,MAAM,iCAAQ,KAAK,KAAK,GAAG;AAAA,IACtC;AACA,UAAM,OAAO,KAAK,WAAW,CAAC;AAC9B,QAAI,KAAK,WAAW,EAAG,QAAO,EAAE,MAAM,mDAAW;AACjD,UAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,eAAe,GAAG,KAAK,EAAE,EAAE,GAAG;AAC9E,WAAO,EAAE,MAAM,gBAAM,KAAK,MAAM;AAAA,EAAO,MAAM,KAAK,IAAI,CAAC,GAAG;AAAA,EAC5D,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,iCAAS,EAAY,OAAO,GAAG;AAAA,EAChD;AACF;AAEO,MAAM,iBAAiC,OAAO,QAAgD;AACnG,MAAI,CAAC,QAAQ,GAAG,EAAG,QAAO,EAAE,MAAM,6CAAU;AAC5C,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,wBAAS;AACjC,QAAM,KAAK,IAAI,QAAQ,KAAK,QAAQ,wBAAwB,EAAE,EAAE,KAAK;AACrE,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,kDAAe;AACvC,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,eAAe,IAAI;AAAA,MACxC;AAAA,MACA,UAAU;AAAA,MACV,YAAY,IAAI,QAAQ;AAAA,MACxB,gBAAgB,kBAAkB,GAAG;AAAA,IACvC,CAAC;AACD,QAAI,KAAK,YAAY,SAAS,KAAK,UAAU,aAAa;AACxD,aAAO,EAAE,MAAM,qFAA6C;AAAA,IAC9D;AACA,WAAO,EAAE,MAAM,KAAK,YAAY,QAAQ,qBAAM,KAAK,KAAK,KAAK,2BAAO,KAAK,eAAe,EAAE,SAAI;AAAA,EAChG,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,qBAAO,EAAY,OAAO,GAAG;AAAA,EAC9C;AACF;AAEO,MAAM,gBAAgC,OAAO,QAAgD;AAClG,MAAI,CAAC,QAAQ,GAAG,EAAG,QAAO,EAAE,MAAM,6CAAU;AAC5C,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,wBAAS;AACjC,QAAM,KAAK,IAAI,QAAQ,KAAK,QAAQ,uBAAuB,EAAE,EAAE,KAAK;AACpE,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,kDAAe;AACvC,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,eAAe,IAAI;AAAA,MACxC;AAAA,MACA,UAAU;AAAA,MACV,YAAY,IAAI,QAAQ;AAAA,MACxB,gBAAgB,kBAAkB,GAAG;AAAA,IACvC,CAAC;AACD,QAAI,KAAK,YAAY,SAAS,KAAK,UAAU,aAAa;AACxD,aAAO,EAAE,MAAM,qFAA6C;AAAA,IAC9D;AACA,WAAO,EAAE,MAAM,KAAK,YAAY,QAAQ,qBAAM,KAAK,KAAK,KAAK,2BAAO,KAAK,eAAe,EAAE,SAAI;AAAA,EAChG,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,qBAAO,EAAY,OAAO,GAAG;AAAA,EAC9C;AACF;AAGO,MAAM,iBAAiC,OAAO,QAAgD;AACnG,QAAM,KAAK,OAAO,IAAI,YAAY,mBAAmB,EAAE,EAAE,KAAK;AAC9D,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA,KAAK,qBAAM,EAAE,KAAK;AAAA,IAClB,qBAAM,IAAI,QAAQ,OAAO,GAAG,IAAI,YAAY,UAAU,kBAAe,EAAE;AAAA,EACzE;AACA,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,IAAI;AACP,UAAM,KAAK,4CAAwB;AAAA,EACrC,OAAO;AACL,QAAI;AACF,YAAM,KAAK,MAAM,gBAAgB,EAAE;AACnC,YAAM,MAAM,GAAG,WAAW;AAC1B,YAAM,KAAK,GAAG,WAAW;AACzB,YAAM,KAAK,kBAAa,IAAI,UAAU,aAAa,IAAI,YAAY,QAAQ,uBAAQ,IAAI,cAAc,cAAI,GAAG,IAAI,MAAM,SAAS,GAAG,GAAG,MAAM,EAAE,EAAE;AAC/I,YAAM;AAAA,QACJ,YAAO,KAAK,UAAU,aAAa,KAAK,YAAY,OAAO,2BAAS,IAAI,cAAc,QAAG,KAAK,oBAAK;AAAA,MACrG;AAAA,IACF,SAAS,GAAG;AACV,YAAM,KAAK,mCAAW,EAAY,OAAO,QAAG;AAAA,IAC9C;AAAA,EACF;AACA,QAAM,KAAK,kLAAsC;AACjD,QAAM,OAAO,MAAM,KAAK,IAAI;AAC5B,SAAO;AAAA,IACL;AAAA,IACA,UAAU,KACP,MAAM,IAAI,EACV,IAAI,CAAC,GAAG,MAAO,MAAM,IAAI,MAAM,EAAE,QAAQ,QAAQ,EAAE,CAAC,KAAK,KAAK,CAAC,EAAG,EAClE,KAAK,IAAI;AAAA,EACd;AACF;AAGO,MAAM,gBAAgC,OAAO,QAAgD;AAClG,MAAI,CAAC,QAAQ,GAAG,EAAG,QAAO,EAAE,MAAM,yDAAY;AAC9C,QAAM,OAAO,MAAM,eAAe,GAAG;AACrC,QAAM,QAAkB,CAAC,IAAI,sCAAQ;AACrC,QAAM,SAAS,IAAI,YAAY,gBAAgB,CAAC;AAChD,QAAM,KAAK,yCAAgB,OAAO,MAAM,GAAG,OAAO,WAAW,IAAI,kEAAgB,EAAE,EAAE;AACrF,QAAM,KAAK,sBAAY,IAAI,YAAY,cAAc,uBAAQ,oBAAK,EAAE;AACpE,MAAI,IAAI,QAAQ,YAAY,YAAY;AACtC,UAAM,KAAK,qBAAM,IAAI,YAAY,gBAAgB,uBAAQ,cAAI,EAAE;AAAA,EACjE;AACA,QAAM,OAAO,GAAG,KAAK,IAAI;AAAA,EAAK,MAAM,KAAK,IAAI,CAAC;AAC9C,SAAO,EAAE,MAAM,UAAU,GAAG,KAAK,YAAY,KAAK,IAAI;AAAA;AAAA;AAAA;AAAA,EAAmB,MAAM,OAAO,OAAO,EAAE,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,GAAG;AACnI;AAEO,MAAM,cAA8B,OAAO,QAAgD;AAChG,MAAI,CAAC,QAAQ,GAAG,EAAG,QAAO,EAAE,MAAM,sFAA+B;AACjE,QAAM,KAAK,KAAK,GAAG;AACnB,MAAI,CAAC,GAAI,QAAO,EAAE,MAAM,0CAAY;AACpC,QAAM,SAAS,IAAI,QAAQ,KAAK,QAAQ,qBAAqB,EAAE,EAAE,KAAK;AACtE,MAAI,CAAC,OAAQ,QAAO,EAAE,MAAM,sDAAc;AAC1C,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,cAAc,IAAI;AAAA,MACvC,QAAQ,IAAI,QAAQ;AAAA,MACpB,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,gBAAgB,kBAAkB,GAAG;AAAA,IACvC,CAAC;AACD,QAAI,CAAC,KAAK,SAAS;AACjB,UAAI,KAAK,UAAU,aAAa;AAC9B,eAAO,EAAE,MAAM,qFAA6C;AAAA,MAC9D;AACA,aAAO,EAAE,MAAM,6CAAU,KAAK,SAAS,SAAS,GAAG;AAAA,IACrD;AACA,WAAO,EAAE,MAAM,qBAAM,MAAM,sFAAqB;AAAA,EAClD,SAAS,GAAG;AACV,WAAO,EAAE,MAAM,iCAAS,EAAY,OAAO,GAAG;AAAA,EAChD;AACF;AAGO,SAAS,wBAAwB,UAAiC;AACvE,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,QAAQ,gBAAM,SAAS,iBAAO,OAAO;AAAA,IACrD,aAAa;AAAA,IACb,SAAS,kBAAkB,QAAQ;AAAA,EACrC,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,OAAO;AAAA,IACjB,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,WAAW,0BAAM;AAAA,IAC3B,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,WAAW,eAAK;AAAA,IAChC,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,WAAW,eAAK;AAAA,IAChC,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,SAAS,eAAK;AAAA,IAC9B,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,WAAW,eAAK;AAAA,IAChC,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,4BAAQ,SAAS,2BAAO;AAAA,IAClC,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,YAAY,eAAK;AAAA,IACjC,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,UAAU,eAAK;AAAA,IAC/B,aAAa;AAAA,IACb,SAAS,uBAAuB,QAAQ;AAAA,EAC1C,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,WAAW,eAAK;AAAA,IAChC,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,sBAAO,UAAU,qBAAM;AAAA,IACjC,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,4BAAQ,WAAW,eAAK;AAAA,IACxC,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,YAAY,eAAK;AAAA,IACjC,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,YAAY,eAAK;AAAA,IACjC,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,WAAW,eAAK;AAAA,IAChC,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,SAAS,CAAC,gBAAM,SAAS,eAAK;AAAA,IAC9B,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { registerBuiltinCommands } from "./handlers.js";
|
|
2
|
+
import { PendingChoiceStore } from "./pending.js";
|
|
3
|
+
import { CommandRegistry } from "./registry.js";
|
|
4
|
+
import { createLlbotReplyPort } from "./reply-llbot.js";
|
|
5
|
+
import { createOfficialReplyPort } from "./reply-official.js";
|
|
6
|
+
import { CommandRouter } from "./router.js";
|
|
7
|
+
import { CommandRouter as CommandRouter2 } from "./router.js";
|
|
8
|
+
import { renderOfficial, renderLlbot } from "./render.js";
|
|
9
|
+
import { normalizeTrigger, CommandRegistry as CommandRegistry2 } from "./registry.js";
|
|
10
|
+
import { PendingChoiceStore as PendingChoiceStore2 } from "./pending.js";
|
|
11
|
+
import { registerBuiltinCommands as registerBuiltinCommands2 } from "./handlers.js";
|
|
12
|
+
import { syncMenuAndPanel, buildMenuItems, buildPanelItems } from "./menu-panel-sync.js";
|
|
13
|
+
function createCommandRouter(opts) {
|
|
14
|
+
const registry = new CommandRegistry();
|
|
15
|
+
registerBuiltinCommands(registry);
|
|
16
|
+
return new CommandRouter({
|
|
17
|
+
registry,
|
|
18
|
+
pending: new PendingChoiceStore(),
|
|
19
|
+
reply: opts.reply,
|
|
20
|
+
startedAt: opts.startedAt ?? Date.now(),
|
|
21
|
+
runtimeInfo: opts.runtimeInfo
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function createOfficialCommandRouter(creds, runtimeInfo, startedAt) {
|
|
25
|
+
const opts = {
|
|
26
|
+
reply: createOfficialReplyPort(creds),
|
|
27
|
+
runtimeInfo
|
|
28
|
+
};
|
|
29
|
+
if (startedAt !== void 0) opts.startedAt = startedAt;
|
|
30
|
+
return createCommandRouter(opts);
|
|
31
|
+
}
|
|
32
|
+
function createLlbotCommandRouter(cfg, runtimeInfo = {}, startedAt) {
|
|
33
|
+
const opts = {
|
|
34
|
+
reply: createLlbotReplyPort(cfg),
|
|
35
|
+
runtimeInfo
|
|
36
|
+
};
|
|
37
|
+
if (startedAt !== void 0) opts.startedAt = startedAt;
|
|
38
|
+
return createCommandRouter(opts);
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
CommandRegistry2 as CommandRegistry,
|
|
42
|
+
CommandRouter2 as CommandRouter,
|
|
43
|
+
PendingChoiceStore2 as PendingChoiceStore,
|
|
44
|
+
buildMenuItems,
|
|
45
|
+
buildPanelItems,
|
|
46
|
+
createCommandRouter,
|
|
47
|
+
createLlbotCommandRouter,
|
|
48
|
+
createOfficialCommandRouter,
|
|
49
|
+
normalizeTrigger,
|
|
50
|
+
registerBuiltinCommands2 as registerBuiltinCommands,
|
|
51
|
+
renderLlbot,
|
|
52
|
+
renderOfficial,
|
|
53
|
+
syncMenuAndPanel
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/commands/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * commands/index.ts \u2014 \u7EC4\u88C5\u9ED8\u8BA4 Router\n */\n\nimport { registerBuiltinCommands } from \"./handlers.js\";\nimport { PendingChoiceStore } from \"./pending.js\";\nimport { CommandRegistry } from \"./registry.js\";\nimport { createLlbotReplyPort, type LlbotReplyConfig } from \"./reply-llbot.js\";\nimport { createOfficialReplyPort } from \"./reply-official.js\";\nimport { CommandRouter } from \"./router.js\";\nimport type { CommandContext, ReplyPort } from \"./types.js\";\nimport type { QqOfficialCredentials } from \"@sfmc-bds/sdk/node/qq-official\";\n\nexport type { CommandResult, InboundMessage, ReplyPort } from \"./types.js\";\nexport { CommandRouter } from \"./router.js\";\nexport { renderOfficial, renderLlbot } from \"./render.js\";\nexport { normalizeTrigger, CommandRegistry } from \"./registry.js\";\nexport { PendingChoiceStore } from \"./pending.js\";\nexport { registerBuiltinCommands } from \"./handlers.js\";\nexport { syncMenuAndPanel, buildMenuItems, buildPanelItems } from \"./menu-panel-sync.js\";\n\nexport function createCommandRouter(opts: {\n reply: ReplyPort;\n runtimeInfo: CommandContext[\"runtimeInfo\"];\n startedAt?: number;\n}): CommandRouter {\n const registry = new CommandRegistry();\n registerBuiltinCommands(registry);\n return new CommandRouter({\n registry,\n pending: new PendingChoiceStore(),\n reply: opts.reply,\n startedAt: opts.startedAt ?? Date.now(),\n runtimeInfo: opts.runtimeInfo,\n });\n}\n\nexport function createOfficialCommandRouter(\n creds: QqOfficialCredentials,\n runtimeInfo: CommandContext[\"runtimeInfo\"],\n startedAt?: number\n): CommandRouter {\n const opts: Parameters<typeof createCommandRouter>[0] = {\n reply: createOfficialReplyPort(creds),\n runtimeInfo,\n };\n if (startedAt !== undefined) opts.startedAt = startedAt;\n return createCommandRouter(opts);\n}\n\nexport function createLlbotCommandRouter(\n cfg: LlbotReplyConfig,\n runtimeInfo: CommandContext[\"runtimeInfo\"] = {},\n startedAt?: number\n): CommandRouter {\n const opts: Parameters<typeof createCommandRouter>[0] = {\n reply: createLlbotReplyPort(cfg),\n runtimeInfo,\n };\n if (startedAt !== undefined) opts.startedAt = startedAt;\n return createCommandRouter(opts);\n}\n"],
|
|
5
|
+
"mappings": "AAIA,SAAS,+BAA+B;AACxC,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAChC,SAAS,4BAAmD;AAC5D,SAAS,+BAA+B;AACxC,SAAS,qBAAqB;AAK9B,SAAS,iBAAAA,sBAAqB;AAC9B,SAAS,gBAAgB,mBAAmB;AAC5C,SAAS,kBAAkB,mBAAAC,wBAAuB;AAClD,SAAS,sBAAAC,2BAA0B;AACnC,SAAS,2BAAAC,gCAA+B;AACxC,SAAS,kBAAkB,gBAAgB,uBAAuB;AAE3D,SAAS,oBAAoB,MAIlB;AAChB,QAAM,WAAW,IAAI,gBAAgB;AACrC,0BAAwB,QAAQ;AAChC,SAAO,IAAI,cAAc;AAAA,IACvB;AAAA,IACA,SAAS,IAAI,mBAAmB;AAAA,IAChC,OAAO,KAAK;AAAA,IACZ,WAAW,KAAK,aAAa,KAAK,IAAI;AAAA,IACtC,aAAa,KAAK;AAAA,EACpB,CAAC;AACH;AAEO,SAAS,4BACd,OACA,aACA,WACe;AACf,QAAM,OAAkD;AAAA,IACtD,OAAO,wBAAwB,KAAK;AAAA,IACpC;AAAA,EACF;AACA,MAAI,cAAc,OAAW,MAAK,YAAY;AAC9C,SAAO,oBAAoB,IAAI;AACjC;AAEO,SAAS,yBACd,KACA,cAA6C,CAAC,GAC9C,WACe;AACf,QAAM,OAAkD;AAAA,IACtD,OAAO,qBAAqB,GAAG;AAAA,IAC/B;AAAA,EACF;AACA,MAAI,cAAc,OAAW,MAAK,YAAY;AAC9C,SAAO,oBAAoB,IAAI;AACjC;",
|
|
6
|
+
"names": ["CommandRouter", "CommandRegistry", "PendingChoiceStore", "registerBuiltinCommands"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ackInteraction,
|
|
3
|
+
sendC2cMessage,
|
|
4
|
+
sendGroupMessage
|
|
5
|
+
} from "@sfmc-bds/sdk/node/qq-official";
|
|
6
|
+
import { log } from "../log.js";
|
|
7
|
+
import { postJoinDecide, postJoinSettings } from "./db-api.js";
|
|
8
|
+
import {
|
|
9
|
+
buildJoinSettingsPanel,
|
|
10
|
+
parseCfgInteractionData,
|
|
11
|
+
settingsFromResponse
|
|
12
|
+
} from "./join-settings-ui.js";
|
|
13
|
+
import { renderOfficial } from "./render.js";
|
|
14
|
+
const recentIds = /* @__PURE__ */ new Map();
|
|
15
|
+
const DEDUP_MS = 6e4;
|
|
16
|
+
function remember(id) {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
for (const [k, t] of recentIds) {
|
|
19
|
+
if (now - t > DEDUP_MS) recentIds.delete(k);
|
|
20
|
+
}
|
|
21
|
+
if (recentIds.has(id)) return false;
|
|
22
|
+
recentIds.set(id, now);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
function extractUserOpenid(d) {
|
|
26
|
+
return String(
|
|
27
|
+
d.user_openid || d.member_openid || d.author?.member_openid || d.author?.user_openid || d.author?.id || ""
|
|
28
|
+
).trim();
|
|
29
|
+
}
|
|
30
|
+
function extractData(d) {
|
|
31
|
+
const raw = d.data;
|
|
32
|
+
if (typeof raw === "string") return raw.trim();
|
|
33
|
+
const nested = d;
|
|
34
|
+
for (const key of ["button_data", "button", "event_data"]) {
|
|
35
|
+
const v = nested[key];
|
|
36
|
+
if (typeof v === "string") return v.trim();
|
|
37
|
+
if (v && typeof v === "object" && "data" in v) {
|
|
38
|
+
return String(v.data ?? "").trim();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
async function replyGroup(opts, groupOpenid, text, panel) {
|
|
44
|
+
if (!groupOpenid) return;
|
|
45
|
+
if (panel) {
|
|
46
|
+
const rendered = renderOfficial(panel);
|
|
47
|
+
const res = await sendGroupMessage(opts.creds, {
|
|
48
|
+
groupOpenid,
|
|
49
|
+
msgType: rendered.msgType,
|
|
50
|
+
...rendered.msgType === 2 ? { markdown: rendered.markdown ?? panel.text } : { content: rendered.content ?? panel.text },
|
|
51
|
+
...rendered.keyboardButtons ? { keyboardButtons: rendered.keyboardButtons } : {}
|
|
52
|
+
});
|
|
53
|
+
if (res.ok) return;
|
|
54
|
+
log.warn(`\u914D\u7F6E\u9762\u677F Markdown \u53D1\u9001\u5931\u8D25\uFF0C\u964D\u7EA7\u6587\u672C: ${res.error}`);
|
|
55
|
+
}
|
|
56
|
+
await sendGroupMessage(opts.creds, { groupOpenid, content: text });
|
|
57
|
+
}
|
|
58
|
+
function createInteractionRouter(opts) {
|
|
59
|
+
return {
|
|
60
|
+
async handle(raw) {
|
|
61
|
+
const d = raw ?? {};
|
|
62
|
+
const interactionId = String(d.id ?? "").trim();
|
|
63
|
+
if (!interactionId) {
|
|
64
|
+
log.warn("INTERACTION \u7F3A\u5C11 id\uFF0C\u8DF3\u8FC7");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!remember(interactionId)) {
|
|
68
|
+
log.info(`INTERACTION \u53BB\u91CD\u8DF3\u8FC7 id=${interactionId}`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const ack = await ackInteraction(opts.creds, interactionId);
|
|
72
|
+
if (!ack.ok) {
|
|
73
|
+
log.warn(`ackInteraction \u5931\u8D25: ${ack.error}`);
|
|
74
|
+
}
|
|
75
|
+
const userId = extractUserOpenid(d);
|
|
76
|
+
const data = extractData(d);
|
|
77
|
+
const groupOpenid = String(d.group_openid ?? "").trim();
|
|
78
|
+
log.info(`INTERACTION data=${data || "?"} user=${userId || "?"} group=${groupOpenid || "?"}`);
|
|
79
|
+
const cfg = parseCfgInteractionData(data);
|
|
80
|
+
if (cfg) {
|
|
81
|
+
if (!opts.adminOpenids.includes(userId)) {
|
|
82
|
+
await replyGroup(opts, groupOpenid, "\u4F60\u6CA1\u6709\u914D\u7F6E\u6743\u9650\u3002");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const body = { openid: userId };
|
|
87
|
+
if (cfg.field === "allowlist_enabled") body.allowlist_enabled = cfg.value;
|
|
88
|
+
else body.require_approval = cfg.value;
|
|
89
|
+
const { data: result } = await postJoinSettings(opts.db, body);
|
|
90
|
+
if (result.success === false) {
|
|
91
|
+
await replyGroup(opts, groupOpenid, `\u4FDD\u5B58\u5931\u8D25\uFF1A${result.error || result.note || "unknown"}`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const panel = buildJoinSettingsPanel({
|
|
95
|
+
settings: settingsFromResponse(result),
|
|
96
|
+
backend: "official",
|
|
97
|
+
adminOpenids: opts.adminOpenids,
|
|
98
|
+
prefix: "\u5DF2\u4FDD\u5B58"
|
|
99
|
+
});
|
|
100
|
+
await replyGroup(opts, groupOpenid, panel.text, panel);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
log.warn(`cfg settings \u5931\u8D25: ${e.message}`);
|
|
103
|
+
await replyGroup(opts, groupOpenid, `\u4FDD\u5B58\u5931\u8D25\uFF1A${e.message}`);
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const m = /^(join):(approve|reject):(.+)$/.exec(data);
|
|
108
|
+
if (!m) {
|
|
109
|
+
log.warn(`\u672A\u77E5 INTERACTION data: ${data.slice(0, 80)}`);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const decision = m[2] === "approve" ? "approve" : "reject";
|
|
113
|
+
const requestId = String(m[3] ?? "").trim();
|
|
114
|
+
if (!requestId) return;
|
|
115
|
+
if (!opts.adminOpenids.includes(userId)) {
|
|
116
|
+
if (groupOpenid) {
|
|
117
|
+
await sendGroupMessage(opts.creds, {
|
|
118
|
+
groupOpenid,
|
|
119
|
+
content: "\u4F60\u6CA1\u6709\u5BA1\u6279\u6743\u9650\u3002"
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const { data: result } = await postJoinDecide(opts.db, {
|
|
126
|
+
id: requestId,
|
|
127
|
+
decision,
|
|
128
|
+
decided_by: userId
|
|
129
|
+
});
|
|
130
|
+
const name = result.player_name || "?";
|
|
131
|
+
const text = result.success === false ? `\u5BA1\u6279\u5931\u8D25\uFF1A${result.error || "unknown"}` : decision === "approve" ? `\u5DF2\u901A\u8FC7\u300C${name}\u300D\u5165\u670D\u7533\u8BF7\uFF08\u7B49\u5F85 BDS \u5199\u5165\u767D\u540D\u5355\uFF09` : `\u5DF2\u62D2\u7EDD\u300C${name}\u300D\u5165\u670D\u7533\u8BF7`;
|
|
132
|
+
if (groupOpenid) {
|
|
133
|
+
await sendGroupMessage(opts.creds, { groupOpenid, content: text });
|
|
134
|
+
}
|
|
135
|
+
const applicant = String(result.applicant_openid ?? "").trim();
|
|
136
|
+
if (result.success !== false && applicant) {
|
|
137
|
+
const tip = decision === "approve" ? `\u4F60\u7684\u5165\u670D\u7533\u8BF7\u300C${name}\u300D\u5DF2\u901A\u8FC7\uFF0C\u8BF7\u7B49\u5F85\u670D\u52A1\u5668\u5199\u5165\u767D\u540D\u5355\u3002` : `\u4F60\u7684\u5165\u670D\u7533\u8BF7\u300C${name}\u300D\u5DF2\u62D2\u7EDD\u3002`;
|
|
138
|
+
await sendC2cMessage(opts.creds, { userOpenid: applicant, content: tip }).catch(() => void 0);
|
|
139
|
+
}
|
|
140
|
+
} catch (e) {
|
|
141
|
+
log.warn(`join decide \u5931\u8D25: ${e.message}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
export {
|
|
147
|
+
createInteractionRouter
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=interaction-router.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/commands/interaction-router.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * commands/interaction-router.ts \u2014 \u5B98\u65B9 INTERACTION_CREATE \u5206\u53D1\n *\n * data \u7EA6\u5B9A\uFF1A\n * join:approve:<id> / join:reject:<id>\n * cfg:allowlist|approval:on|off\n */\n\nimport {\n ackInteraction,\n sendC2cMessage,\n sendGroupMessage,\n type QqOfficialCredentials,\n} from \"@sfmc-bds/sdk/node/qq-official\";\nimport { log } from \"../log.js\";\nimport { postJoinDecide, postJoinSettings, type DbEndpoint } from \"./db-api.js\";\nimport {\n buildJoinSettingsPanel,\n parseCfgInteractionData,\n settingsFromResponse,\n} from \"./join-settings-ui.js\";\nimport { renderOfficial } from \"./render.js\";\n\nexport type InteractionPayload = {\n id?: string;\n data?: string;\n group_openid?: string;\n chat_type?: number;\n /** \u70B9\u51FB\u4EBA */\n user_openid?: string;\n member_openid?: string;\n author?: { id?: string; member_openid?: string; user_openid?: string };\n};\n\nexport type InteractionRouterOpts = {\n creds: QqOfficialCredentials;\n db: DbEndpoint;\n adminOpenids: string[];\n};\n\nconst recentIds = new Map<string, number>();\nconst DEDUP_MS = 60_000;\n\nfunction remember(id: string): boolean {\n const now = Date.now();\n for (const [k, t] of recentIds) {\n if (now - t > DEDUP_MS) recentIds.delete(k);\n }\n if (recentIds.has(id)) return false;\n recentIds.set(id, now);\n return true;\n}\n\nfunction extractUserOpenid(d: InteractionPayload): string {\n return String(\n d.user_openid ||\n d.member_openid ||\n d.author?.member_openid ||\n d.author?.user_openid ||\n d.author?.id ||\n \"\"\n ).trim();\n}\n\nfunction extractData(d: InteractionPayload): string {\n const raw = d.data;\n if (typeof raw === \"string\") return raw.trim();\n // \u90E8\u5206\u4E8B\u4EF6\u628A button \u5D4C\u5728 nested \u5B57\u6BB5\n const nested = d as Record<string, unknown>;\n for (const key of [\"button_data\", \"button\", \"event_data\"]) {\n const v = nested[key];\n if (typeof v === \"string\") return v.trim();\n if (v && typeof v === \"object\" && \"data\" in (v as object)) {\n return String((v as { data?: string }).data ?? \"\").trim();\n }\n }\n return \"\";\n}\n\nasync function replyGroup(\n opts: InteractionRouterOpts,\n groupOpenid: string,\n text: string,\n panel?: ReturnType<typeof buildJoinSettingsPanel>\n): Promise<void> {\n if (!groupOpenid) return;\n if (panel) {\n const rendered = renderOfficial(panel);\n const res = await sendGroupMessage(opts.creds, {\n groupOpenid,\n msgType: rendered.msgType,\n ...(rendered.msgType === 2\n ? { markdown: rendered.markdown ?? panel.text }\n : { content: rendered.content ?? panel.text }),\n ...(rendered.keyboardButtons ? { keyboardButtons: rendered.keyboardButtons } : {}),\n });\n if (res.ok) return;\n log.warn(`\u914D\u7F6E\u9762\u677F Markdown \u53D1\u9001\u5931\u8D25\uFF0C\u964D\u7EA7\u6587\u672C: ${res.error}`);\n }\n await sendGroupMessage(opts.creds, { groupOpenid, content: text });\n}\n\nexport function createInteractionRouter(opts: InteractionRouterOpts) {\n return {\n async handle(raw: unknown): Promise<void> {\n const d = (raw ?? {}) as InteractionPayload;\n const interactionId = String(d.id ?? \"\").trim();\n if (!interactionId) {\n log.warn(\"INTERACTION \u7F3A\u5C11 id\uFF0C\u8DF3\u8FC7\");\n return;\n }\n if (!remember(interactionId)) {\n log.info(`INTERACTION \u53BB\u91CD\u8DF3\u8FC7 id=${interactionId}`);\n return;\n }\n\n // \u5148 ack\uFF0C\u907F\u514D\u5BA2\u6237\u7AEF\u4E00\u76F4 loading\n const ack = await ackInteraction(opts.creds, interactionId);\n if (!ack.ok) {\n log.warn(`ackInteraction \u5931\u8D25: ${ack.error}`);\n }\n\n const userId = extractUserOpenid(d);\n const data = extractData(d);\n const groupOpenid = String(d.group_openid ?? \"\").trim();\n log.info(`INTERACTION data=${data || \"?\"} user=${userId || \"?\"} group=${groupOpenid || \"?\"}`);\n\n const cfg = parseCfgInteractionData(data);\n if (cfg) {\n if (!opts.adminOpenids.includes(userId)) {\n await replyGroup(opts, groupOpenid, \"\u4F60\u6CA1\u6709\u914D\u7F6E\u6743\u9650\u3002\");\n return;\n }\n try {\n const body: {\n openid: string;\n allowlist_enabled?: boolean;\n require_approval?: boolean;\n } = { openid: userId };\n if (cfg.field === \"allowlist_enabled\") body.allowlist_enabled = cfg.value;\n else body.require_approval = cfg.value;\n\n const { data: result } = await postJoinSettings(opts.db, body);\n if (result.success === false) {\n await replyGroup(opts, groupOpenid, `\u4FDD\u5B58\u5931\u8D25\uFF1A${result.error || result.note || \"unknown\"}`);\n return;\n }\n const panel = buildJoinSettingsPanel({\n settings: settingsFromResponse(result),\n backend: \"official\",\n adminOpenids: opts.adminOpenids,\n prefix: \"\u5DF2\u4FDD\u5B58\",\n });\n await replyGroup(opts, groupOpenid, panel.text, panel);\n } catch (e) {\n log.warn(`cfg settings \u5931\u8D25: ${(e as Error).message}`);\n await replyGroup(opts, groupOpenid, `\u4FDD\u5B58\u5931\u8D25\uFF1A${(e as Error).message}`);\n }\n return;\n }\n\n const m = /^(join):(approve|reject):(.+)$/.exec(data);\n if (!m) {\n log.warn(`\u672A\u77E5 INTERACTION data: ${data.slice(0, 80)}`);\n return;\n }\n const decision = m[2] === \"approve\" ? (\"approve\" as const) : (\"reject\" as const);\n const requestId = String(m[3] ?? \"\").trim();\n if (!requestId) return;\n\n if (!opts.adminOpenids.includes(userId)) {\n if (groupOpenid) {\n await sendGroupMessage(opts.creds, {\n groupOpenid,\n content: \"\u4F60\u6CA1\u6709\u5BA1\u6279\u6743\u9650\u3002\",\n });\n }\n return;\n }\n\n try {\n const { data: result } = await postJoinDecide(opts.db, {\n id: requestId,\n decision,\n decided_by: userId,\n });\n const name = result.player_name || \"?\";\n const text =\n result.success === false\n ? `\u5BA1\u6279\u5931\u8D25\uFF1A${result.error || \"unknown\"}`\n : decision === \"approve\"\n ? `\u5DF2\u901A\u8FC7\u300C${name}\u300D\u5165\u670D\u7533\u8BF7\uFF08\u7B49\u5F85 BDS \u5199\u5165\u767D\u540D\u5355\uFF09`\n : `\u5DF2\u62D2\u7EDD\u300C${name}\u300D\u5165\u670D\u7533\u8BF7`;\n if (groupOpenid) {\n await sendGroupMessage(opts.creds, { groupOpenid, content: text });\n }\n // \u901A\u77E5\u7533\u8BF7\u4EBA\uFF08\u5355\u804A\uFF1B\u5931\u8D25\u5FFD\u7565\uFF09\n const applicant = String(result.applicant_openid ?? \"\").trim();\n if (result.success !== false && applicant) {\n const tip =\n decision === \"approve\"\n ? `\u4F60\u7684\u5165\u670D\u7533\u8BF7\u300C${name}\u300D\u5DF2\u901A\u8FC7\uFF0C\u8BF7\u7B49\u5F85\u670D\u52A1\u5668\u5199\u5165\u767D\u540D\u5355\u3002`\n : `\u4F60\u7684\u5165\u670D\u7533\u8BF7\u300C${name}\u300D\u5DF2\u62D2\u7EDD\u3002`;\n await sendC2cMessage(opts.creds, { userOpenid: applicant, content: tip }).catch(() => undefined);\n }\n } catch (e) {\n log.warn(`join decide \u5931\u8D25: ${(e as Error).message}`);\n }\n },\n };\n}\n\nexport type InteractionRouter = ReturnType<typeof createInteractionRouter>;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
function onOffLabel(on) {
|
|
2
|
+
return on ? "\u5F00" : "\u5173";
|
|
3
|
+
}
|
|
4
|
+
function formatJoinSettingsText(s, prefix = "") {
|
|
5
|
+
const al = onOffLabel(s.allowlist_enabled !== false);
|
|
6
|
+
const ap = onOffLabel(s.require_approval !== false);
|
|
7
|
+
const ga = onOffLabel(s.treat_group_admins_as_admins === true);
|
|
8
|
+
const head = prefix ? `${prefix}
|
|
9
|
+
` : "";
|
|
10
|
+
return `${head}\u5165\u670D\u63D2\u4EF6\u914D\u7F6E\uFF08configs/qq_link.json\uFF09
|
|
11
|
+
\xB7 \u767D\u540D\u5355\uFF1A${al}
|
|
12
|
+
\xB7 \u5BA1\u6279\uFF1A${ap}
|
|
13
|
+
\xB7 \u7FA4\u7BA1\u89C6\u4F5C\u7BA1\u7406\u5458\uFF1A${ga}\uFF08\u53EA\u8BFB\uFF0C\u6539\u6587\u4EF6\uFF09`;
|
|
14
|
+
}
|
|
15
|
+
function formatJoinSettingsMarkdown(s, prefix) {
|
|
16
|
+
const al = onOffLabel(s.allowlist_enabled !== false);
|
|
17
|
+
const ap = onOffLabel(s.require_approval !== false);
|
|
18
|
+
const ga = onOffLabel(s.treat_group_admins_as_admins === true);
|
|
19
|
+
const lines = [
|
|
20
|
+
"## \u5165\u670D\u914D\u7F6E",
|
|
21
|
+
...prefix ? ["", prefix] : [],
|
|
22
|
+
"",
|
|
23
|
+
`| \u9879 | \u72B6\u6001 |`,
|
|
24
|
+
`| --- | --- |`,
|
|
25
|
+
`| \u767D\u540D\u5355 | **${al}** |`,
|
|
26
|
+
`| \u5BA1\u6279 | **${ap}** |`,
|
|
27
|
+
`| \u7FA4\u7BA1\u89C6\u4F5C\u7BA1\u7406\u5458 | ${ga}\uFF08\u53EA\u8BFB\uFF09 |`,
|
|
28
|
+
"",
|
|
29
|
+
"_\u70B9\u6309\u94AE\u5207\u6362\u767D\u540D\u5355/\u5BA1\u6279\uFF1B\u7FA4\u7BA1\u5F00\u5173\u8BF7\u6539\u914D\u7F6E\u6587\u4EF6_"
|
|
30
|
+
];
|
|
31
|
+
return lines.join("\n");
|
|
32
|
+
}
|
|
33
|
+
function buildJoinSettingsButtons(s, backend, adminOpenids = []) {
|
|
34
|
+
const alOn = s.allowlist_enabled !== false;
|
|
35
|
+
const apOn = s.require_approval !== false;
|
|
36
|
+
const alTarget = !alOn;
|
|
37
|
+
const apTarget = !apOn;
|
|
38
|
+
const alWord = alTarget ? "\u5F00" : "\u5173";
|
|
39
|
+
const apWord = apTarget ? "\u5F00" : "\u5173";
|
|
40
|
+
const permission = adminOpenids.length > 0 ? { type: 0, specify_user_ids: adminOpenids } : { type: 2 };
|
|
41
|
+
if (backend === "official") {
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
id: "cfg_al",
|
|
45
|
+
label: `\u767D\u540D\u5355\xB7${alWord}`,
|
|
46
|
+
command: `cfg:allowlist:${alTarget ? "on" : "off"}`,
|
|
47
|
+
actionType: 1,
|
|
48
|
+
style: alTarget ? 1 : 0,
|
|
49
|
+
visitedLabel: `\u767D\u540D\u5355\xB7${alWord}`,
|
|
50
|
+
permission
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "cfg_ap",
|
|
54
|
+
label: `\u5BA1\u6279\xB7${apWord}`,
|
|
55
|
+
command: `cfg:approval:${apTarget ? "on" : "off"}`,
|
|
56
|
+
actionType: 1,
|
|
57
|
+
style: apTarget ? 1 : 0,
|
|
58
|
+
visitedLabel: `\u5BA1\u6279\xB7${apWord}`,
|
|
59
|
+
permission
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
return [
|
|
64
|
+
{
|
|
65
|
+
id: "cfg_al",
|
|
66
|
+
label: `\u767D\u540D\u5355 ${alWord}`,
|
|
67
|
+
command: `\u914D\u7F6E \u767D\u540D\u5355 ${alWord}`
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "cfg_ap",
|
|
71
|
+
label: `\u5BA1\u6279 ${apWord}`,
|
|
72
|
+
command: `\u914D\u7F6E \u5BA1\u6279 ${apWord}`
|
|
73
|
+
}
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
function buildJoinSettingsPanel(opts) {
|
|
77
|
+
const { settings, backend, adminOpenids = [], prefix } = opts;
|
|
78
|
+
const text = formatJoinSettingsText(settings, prefix);
|
|
79
|
+
return {
|
|
80
|
+
text,
|
|
81
|
+
markdown: formatJoinSettingsMarkdown(settings, prefix),
|
|
82
|
+
buttons: buildJoinSettingsButtons(settings, backend, adminOpenids)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function parseCfgInteractionData(data) {
|
|
86
|
+
const m = /^cfg:(allowlist|approval):(on|off|true|false|1|0)$/i.exec(data.trim());
|
|
87
|
+
if (!m) return null;
|
|
88
|
+
const field = m[1].toLowerCase() === "allowlist" ? "allowlist_enabled" : "require_approval";
|
|
89
|
+
const raw = m[2].toLowerCase();
|
|
90
|
+
const value = raw === "on" || raw === "true" || raw === "1";
|
|
91
|
+
return { field, value };
|
|
92
|
+
}
|
|
93
|
+
function settingsFromResponse(data) {
|
|
94
|
+
return {
|
|
95
|
+
allowlist_enabled: data.allowlist_enabled,
|
|
96
|
+
require_approval: data.require_approval,
|
|
97
|
+
treat_group_admins_as_admins: data.treat_group_admins_as_admins
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export {
|
|
101
|
+
buildJoinSettingsButtons,
|
|
102
|
+
buildJoinSettingsPanel,
|
|
103
|
+
formatJoinSettingsMarkdown,
|
|
104
|
+
formatJoinSettingsText,
|
|
105
|
+
parseCfgInteractionData,
|
|
106
|
+
settingsFromResponse
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=join-settings-ui.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/commands/join-settings-ui.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * commands/join-settings-ui.ts \u2014 \u5165\u670D\u914D\u7F6E\u9762\u677F\u6587\u6848\u4E0E\u4E92\u52A8\u6309\u94AE\uFF08DRY\uFF09\n *\n * official\uFF1AINTERACTION \u56DE\u8C03 data = cfg:allowlist|approval:on|off\n * llbot\uFF1A\u7F16\u53F7\u4F1A\u8BDD command = \u300C\u914D\u7F6E \u767D\u540D\u5355/\u5BA1\u6279 \u5F00|\u5173\u300D\n */\n\nimport type { JoinSettingsResponse } from \"./db-api.js\";\nimport type { CommandButton, CommandResult, QqBackendKind } from \"./types.js\";\n\nexport type JoinSettingsView = {\n allowlist_enabled?: boolean;\n require_approval?: boolean;\n treat_group_admins_as_admins?: boolean;\n};\n\nfunction onOffLabel(on: boolean): string {\n return on ? \"\u5F00\" : \"\u5173\";\n}\n\n/** \u7EAF\u6587\u672C\u6458\u8981\uFF08llbot / \u964D\u7EA7\uFF09 */\nexport function formatJoinSettingsText(s: JoinSettingsView, prefix = \"\"): string {\n const al = onOffLabel(s.allowlist_enabled !== false);\n const ap = onOffLabel(s.require_approval !== false);\n const ga = onOffLabel(s.treat_group_admins_as_admins === true);\n const head = prefix ? `${prefix}\\n` : \"\";\n return (\n `${head}\u5165\u670D\u63D2\u4EF6\u914D\u7F6E\uFF08configs/qq_link.json\uFF09\\n` +\n `\u00B7 \u767D\u540D\u5355\uFF1A${al}\\n` +\n `\u00B7 \u5BA1\u6279\uFF1A${ap}\\n` +\n `\u00B7 \u7FA4\u7BA1\u89C6\u4F5C\u7BA1\u7406\u5458\uFF1A${ga}\uFF08\u53EA\u8BFB\uFF0C\u6539\u6587\u4EF6\uFF09`\n );\n}\n\nexport function formatJoinSettingsMarkdown(s: JoinSettingsView, prefix?: string): string {\n const al = onOffLabel(s.allowlist_enabled !== false);\n const ap = onOffLabel(s.require_approval !== false);\n const ga = onOffLabel(s.treat_group_admins_as_admins === true);\n const lines = [\n \"## \u5165\u670D\u914D\u7F6E\",\n ...(prefix ? [\"\", prefix] : []),\n \"\",\n `| \u9879 | \u72B6\u6001 |`,\n `| --- | --- |`,\n `| \u767D\u540D\u5355 | **${al}** |`,\n `| \u5BA1\u6279 | **${ap}** |`,\n `| \u7FA4\u7BA1\u89C6\u4F5C\u7BA1\u7406\u5458 | ${ga}\uFF08\u53EA\u8BFB\uFF09 |`,\n \"\",\n \"_\u70B9\u6309\u94AE\u5207\u6362\u767D\u540D\u5355/\u5BA1\u6279\uFF1B\u7FA4\u7BA1\u5F00\u5173\u8BF7\u6539\u914D\u7F6E\u6587\u4EF6_\",\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * \u751F\u6210\u5207\u6362\u6309\u94AE\uFF1A\u5C55\u793A\u300C\u70B9\u4E00\u4E0B\u53D8\u6210\u7684\u76EE\u6807\u72B6\u6001\u300D\u3002\n * official \u7528\u56DE\u8C03\uFF1Bllbot \u7528\u6587\u672C\u547D\u4EE4\u3002\n */\nexport function buildJoinSettingsButtons(\n s: JoinSettingsView,\n backend: QqBackendKind,\n adminOpenids: string[] = []\n): CommandButton[] {\n const alOn = s.allowlist_enabled !== false;\n const apOn = s.require_approval !== false;\n // \u70B9\u4E00\u4E0B\u5207\u5230\u53CD\u72B6\u6001\n const alTarget = !alOn;\n const apTarget = !apOn;\n const alWord = alTarget ? \"\u5F00\" : \"\u5173\";\n const apWord = apTarget ? \"\u5F00\" : \"\u5173\";\n\n const permission =\n adminOpenids.length > 0\n ? { type: 0 as const, specify_user_ids: adminOpenids }\n : { type: 2 as const };\n\n if (backend === \"official\") {\n return [\n {\n id: \"cfg_al\",\n label: `\u767D\u540D\u5355\u00B7${alWord}`,\n command: `cfg:allowlist:${alTarget ? \"on\" : \"off\"}`,\n actionType: 1,\n style: alTarget ? 1 : 0,\n visitedLabel: `\u767D\u540D\u5355\u00B7${alWord}`,\n permission,\n },\n {\n id: \"cfg_ap\",\n label: `\u5BA1\u6279\u00B7${apWord}`,\n command: `cfg:approval:${apTarget ? \"on\" : \"off\"}`,\n actionType: 1,\n style: apTarget ? 1 : 0,\n visitedLabel: `\u5BA1\u6279\u00B7${apWord}`,\n permission,\n },\n ];\n }\n\n return [\n {\n id: \"cfg_al\",\n label: `\u767D\u540D\u5355 ${alWord}`,\n command: `\u914D\u7F6E \u767D\u540D\u5355 ${alWord}`,\n },\n {\n id: \"cfg_ap\",\n label: `\u5BA1\u6279 ${apWord}`,\n command: `\u914D\u7F6E \u5BA1\u6279 ${apWord}`,\n },\n ];\n}\n\nexport function buildJoinSettingsPanel(opts: {\n settings: JoinSettingsView;\n backend: QqBackendKind;\n adminOpenids?: string[];\n /** \u5982\u300C\u5DF2\u4FDD\u5B58\u300D */\n prefix?: string;\n}): CommandResult {\n const { settings, backend, adminOpenids = [], prefix } = opts;\n const text = formatJoinSettingsText(settings, prefix);\n return {\n text,\n markdown: formatJoinSettingsMarkdown(settings, prefix),\n buttons: buildJoinSettingsButtons(settings, backend, adminOpenids),\n };\n}\n\n/** \u89E3\u6790 cfg:allowlist|approval:on|off */\nexport function parseCfgInteractionData(\n data: string\n): { field: \"allowlist_enabled\" | \"require_approval\"; value: boolean } | null {\n const m = /^cfg:(allowlist|approval):(on|off|true|false|1|0)$/i.exec(data.trim());\n if (!m) return null;\n const field = m[1]!.toLowerCase() === \"allowlist\" ? \"allowlist_enabled\" : \"require_approval\";\n const raw = m[2]!.toLowerCase();\n const value = raw === \"on\" || raw === \"true\" || raw === \"1\";\n return { field, value };\n}\n\nexport function settingsFromResponse(data: JoinSettingsResponse): JoinSettingsView {\n return {\n allowlist_enabled: data.allowlist_enabled,\n require_approval: data.require_approval,\n treat_group_admins_as_admins: data.treat_group_admins_as_admins,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import {
|
|
4
|
+
buildJoinSettingsPanel,
|
|
5
|
+
parseCfgInteractionData
|
|
6
|
+
} from "./join-settings-ui.js";
|
|
7
|
+
import { renderOfficial } from "./render.js";
|
|
8
|
+
test("parseCfgInteractionData", () => {
|
|
9
|
+
assert.deepEqual(parseCfgInteractionData("cfg:allowlist:off"), {
|
|
10
|
+
field: "allowlist_enabled",
|
|
11
|
+
value: false
|
|
12
|
+
});
|
|
13
|
+
assert.deepEqual(parseCfgInteractionData("cfg:approval:on"), {
|
|
14
|
+
field: "require_approval",
|
|
15
|
+
value: true
|
|
16
|
+
});
|
|
17
|
+
assert.equal(parseCfgInteractionData("join:approve:x"), null);
|
|
18
|
+
});
|
|
19
|
+
test("official \u914D\u7F6E\u9762\u677F\u4E3A INTERACTION \u56DE\u8C03\u6309\u94AE", () => {
|
|
20
|
+
const panel = buildJoinSettingsPanel({
|
|
21
|
+
settings: { allowlist_enabled: true, require_approval: false, treat_group_admins_as_admins: false },
|
|
22
|
+
backend: "official",
|
|
23
|
+
adminOpenids: ["admin1"]
|
|
24
|
+
});
|
|
25
|
+
assert.equal(panel.buttons?.length, 2);
|
|
26
|
+
assert.equal(panel.buttons?.[0]?.actionType, 1);
|
|
27
|
+
assert.equal(panel.buttons?.[0]?.command, "cfg:allowlist:off");
|
|
28
|
+
assert.equal(panel.buttons?.[1]?.command, "cfg:approval:on");
|
|
29
|
+
const rendered = renderOfficial(panel);
|
|
30
|
+
assert.equal(rendered.msgType, 2);
|
|
31
|
+
assert.equal(rendered.keyboardButtons?.[0]?.actionType, 1);
|
|
32
|
+
assert.equal(rendered.keyboardButtons?.[0]?.data, "cfg:allowlist:off");
|
|
33
|
+
});
|
|
34
|
+
test("llbot \u914D\u7F6E\u9762\u677F\u4E3A\u6587\u672C\u547D\u4EE4\u7F16\u53F7", () => {
|
|
35
|
+
const panel = buildJoinSettingsPanel({
|
|
36
|
+
settings: { allowlist_enabled: false, require_approval: true },
|
|
37
|
+
backend: "llbot"
|
|
38
|
+
});
|
|
39
|
+
assert.equal(panel.buttons?.[0]?.command, "\u914D\u7F6E \u767D\u540D\u5355 \u5F00");
|
|
40
|
+
assert.equal(panel.buttons?.[1]?.command, "\u914D\u7F6E \u5BA1\u6279 \u5173");
|
|
41
|
+
assert.equal(panel.buttons?.[0]?.actionType, void 0);
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=join-settings-ui.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/commands/join-settings-ui.test.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * commands/join-settings-ui.test.ts\n */\nimport assert from \"node:assert/strict\";\nimport test from \"node:test\";\nimport {\n buildJoinSettingsPanel,\n parseCfgInteractionData,\n} from \"./join-settings-ui.js\";\nimport { renderOfficial } from \"./render.js\";\n\ntest(\"parseCfgInteractionData\", () => {\n assert.deepEqual(parseCfgInteractionData(\"cfg:allowlist:off\"), {\n field: \"allowlist_enabled\",\n value: false,\n });\n assert.deepEqual(parseCfgInteractionData(\"cfg:approval:on\"), {\n field: \"require_approval\",\n value: true,\n });\n assert.equal(parseCfgInteractionData(\"join:approve:x\"), null);\n});\n\ntest(\"official \u914D\u7F6E\u9762\u677F\u4E3A INTERACTION \u56DE\u8C03\u6309\u94AE\", () => {\n const panel = buildJoinSettingsPanel({\n settings: { allowlist_enabled: true, require_approval: false, treat_group_admins_as_admins: false },\n backend: \"official\",\n adminOpenids: [\"admin1\"],\n });\n assert.equal(panel.buttons?.length, 2);\n assert.equal(panel.buttons?.[0]?.actionType, 1);\n assert.equal(panel.buttons?.[0]?.command, \"cfg:allowlist:off\");\n assert.equal(panel.buttons?.[1]?.command, \"cfg:approval:on\");\n const rendered = renderOfficial(panel);\n assert.equal(rendered.msgType, 2);\n assert.equal(rendered.keyboardButtons?.[0]?.actionType, 1);\n assert.equal(rendered.keyboardButtons?.[0]?.data, \"cfg:allowlist:off\");\n});\n\ntest(\"llbot \u914D\u7F6E\u9762\u677F\u4E3A\u6587\u672C\u547D\u4EE4\u7F16\u53F7\", () => {\n const panel = buildJoinSettingsPanel({\n settings: { allowlist_enabled: false, require_approval: true },\n backend: \"llbot\",\n });\n assert.equal(panel.buttons?.[0]?.command, \"\u914D\u7F6E \u767D\u540D\u5355 \u5F00\");\n assert.equal(panel.buttons?.[1]?.command, \"\u914D\u7F6E \u5BA1\u6279 \u5173\");\n assert.equal(panel.buttons?.[0]?.actionType, undefined);\n});\n"],
|
|
5
|
+
"mappings": "AAGA,OAAO,YAAY;AACnB,OAAO,UAAU;AACjB;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAE/B,KAAK,2BAA2B,MAAM;AACpC,SAAO,UAAU,wBAAwB,mBAAmB,GAAG;AAAA,IAC7D,OAAO;AAAA,IACP,OAAO;AAAA,EACT,CAAC;AACD,SAAO,UAAU,wBAAwB,iBAAiB,GAAG;AAAA,IAC3D,OAAO;AAAA,IACP,OAAO;AAAA,EACT,CAAC;AACD,SAAO,MAAM,wBAAwB,gBAAgB,GAAG,IAAI;AAC9D,CAAC;AAED,KAAK,gFAAmC,MAAM;AAC5C,QAAM,QAAQ,uBAAuB;AAAA,IACnC,UAAU,EAAE,mBAAmB,MAAM,kBAAkB,OAAO,8BAA8B,MAAM;AAAA,IAClG,SAAS;AAAA,IACT,cAAc,CAAC,QAAQ;AAAA,EACzB,CAAC;AACD,SAAO,MAAM,MAAM,SAAS,QAAQ,CAAC;AACrC,SAAO,MAAM,MAAM,UAAU,CAAC,GAAG,YAAY,CAAC;AAC9C,SAAO,MAAM,MAAM,UAAU,CAAC,GAAG,SAAS,mBAAmB;AAC7D,SAAO,MAAM,MAAM,UAAU,CAAC,GAAG,SAAS,iBAAiB;AAC3D,QAAM,WAAW,eAAe,KAAK;AACrC,SAAO,MAAM,SAAS,SAAS,CAAC;AAChC,SAAO,MAAM,SAAS,kBAAkB,CAAC,GAAG,YAAY,CAAC;AACzD,SAAO,MAAM,SAAS,kBAAkB,CAAC,GAAG,MAAM,mBAAmB;AACvE,CAAC;AAED,KAAK,4EAAqB,MAAM;AAC9B,QAAM,QAAQ,uBAAuB;AAAA,IACnC,UAAU,EAAE,mBAAmB,OAAO,kBAAkB,KAAK;AAAA,IAC7D,SAAS;AAAA,EACX,CAAC;AACD,SAAO,MAAM,MAAM,UAAU,CAAC,GAAG,SAAS,wCAAU;AACpD,SAAO,MAAM,MAAM,UAAU,CAAC,GAAG,SAAS,kCAAS;AACnD,SAAO,MAAM,MAAM,UAAU,CAAC,GAAG,YAAY,MAAS;AACxD,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
function pickDisplayLabel(cmd, maxChars = 8) {
|
|
2
|
+
const candidates = [cmd.name, ...cmd.aliases].map((a) => String(a ?? "").replace(/^[//]+/, "").trim()).filter((a) => a.length > 0);
|
|
3
|
+
const zh = candidates.find((a) => /[\u4e00-\u9fff]/.test(a));
|
|
4
|
+
const preferred = zh ?? candidates.find((a) => !a.startsWith("/")) ?? candidates[0] ?? cmd.name;
|
|
5
|
+
return preferred.slice(0, maxChars);
|
|
6
|
+
}
|
|
7
|
+
function buttonsFor(cmds, idPrefix) {
|
|
8
|
+
return cmds.map((c) => ({
|
|
9
|
+
id: `${idPrefix}_${c.name}`,
|
|
10
|
+
label: pickDisplayLabel(c, 8),
|
|
11
|
+
command: `/${c.name}`
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
function formatCommandMenu(opts) {
|
|
15
|
+
const { title, subtitle, cmds, idPrefix, footerMd, footerText } = opts;
|
|
16
|
+
const textLines = cmds.map((c, i) => {
|
|
17
|
+
const label = pickDisplayLabel(c, 8);
|
|
18
|
+
return `${i + 1}. ${label} \u2014 ${c.description}`;
|
|
19
|
+
});
|
|
20
|
+
const mdLines = cmds.map((c) => {
|
|
21
|
+
const label = pickDisplayLabel(c, 12);
|
|
22
|
+
return `- **${label}**\uFF08\`/${c.name}\`\uFF09\uFF1A${c.description}`;
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
text: `${title}
|
|
26
|
+
${subtitle}
|
|
27
|
+
|
|
28
|
+
${textLines.join("\n")}
|
|
29
|
+
|
|
30
|
+
${footerText}`,
|
|
31
|
+
markdown: `## ${title}
|
|
32
|
+
|
|
33
|
+
${subtitle}
|
|
34
|
+
|
|
35
|
+
${mdLines.join("\n")}
|
|
36
|
+
|
|
37
|
+
${footerMd}`,
|
|
38
|
+
buttons: buttonsFor(cmds, idPrefix)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
formatCommandMenu,
|
|
43
|
+
pickDisplayLabel
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=menu-format.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/commands/menu-format.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * menu-format.ts \u2014 \u4E3B\u83DC\u5355 / \u7BA1\u7406\u5B50\u83DC\u5355\u7EDF\u4E00\u6587\u6848\uFF08official Markdown + llbot \u7EAF\u6587\u672C\uFF09\n *\n * \u4E24\u8FB9\u5171\u7528\u540C\u4E00\u5957 label/description\uFF0C\u4FDD\u8BC1\u7F16\u53F7\u4F1A\u8BDD\u4E0E\u6309\u94AE\u6587\u6848\u4E00\u81F4\u3002\n */\n\nimport type { CommandButton, CommandResult, RegisteredCommand } from \"./types.js\";\n\n/** \u4F18\u5148\u4E2D\u6587\u77ED\u522B\u540D\u4F5C\u6309\u94AE/\u7F16\u53F7\u6807\u7B7E */\nexport function pickDisplayLabel(cmd: RegisteredCommand, maxChars = 8): string {\n const candidates = [cmd.name, ...cmd.aliases]\n .map((a) => String(a ?? \"\").replace(/^[/\uFF0F]+/, \"\").trim())\n .filter((a) => a.length > 0);\n const zh = candidates.find((a) => /[\\u4e00-\\u9fff]/.test(a));\n const preferred = zh ?? candidates.find((a) => !a.startsWith(\"/\")) ?? candidates[0] ?? cmd.name;\n return preferred.slice(0, maxChars);\n}\n\nfunction buttonsFor(cmds: RegisteredCommand[], idPrefix: string): CommandButton[] {\n return cmds.map((c) => ({\n id: `${idPrefix}_${c.name}`,\n label: pickDisplayLabel(c, 8),\n command: `/${c.name}`,\n }));\n}\n\nexport function formatCommandMenu(opts: {\n title: string;\n subtitle: string;\n cmds: RegisteredCommand[];\n idPrefix: string;\n footerMd: string;\n footerText: string;\n}): CommandResult {\n const { title, subtitle, cmds, idPrefix, footerMd, footerText } = opts;\n const textLines = cmds.map((c, i) => {\n const label = pickDisplayLabel(c, 8);\n return `${i + 1}. ${label} \u2014 ${c.description}`;\n });\n const mdLines = cmds.map((c) => {\n const label = pickDisplayLabel(c, 12);\n return `- **${label}**\uFF08\\`/${c.name}\\`\uFF09\uFF1A${c.description}`;\n });\n return {\n text: `${title}\\n${subtitle}\\n\\n${textLines.join(\"\\n\")}\\n\\n${footerText}`,\n markdown: `## ${title}\\n\\n${subtitle}\\n\\n${mdLines.join(\"\\n\")}\\n\\n${footerMd}`,\n buttons: buttonsFor(cmds, idPrefix),\n };\n}\n"],
|
|
5
|
+
"mappings": "AASO,SAAS,iBAAiB,KAAwB,WAAW,GAAW;AAC7E,QAAM,aAAa,CAAC,IAAI,MAAM,GAAG,IAAI,OAAO,EACzC,IAAI,CAAC,MAAM,OAAO,KAAK,EAAE,EAAE,QAAQ,UAAU,EAAE,EAAE,KAAK,CAAC,EACvD,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC7B,QAAM,KAAK,WAAW,KAAK,CAAC,MAAM,kBAAkB,KAAK,CAAC,CAAC;AAC3D,QAAM,YAAY,MAAM,WAAW,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC,KAAK,WAAW,CAAC,KAAK,IAAI;AAC3F,SAAO,UAAU,MAAM,GAAG,QAAQ;AACpC;AAEA,SAAS,WAAW,MAA2B,UAAmC;AAChF,SAAO,KAAK,IAAI,CAAC,OAAO;AAAA,IACtB,IAAI,GAAG,QAAQ,IAAI,EAAE,IAAI;AAAA,IACzB,OAAO,iBAAiB,GAAG,CAAC;AAAA,IAC5B,SAAS,IAAI,EAAE,IAAI;AAAA,EACrB,EAAE;AACJ;AAEO,SAAS,kBAAkB,MAOhB;AAChB,QAAM,EAAE,OAAO,UAAU,MAAM,UAAU,UAAU,WAAW,IAAI;AAClE,QAAM,YAAY,KAAK,IAAI,CAAC,GAAG,MAAM;AACnC,UAAM,QAAQ,iBAAiB,GAAG,CAAC;AACnC,WAAO,GAAG,IAAI,CAAC,KAAK,KAAK,WAAM,EAAE,WAAW;AAAA,EAC9C,CAAC;AACD,QAAM,UAAU,KAAK,IAAI,CAAC,MAAM;AAC9B,UAAM,QAAQ,iBAAiB,GAAG,EAAE;AACpC,WAAO,OAAO,KAAK,cAAS,EAAE,IAAI,iBAAO,EAAE,WAAW;AAAA,EACxD,CAAC;AACD,SAAO;AAAA,IACL,MAAM,GAAG,KAAK;AAAA,EAAK,QAAQ;AAAA;AAAA,EAAO,UAAU,KAAK,IAAI,CAAC;AAAA;AAAA,EAAO,UAAU;AAAA,IACvE,UAAU,MAAM,KAAK;AAAA;AAAA,EAAO,QAAQ;AAAA;AAAA,EAAO,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA,EAAO,QAAQ;AAAA,IAC5E,SAAS,WAAW,MAAM,QAAQ;AAAA,EACpC;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|