@kotori-bot/kotori-plugin-adapter-onebot
Version:
Adapter For Onebot 11
270 lines (269 loc) • 10.4 kB
JavaScript
/**
* @Package @kotori-bot/kotori-plugin-adapter-onebot
* @Version 2.1.1
* @Author Hotaru <me@hotaru.icu>
* @Copyright 2024-2025 Hotaru. All rights reserved.
* @License GPL-3.0
* @Link https://github.com/kotorijs/kotori
* @Date 2026/2/14 21:24:52
*/
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var adapter_exports = {};
__export(adapter_exports, {
OnebotAdapter: () => OnebotAdapter,
config: () => config,
default: () => adapter_default
});
module.exports = __toCommonJS(adapter_exports);
var import_kotori_bot = require("kotori-bot");
var import_ws = __toESM(require("ws"));
var import_api = __toESM(require("./api"));
var import_elements = __toESM(require("./elements"));
const config = import_kotori_bot.Tsu.Union(
import_kotori_bot.Tsu.Object({
mode: import_kotori_bot.Tsu.Literal("ws").describe("Connect mode: WebSocket"),
port: import_kotori_bot.Tsu.Number().port().describe("WebSocket server port"),
address: import_kotori_bot.Tsu.String().regexp(/^ws(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$/).default("ws://127.0.0.1").describe("WebSocket address"),
retry: import_kotori_bot.Tsu.Number().int().min(1).default(10).describe("try reconnect times when disconnected")
}),
import_kotori_bot.Tsu.Object({
mode: import_kotori_bot.Tsu.Literal("ws-reverse").describe("Connect mode: WebSocket Reverse")
})
);
const handleMsg = (msg) => msg.replace(/\[CQ:at,qq=(.*?)\]/g, "$1");
class OnebotAdapter extends import_kotori_bot.Adapters.WebSocket {
address;
isReverse;
config;
elements;
api;
platform = "onebot";
pendingRequests = /* @__PURE__ */ new Map();
constructor(ctx, config2, identity) {
super(ctx, config2, identity);
this.config = config2;
this.api = new import_api.default(this);
this.elements = new import_elements.default(this);
this.address = this.config.mode === "ws" ? `${this.config.address ?? "ws://127.0.0.1"}:${this.config.port}` : "";
this.isReverse = !this.address;
if (!this.isReverse) return;
this.connection = (ws) => {
this.socket = ws;
this.online();
};
}
handle(data) {
if ("echo" in data) {
if (!this.pendingRequests.has(data.echo)) return;
const { resolve, reject, timer } = this.pendingRequests.get(data.echo);
clearTimeout(timer);
this.pendingRequests.delete(data.echo);
if (data.status === "ok") {
resolve(data.data);
} else {
reject(data);
}
return;
}
if (data.post_type === "message" && data.message_type === "private") {
this.session("on_message", {
type: import_kotori_bot.MessageScope.PRIVATE,
userId: String(data.user_id),
messageId: String(data.message_id),
message: handleMsg(data.raw_message),
messageAlt: data.raw_message,
sender: {
nickname: data.sender.nickname
},
groupId: String(data.group_id),
time: data.time
});
} else if (data.post_type === "message" && data.message_type === "group") {
this.session("on_message", {
type: import_kotori_bot.MessageScope.GROUP,
userId: String(data.user_id),
messageId: String(data.message_id),
message: handleMsg(data.raw_message),
messageAlt: data.raw_message,
sender: {
nickname: data.sender.nickname,
role: data.sender.role ?? "member"
},
groupId: String(data.group_id),
time: data.time
});
} else if (data.post_type === "notice" && data.notice_type === "private_recall") {
this.session("on_message_delete", {
type: import_kotori_bot.MessageScope.PRIVATE,
userId: String(data.user_id),
messageId: String(data.message_id),
time: data.time
});
} else if (data.post_type === "notice" && data.notice_type === "group_recall") {
this.session("on_message_delete", {
type: import_kotori_bot.MessageScope.GROUP,
userId: String(data.user_id),
messageId: String(data.message_id),
groupId: String(data.group_id),
operatorId: String(data.user_id),
time: data.time
});
} else if (data.post_type === "request" && data.request_type === "private") {
this.session("on_request", {
type: import_kotori_bot.MessageScope.PRIVATE,
userId: String(data.user_id),
comment: String(data.comment),
time: data.time,
approve: (approve = true, remark = "") => this.call("set_friend_add_request", { flag: data.flag, approve, remark })
});
} else if (data.post_type === "request" && data.request_type === "group") {
this.session("on_request", {
type: import_kotori_bot.MessageScope.GROUP,
userId: String(data.user_id),
groupId: String(data.group_id),
operatorId: String(data.operator_id) || String(data.user_id),
comment: String(data.comment),
approve: (approve = true, reason = "") => this.call("set_friend_add_request", { flag: data.flag, approve, reason, type: data.sub_type }),
time: data.time
});
} else if (data.post_type === "notice" && data.notice_type === "group_increase") {
this.session("on_group_increase", {
type: import_kotori_bot.MessageScope.GROUP,
userId: String(data.user_id),
groupId: String(data.group_id),
operatorId: String(data.operator_id) ?? String(data.user_id),
time: data.time
});
} else if (data.post_type === "notice" && data.notice_type === "group_decrease") {
this.session("on_group_decrease", {
type: import_kotori_bot.MessageScope.GROUP,
userId: String(data.user_id),
groupId: String(data.group_id),
operatorId: String(data.operator_id) ?? String(data.user_id),
time: data.time
});
} else if (data.post_type === "notice" && data.notice_type === "group_admin") {
this.session("on_group_admin", {
type: import_kotori_bot.MessageScope.GROUP,
userId: String(data.user_id),
groupId: String(data.group_id),
operation: data.sub_type === "set" ? "set" : "unset",
time: data.time
});
} else if (data.post_type === "notice" && data.notice_type === "group_ban") {
this.session("on_group_ban", {
type: import_kotori_bot.MessageScope.GROUP,
userId: String(data.user_id),
groupId: String(data.group_id),
operatorId: String(data.operator_id),
duration: Number(data.duration),
time: data.time
});
} else if (data.post_type === "meta_event" && data.meta_event_type === "heartbeat") {
if (data.status.online) {
this.online();
if (this.onlineTimerId) clearTimeout(this.onlineTimerId);
}
if (this.selfId === "" && typeof data.self_id === "number") {
this.selfId = String(data.self_id);
}
} else if (data.post_type === "notice" && data.notice_type === "notify" && data.sub_type === "poke" && data.target_id) {
this.session("onebot_poke", {
type: data.message_type === "private" ? import_kotori_bot.MessageScope.PRIVATE : import_kotori_bot.MessageScope.GROUP,
userId: String(data.user_id),
targetId: String(data.target_id),
groupId: String(data.group_id),
time: data.time
});
}
if (!this.onlineTimerId) this.onlineTimerId = setTimeout(() => this.offline(), 50 * 1e3);
}
start() {
if (this.isReverse) {
this.setup();
return;
}
this.ctx.emit("connect", {
type: "connect",
mode: "ws",
adapter: this,
normal: true,
address: this.address
});
this.socket = new import_ws.default(`${this.address}`);
this.socket.on("close", () => {
this.ctx.emit("connect", {
type: "disconnect",
adapter: this,
normal: false,
mode: "ws",
address: this.address
});
});
this.socket.on("message", (raw) => this.handle(JSON.parse(raw.toString())));
}
stop() {
if (this.isReverse) {
super.stop();
return;
}
this.ctx.emit("connect", {
type: "disconnect",
adapter: this,
normal: true,
address: this.address,
mode: "ws"
});
this.socket?.close();
}
send(content, operation) {
this.socket?.send(JSON.stringify({ content, operation }));
}
call(action, params) {
return new Promise((resolve, reject) => {
const echo = `${Date.now()}_${Math.random().toString(36)}`;
const timer = setTimeout(() => {
this.pendingRequests.delete(echo);
reject(new import_kotori_bot.KotoriError(`Request timeout: ${action}`));
}, 60 * 1e3);
this.pendingRequests.set(echo, { resolve, reject, timer });
this.socket?.send(JSON.stringify({ action, params, echo }));
});
}
socket = null;
/* global NodeJS */
onlineTimerId = null;
}
var adapter_default = OnebotAdapter;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
OnebotAdapter,
config
});