koishi-plugin-18xx 0.0.1

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/lib/api.d.ts ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ import type { Context } from 'koishi';
2
+ import { Config } from './config';
3
+ export declare function command(ctx: Context, config: Config): void;
@@ -0,0 +1,20 @@
1
+ import { Schema } from 'koishi';
2
+ export declare const name = "18xx";
3
+ export declare const inject: {
4
+ required: string[];
5
+ };
6
+ export interface Config {
7
+ notification: {
8
+ enable: boolean;
9
+ path: string;
10
+ items: {
11
+ platform: string;
12
+ defaultGuildId: string;
13
+ guildIds: string[];
14
+ defaultBotIds: string[];
15
+ botIds: string[];
16
+ }[];
17
+ };
18
+ }
19
+ export declare const Config: Schema<Config>;
20
+ export default Config;
package/lib/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { Context } from 'koishi';
2
+ import { Config, name, inject } from './config';
3
+ export { name, inject };
4
+ export { Config };
5
+ export declare function apply(ctx: Context, config: Config): void;
package/lib/index.js ADDED
@@ -0,0 +1,252 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ var __export = (target, all) => {
7
+ for (var name2 in all)
8
+ __defProp(target, name2, { get: all[name2], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ Config: () => Config,
24
+ apply: () => apply,
25
+ inject: () => inject,
26
+ name: () => name
27
+ });
28
+ module.exports = __toCommonJS(src_exports);
29
+
30
+ // src/config.ts
31
+ var import_koishi = require("koishi");
32
+ var name = "18xx";
33
+ var inject = {
34
+ required: ["server", "database"]
35
+ // optional: ['puppeteer'],
36
+ };
37
+ var Config = import_koishi.Schema.object({
38
+ notification: import_koishi.Schema.object({
39
+ enable: import_koishi.Schema.boolean().default(true).description("启用通知"),
40
+ path: import_koishi.Schema.string().default("/18xx").description("Webhook 监听路径"),
41
+ items: import_koishi.Schema.array(
42
+ import_koishi.Schema.object({
43
+ platform: import_koishi.Schema.string().default("").description("平台,为空表示不限制"),
44
+ defaultGuildId: import_koishi.Schema.string().default("").description("默认发送通知的群,如果不指定,通知会被发送到绑定时的群,如果绑定时没有群,通知不会发送"),
45
+ guildIds: import_koishi.Schema.array(import_koishi.Schema.string()).default([]).description("允许发送通知的群,为空表示允许在所有群发送通知"),
46
+ defaultBotIds: import_koishi.Schema.array(import_koishi.Schema.string()).default([]).description("默认发送通知的机器人,如果不指定,通知由绑定时的机器人发送"),
47
+ botIds: import_koishi.Schema.array(import_koishi.Schema.string()).default([]).description("允许发送通知的机器人,如果先前的机器人都无法工作,将会尝试使用后面的机器人发送通知,为空表示允许所有机器人发送通知")
48
+ })
49
+ ).default([]).description("平台通知设置")
50
+ }).description("通知设置")
51
+ });
52
+
53
+ // src/command.ts
54
+ function command(ctx, config) {
55
+ const logger = ctx.logger(name);
56
+ const checkSessionMiddleware = /* @__PURE__ */ __name(({ session }) => {
57
+ if (!session.guildId) {
58
+ return "请在群里使用这个命令";
59
+ }
60
+ if (config.notification.items.length) {
61
+ let found = false;
62
+ for (const { botIds, guildIds, defaultBotIds, defaultGuildId } of config.notification.items.filter(
63
+ (item) => !item.platform || item.platform === session.platform
64
+ )) {
65
+ if (botIds.length && !botIds.includes(session.selfId) && !defaultBotIds.includes(session.selfId)) {
66
+ continue;
67
+ }
68
+ if (guildIds.length && !guildIds.includes(session.guildId) && defaultGuildId !== session.guildId) {
69
+ continue;
70
+ }
71
+ found = true;
72
+ break;
73
+ }
74
+ if (!found) return "";
75
+ }
76
+ }, "checkSessionMiddleware");
77
+ ctx.command("18xx.bind <id>", "绑定 18xx.games 账号").usage("id 是个人资料页地址栏 profile 后面的数字").before(checkSessionMiddleware).action(async ({ session }, id) => {
78
+ if (Number(id)) {
79
+ const result = await ctx.database.upsert(name, [
80
+ {
81
+ id: Number(id),
82
+ userId: session.userId,
83
+ platform: session.platform,
84
+ botId: session.selfId,
85
+ guildId: session.guildId
86
+ }
87
+ ]);
88
+ if (result.inserted) {
89
+ return `${id} 绑定成功`;
90
+ } else {
91
+ return `${id} 重新绑定成功`;
92
+ }
93
+ } else {
94
+ return "绑定失败";
95
+ }
96
+ });
97
+ ctx.command("18xx.unbind <id>", "取消绑定 18xx.games 账号").usage("id 是个人资料页地址栏 profile 后面的数字").action(async ({ session }, id) => {
98
+ const result = await ctx.database.remove(name, { id: Number(id), userId: session.userId });
99
+ if (!result.matched) {
100
+ return "你还没有绑定 18xx.games 账号";
101
+ }
102
+ if (result.removed) {
103
+ return `${id} 解绑成功`;
104
+ }
105
+ return "解绑失败";
106
+ });
107
+ ctx.command("18xx.list", "列出已绑定的 18xx.games 账号").alias("18xx.ls").action(async ({ session }) => {
108
+ const profiles = await ctx.database.get(name, { userId: session.userId });
109
+ if (!profiles.length) {
110
+ return "你还没有绑定 18xx.games 账号";
111
+ }
112
+ return `当前已绑定${profiles.length}个账号:
113
+ ${profiles.map((p) => `${p.id}`).join("\n")}`;
114
+ });
115
+ ctx.command("18xx.on", "开启 18xx.games 通知").usage("需要先绑定 18xx.games 账号,并在个人资料页 webhook_user_id 中填入你的 id").action(async ({ session }) => {
116
+ const profiles = await ctx.database.get(name, { userId: session.userId });
117
+ if (!profiles.length) {
118
+ return "你还没有绑定 18xx.games 账号";
119
+ }
120
+ const result = await ctx.database.upsert(
121
+ name,
122
+ profiles.map((p) => ({ ...p, notify: true }))
123
+ );
124
+ if (result.matched > 1) {
125
+ return `开启了${result.matched || 0}个账号的通知`;
126
+ }
127
+ return "通知已开启";
128
+ });
129
+ ctx.command("18xx.off", "关闭 18xx.games 通知").action(async ({ session }) => {
130
+ const profiles = await ctx.database.get(name, { userId: session.userId });
131
+ if (!profiles.length) {
132
+ return "你还没有绑定 18xx.games 账号";
133
+ }
134
+ const result = await ctx.database.upsert(
135
+ name,
136
+ profiles.map((p) => ({ ...p, notify: false }))
137
+ );
138
+ if (result.matched > 1) {
139
+ return `关闭了${result.matched || 0}个账号的通知`;
140
+ }
141
+ return "通知已关闭";
142
+ });
143
+ }
144
+ __name(command, "command");
145
+
146
+ // src/server.tsx
147
+ var import_jsx_runtime = require("@satorijs/element/jsx-runtime");
148
+ var MESSAGE_REGEX = /^<@?(.*?)>\s*(.*)$/;
149
+ function server(ctx, config) {
150
+ const logger = ctx.logger(name);
151
+ if (config.notification.enable) {
152
+ ctx.server.post(config.notification.path, async (ptx, _next) => {
153
+ const { text = "" } = ptx.request.body || {};
154
+ const result = MESSAGE_REGEX.exec(text);
155
+ if (!result) {
156
+ logger.error("Webhook格式错误");
157
+ return ptx.status = 400;
158
+ }
159
+ const [, webhookId, message] = result;
160
+ if (!Number(webhookId) || !message) {
161
+ logger.error("Webhook格式错误");
162
+ return ptx.status = 400;
163
+ }
164
+ const profiles = await ctx.database.get(name, { id: Number(webhookId) });
165
+ logger.info("Webhook", webhookId, message, profiles);
166
+ const sendNotification = /* @__PURE__ */ __name(async (profile, bots = ctx.bots, guildIds = [profile.guildId]) => {
167
+ let success = false;
168
+ for (const bot of bots) {
169
+ for (const guildId of guildIds) {
170
+ try {
171
+ const result2 = await bot.sendMessage(
172
+ guildId,
173
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
174
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("at", { id: profile.userId, name: webhookId }),
175
+ " ",
176
+ message
177
+ ] })
178
+ );
179
+ logger.info("通知发送成功", result2, message, profile);
180
+ success = true;
181
+ break;
182
+ } catch (e) {
183
+ logger.error("通知发送失败", e, message, profile);
184
+ }
185
+ }
186
+ if (success) {
187
+ break;
188
+ }
189
+ }
190
+ if (!success) {
191
+ logger.info("未能发送通知", message, profile);
192
+ }
193
+ return success;
194
+ }, "sendNotification");
195
+ for (const profile of profiles.filter((profile2) => profile2.notify)) {
196
+ if (!config.notification.items.length) {
197
+ await sendNotification(profile);
198
+ continue;
199
+ }
200
+ for (const item of config.notification.items.filter((item2) => !item2.platform || item2.platform === profile.platform)) {
201
+ if (item.botIds.length && !item.botIds.includes(profile.botId) && !item.defaultBotIds.includes(profile.botId)) {
202
+ continue;
203
+ }
204
+ if (item.guildIds.length && !item.guildIds.includes(profile.guildId) && item.defaultGuildId !== profile.guildId) {
205
+ continue;
206
+ }
207
+ const bots = Array.from(
208
+ new Set(
209
+ [
210
+ ...item.defaultBotIds.map((id) => ctx.bots.find((bot) => bot.selfId === id)),
211
+ ctx.bots.find((bot) => bot.selfId === profile.botId),
212
+ ...item.botIds.map((id) => ctx.bots.find((bot) => bot.selfId === id))
213
+ ].filter(Boolean)
214
+ )
215
+ );
216
+ const guildIds = Array.from(new Set([item.defaultGuildId, profile.guildId, ...item.guildIds].filter(Boolean)));
217
+ if (await sendNotification(profile, bots, guildIds)) {
218
+ break;
219
+ }
220
+ }
221
+ }
222
+ return ptx.status = 200;
223
+ });
224
+ logger.info("启用通知服务");
225
+ }
226
+ }
227
+ __name(server, "server");
228
+
229
+ // src/index.ts
230
+ function apply(ctx, config) {
231
+ ctx.model.extend(name, {
232
+ id: "integer",
233
+ userId: "string",
234
+ platform: "string",
235
+ botId: "string",
236
+ guildId: "string",
237
+ notify: {
238
+ type: "boolean",
239
+ initial: true
240
+ }
241
+ });
242
+ command(ctx, config);
243
+ server(ctx, config);
244
+ }
245
+ __name(apply, "apply");
246
+ // Annotate the CommonJS export names for ESM import in node:
247
+ 0 && (module.exports = {
248
+ Config,
249
+ apply,
250
+ inject,
251
+ name
252
+ });
@@ -0,0 +1,3 @@
1
+ import type { Context } from 'koishi';
2
+ import { Config } from './config';
3
+ export declare function server(ctx: Context, config: Config): void;
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "koishi-plugin-18xx",
3
+ "description": "18xxGames 机器人",
4
+ "version": "0.0.1",
5
+ "main": "lib/index.js",
6
+ "typings": "lib/index.d.ts",
7
+ "files": [
8
+ "lib",
9
+ "dist"
10
+ ],
11
+ "contributors": [
12
+ "SeaLoong <sealoongw@foxmail.com>"
13
+ ],
14
+ "license": "MIT",
15
+ "homepage": "https://github.com/SeaLoong/koishi-plugin-18xx",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/SeaLoong/koishi-plugin-18xx.git"
19
+ },
20
+ "keywords": [
21
+ "koishi",
22
+ "18xxgames",
23
+ "webhook"
24
+ ],
25
+ "devDependencies": {
26
+ "@koishijs/plugin-adapter-onebot": "^6.0.2",
27
+ "@koishijs/plugin-server": "^3.2.7",
28
+ "typescript": "^5.8.3"
29
+ },
30
+ "peerDependencies": {
31
+ "koishi": "^4.18.7",
32
+ "@satorijs/element": "^3.1.8"
33
+ },
34
+ "koishi": {
35
+ "description": {
36
+ "en": "18xxGames Bot",
37
+ "zh": "18xxGames 机器人"
38
+ },
39
+ "service": {
40
+ "required": [
41
+ "server",
42
+ "database"
43
+ ]
44
+ },
45
+ "locales": [
46
+ "en",
47
+ "zh"
48
+ ]
49
+ }
50
+ }
package/readme.md ADDED
@@ -0,0 +1,5 @@
1
+ # koishi-plugin-18xx
2
+
3
+ [![npm](https://img.shields.io/npm/v/koishi-plugin-18xx?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-18xx)
4
+
5
+ 18xxGames 机器人