@satorijs/core
Version:
Core components of Satorijs
906 lines (896 loc) • 28.2 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// src/index.ts
import { Context as Context4, Logger as Logger2, Service as Service4, z as z2 } from "cordis";
import { defineProperty as defineProperty2 } from "cosmokit";
// src/internal.ts
import { Service } from "cordis";
import { remove, valueMap } from "cosmokit";
import { pathToRegexp } from "path-to-regexp";
var InternalRouter = class {
constructor(ctx) {
this.ctx = ctx;
}
static {
__name(this, "InternalRouter");
}
[Service.tracker] = {
property: "ctx"
};
routes = [];
define(path, callback) {
return this.ctx.effect(() => {
const route = {
...pathToRegexp(path),
callback
};
this.routes.push(route);
return () => remove(this.routes, route);
});
}
handle(bot, method, path, query, headers, body) {
for (const route of this.routes) {
const capture = route.regexp.exec(path);
if (!capture) continue;
const params = {};
route.keys.forEach(({ name }, index) => {
params[name] = capture[index + 1];
});
return route.callback({
bot,
method,
params,
query,
body,
headers: Object.fromEntries(headers.entries())
});
}
}
};
var JsonForm;
((JsonForm2) => {
function load(data, path, form) {
const value = form.get(path);
if (value instanceof File) return value;
if (!data || typeof data !== "object") return data;
if (Array.isArray(data)) {
return data.map((value2, index) => load(value2, `${path}.${index}`, form));
}
return valueMap(data, (value2, key) => {
return load(value2, `${path}.${key}`, form);
});
}
JsonForm2.load = load;
__name(load, "load");
function dump(data, path, form) {
if (!data || typeof data !== "object") return data;
if (data instanceof Blob) {
form.append(path, data);
return null;
}
if (Array.isArray(data)) {
return data.map((value, index) => dump(value, `${path}.${index}`, form));
}
return valueMap(data, (value, key) => {
return dump(value, `${path}.${key}`, form);
});
}
JsonForm2.dump = dump;
__name(dump, "dump");
async function decode(body) {
const type = body.headers.get("content-type");
if (type?.startsWith("multipart/form-data")) {
const response = new globalThis.Response(body.body, { headers: body.headers });
const form = await response.formData();
const json = form.get("$");
return load(JSON.parse(json), "$", form);
} else if (type?.startsWith("application/json")) {
return JSON.parse(new TextDecoder().decode(body.body));
} else {
throw new Error(`Unsupported content type: ${type}`);
}
}
JsonForm2.decode = decode;
__name(decode, "decode");
async function encode(data) {
const form = new FormData();
const json = JSON.stringify(JsonForm2.dump(data, "$", form));
if ([...form.entries()].length) {
form.append("$", json);
const request = new Request("stub:", {
method: "POST",
body: form
});
return {
body: await request.arrayBuffer(),
headers: request.headers
};
} else {
const body = new TextEncoder().encode(json).buffer;
const headers = new Headers({
"content-type": "application/json"
});
return { body, headers };
}
}
JsonForm2.encode = encode;
__name(encode, "encode");
})(JsonForm || (JsonForm = {}));
// src/index.ts
import { HTTP } from "@cordisjs/plugin-http";
import h3 from "@satorijs/element";
export * from "cordis";
export * from "cosmokit";
import * as Universal from "@satorijs/protocol";
// src/bot.ts
import { clone as clone2, isNonNullable, pick } from "cosmokit";
import { Service as Service3 } from "cordis";
// src/session.ts
import { Channel, Resource } from "@satorijs/protocol";
import { clone, defineProperty, isNullable } from "cosmokit";
import { Context, Service as Service2 } from "cordis";
import h from "@satorijs/element";
var Session = class {
static {
__name(this, "Session");
}
[Service2.tracker] = {
associate: "session",
property: "ctx"
};
id;
// for backward compatibility
sn;
bot;
app;
event;
locales = [];
constructor(bot, event) {
event.selfId ??= bot.selfId;
event.platform ??= bot.platform;
event.timestamp ??= Date.now();
this.event = event;
this.sn = this.id = ++bot.ctx.satori._sessionSeq;
defineProperty(this, "bot", bot);
defineProperty(this, "app", bot.ctx.root);
defineProperty(this, Context.current, bot.ctx);
return Context.associate(this, "session");
}
/** @deprecated */
get data() {
return this.event;
}
get isDirect() {
return this.event.channel?.type === Channel.Type.DIRECT;
}
set isDirect(value) {
(this.event.channel ??= {}).type = value ? Channel.Type.DIRECT : Channel.Type.TEXT;
}
get author() {
return {
...this.event.user,
...this.event.member,
userId: this.event.user?.id,
username: this.event.user?.name,
nickname: this.event.member?.name
};
}
get uid() {
return `${this.platform}:${this.userId}`;
}
get gid() {
return `${this.platform}:${this.guildId}`;
}
get cid() {
return `${this.platform}:${this.channelId}`;
}
get fid() {
return `${this.platform}:${this.channelId}:${this.userId}`;
}
get sid() {
return `${this.platform}:${this.selfId}`;
}
get elements() {
return this.event.message?.elements;
}
set elements(value) {
this.event.message ??= {};
this.event.message.elements = value;
}
get content() {
return this.event.message?.elements?.join("");
}
set content(value) {
this.event.message ??= {};
this.event.message.quote = void 0;
this.event.message.elements = isNullable(value) ? value : h.parse(value);
if (this.event.message.elements?.[0]?.type === "quote") {
const el = this.event.message.elements.shift();
this.event.message.quote = Resource.decode(el);
}
}
setInternal(type, data) {
this.event._type = type;
this.event._data = data;
const internal = Object.create(this.bot.internal);
defineProperty(this, type, Object.assign(internal, data));
}
async transform(elements) {
return await h.transformAsync(elements, async ({ type, attrs, children }, session) => {
const render = type === "component" ? attrs.is : this.app.get("component:" + type);
if (!render) return true;
children = await render(attrs, children, session);
return this.transform(h.toElementArray(children));
}, this);
}
toJSON() {
const event = {
...clone(this.event),
sn: this.sn,
login: this.bot.toJSON(),
["id"]: this.sn
// for backward compatibility
};
if (event.message?.elements) {
event.message.content = this.content;
delete event.message.elements;
if (event.message.quote) {
event.message.content = Resource.encode("quote", event.message.quote) + event.message.content;
}
}
return event;
}
};
function defineAccessor(prototype, name, keys) {
Object.defineProperty(prototype, name, {
get() {
return keys.reduce((data, key) => data?.[key], this);
},
set(value) {
if (value === void 0) return;
const _keys = keys.slice();
const last = _keys.pop();
const data = _keys.reduce((data2, key) => data2[key] ??= {}, this);
data[last] = value;
}
});
}
__name(defineAccessor, "defineAccessor");
defineAccessor(Session.prototype, "type", ["event", "type"]);
defineAccessor(Session.prototype, "subtype", ["event", "subtype"]);
defineAccessor(Session.prototype, "subsubtype", ["event", "subsubtype"]);
defineAccessor(Session.prototype, "selfId", ["event", "selfId"]);
defineAccessor(Session.prototype, "platform", ["event", "platform"]);
defineAccessor(Session.prototype, "timestamp", ["event", "timestamp"]);
defineAccessor(Session.prototype, "userId", ["event", "user", "id"]);
defineAccessor(Session.prototype, "channelId", ["event", "channel", "id"]);
defineAccessor(Session.prototype, "channelName", ["event", "channel", "name"]);
defineAccessor(Session.prototype, "guildId", ["event", "guild", "id"]);
defineAccessor(Session.prototype, "guildName", ["event", "guild", "name"]);
defineAccessor(Session.prototype, "messageId", ["event", "message", "id"]);
defineAccessor(Session.prototype, "operatorId", ["event", "operator", "id"]);
defineAccessor(Session.prototype, "roleId", ["event", "role", "id"]);
defineAccessor(Session.prototype, "quote", ["event", "message", "quote"]);
defineAccessor(Session.prototype, "referrer", ["event", "referrer"]);
// src/bot.ts
import { Methods, Status } from "@satorijs/protocol";
var eventAliases = [
["message-created", "message"],
["guild-removed", "guild-deleted"],
["guild-member-removed", "guild-member-deleted"]
];
var Bot = class {
constructor(ctx, config, adapterName) {
this.ctx = ctx;
this.config = config;
this.adapterName = adapterName;
this.sn = ++ctx.satori._loginSeq;
this.internal = null;
this._internalRouter = new InternalRouter(ctx);
this.context = ctx;
ctx.bots.push(this);
this.context.emit("bot-added", this);
this.logger = ctx.logger(adapterName);
this.platform = adapterName;
this.features = Object.entries(Methods).filter(([, value]) => this[value.name]).map(([key]) => key);
ctx.on("ready", async () => {
await Promise.resolve();
this.dispatchLoginEvent("login-added");
return this.start();
});
ctx.on("dispose", () => this.dispose());
ctx.on("interaction/button", (session) => {
const cb = this.callbacks[session.event.button.id];
if (cb) cb(session);
});
}
static {
__name(this, "Bot");
}
static reusable = true;
static MessageEncoder;
[Service3.tracker] = {
associate: "bot",
property: "ctx"
};
sn;
user;
platform;
features;
hidden = false;
adapter;
error;
callbacks = {};
logger;
_internalRouter;
// Same as `this.ctx`, but with a more specific type.
context;
_status = Status.OFFLINE;
getInternalUrl(path, init, slash) {
let search = new URLSearchParams(init).toString();
if (search) search = "?" + search;
return `internal${slash ? "/" : ":"}${this.platform}/${this.selfId}${path}${search}`;
}
defineInternalRoute(path, callback) {
return this._internalRouter.define(path, callback);
}
update(login) {
const { sn, status, ...rest } = login;
Object.assign(this, rest);
this.status = status;
}
dispose() {
const index = this.ctx.bots.findIndex((bot) => bot.sid === this.sid);
if (index >= 0) {
this.ctx.bots.splice(index, 1);
this.context.emit("bot-removed", this);
this.dispatchLoginEvent("login-removed");
}
return this.stop();
}
dispatchLoginEvent(type) {
const session = this.session();
session.type = type;
session.event.login = this.toJSON();
this.dispatch(session);
}
get status() {
return this._status;
}
set status(value) {
if (value === this._status) return;
this._status = value;
if (this.ctx.bots?.some((bot) => bot.sid === this.sid)) {
this.context.emit("bot-status-updated", this);
this.dispatchLoginEvent("login-updated");
}
}
get isActive() {
return this._status !== Status.OFFLINE && this._status !== Status.DISCONNECT;
}
online() {
this.status = Status.ONLINE;
this.error = void 0;
}
offline(error) {
this.status = Status.OFFLINE;
this.error = error;
}
async start() {
if (this.isActive) return;
this.status = Status.CONNECT;
try {
await this.context.parallel("bot-connect", this);
await this.adapter?.connect(this);
} catch (error) {
this.offline(error);
}
}
async stop() {
if (!this.isActive) return;
this.status = Status.DISCONNECT;
try {
await this.context.parallel("bot-disconnect", this);
await this.adapter?.disconnect(this);
} catch (error) {
this.context.emit(this.ctx, "internal/error", error);
} finally {
this.offline();
}
}
get sid() {
return `${this.platform}:${this.selfId}`;
}
session(event = {}) {
return new Session(this, event);
}
dispatch(session) {
if (!this.ctx.lifecycle.isActive) return;
let events = [session.type];
for (const aliases of eventAliases) {
if (aliases.includes(session.type)) {
events = aliases;
session.type = aliases[0];
break;
}
}
this.context.emit("internal/session", session);
if (session.type === "internal") {
this.context.emit(session.event._type, session.event._data, session.bot);
return;
}
for (const event of events) {
this.context.emit(session, event, session);
}
}
async createMessage(channelId, content, referrer, options) {
const { MessageEncoder: MessageEncoder2 } = this.constructor;
return new MessageEncoder2(this, channelId, referrer, options).send(content);
}
async sendMessage(channelId, content, referrer, options) {
const messages = await this.createMessage(channelId, content, referrer, options);
return messages.map((message) => message.id).filter(isNonNullable);
}
async sendPrivateMessage(userId, content, guildId, options) {
const { id } = await this.createDirectChannel(userId, guildId ?? options?.session?.guildId);
return this.sendMessage(id, content, null, options);
}
async createUpload(...uploads) {
const ids = [];
for (const upload of uploads) {
const id = Math.random().toString(36).slice(2);
const headers = new Headers();
headers.set("content-type", upload.type);
if (upload.filename) {
headers.set("content-disposition", `attachment; filename*=UTF-8''${encodeURIComponent(upload.filename)}`);
}
this.ctx.satori._tempStore[id] = {
status: 200,
body: upload.data,
headers
};
ids.push(id);
}
const timer = setTimeout(() => dispose(), 6e5);
const dispose = /* @__PURE__ */ __name(() => {
_dispose();
clearTimeout(timer);
for (const id of ids) {
delete this.ctx.satori._tempStore[id];
}
}, "dispose");
const _dispose = this.ctx.on("dispose", dispose);
return ids.map((id) => this.getInternalUrl(`/_tmp/${id}`));
}
async supports(name, session = {}) {
return !!this[Methods[name]?.name];
}
async checkPermission(name, session) {
if (name.startsWith("bot.")) {
return this.supports(name.slice(4), session);
}
}
toJSON() {
return clone2({
...pick(this, ["sn", "user", "platform", "selfId", "status", "hidden", "features"]),
adapter: this.adapterName
});
}
async getLogin() {
return this.toJSON();
}
/** @deprecated use `bot.getLogin()` instead */
async getSelf() {
const { user } = await this.getLogin();
return user;
}
};
var iterableMethods = [
"getMessage",
"getReaction",
"getFriend",
"getGuild",
"getGuildMember",
"getGuildRole",
"getChannel"
];
for (const name of iterableMethods) {
Bot.prototype[name + "Iter"] = function(...args) {
let list;
if (!this[name + "List"]) throw new Error(`not implemented: ${name}List`);
const getList = /* @__PURE__ */ __name(async () => {
list = await this[name + "List"](...args, list?.next);
if (name === "getMessage") list.data.reverse();
}, "getList");
return {
async next() {
if (list?.data.length) return { done: false, value: list.data.shift() };
if (list && !list?.next) return { done: true, value: void 0 };
await getList();
return this.next();
},
[Symbol.asyncIterator]() {
return this;
}
};
};
}
defineAccessor(Bot.prototype, "selfId", ["user", "id"]);
defineAccessor(Bot.prototype, "userId", ["user", "id"]);
// src/adapter.ts
import { remove as remove2, Time } from "cosmokit";
import { Status as Status2 } from "@satorijs/protocol";
import { z } from "cordis";
var Adapter = class {
constructor(ctx) {
this.ctx = ctx;
}
static {
__name(this, "Adapter");
}
static schema = false;
bots = [];
async connect(bot) {
}
async disconnect(bot) {
}
fork(ctx, bot) {
bot.adapter = this;
this.bots.push(bot);
ctx.on("dispose", () => {
remove2(this.bots, bot);
});
}
};
((Adapter2) => {
Adapter2.WsClientConfig = z.object({
retryTimes: z.natural().description("初次连接时的最大重试次数。").default(6),
retryInterval: z.natural().role("ms").description("初次连接时的重试时间间隔。").default(5 * Time.second),
retryLazy: z.natural().role("ms").description("连接关闭后的重试时间间隔。").default(Time.minute)
}).description("连接设置");
class WsClientBase extends Adapter2 {
constructor(ctx, config) {
super(ctx);
this.config = config;
}
static {
__name(this, "WsClientBase");
}
socket;
connectionId = 0;
async start() {
let retryCount = 0;
const connectionId = ++this.connectionId;
const logger = this.ctx.logger("adapter");
const { retryTimes, retryInterval, retryLazy } = this.config;
const reconnect = /* @__PURE__ */ __name((initial, message) => {
if (!this.getActive() || connectionId !== this.connectionId) return;
let timeout = retryInterval;
if (retryCount >= retryTimes) {
if (initial) {
return this.setStatus(Status2.OFFLINE, new Error(message));
} else {
timeout = retryLazy;
}
}
retryCount++;
this.setStatus(Status2.RECONNECT);
logger.warn(`${message}, will retry in ${Time.format(timeout)}...`);
setTimeout(() => {
if (!this.getActive() || connectionId !== this.connectionId) return;
connect();
}, timeout);
}, "reconnect");
const connect = /* @__PURE__ */ __name(async (initial = false) => {
logger.debug("websocket client opening");
let socket;
try {
socket = await this.prepare();
} catch (error) {
reconnect(initial, error.toString() || `failed to prepare websocket`);
return;
}
const url = socket.url.replace(/\?.+/, "");
socket.addEventListener("error", (event) => {
if (event.message) logger.warn(event.message);
});
socket.addEventListener("close", ({ code, reason }) => {
if (this.socket === socket) this.socket = void 0;
logger.debug(`websocket closed with ${code}`);
reconnect(initial, reason.toString() || `failed to connect to ${url}, code: ${code}`);
});
socket.addEventListener("open", () => {
retryCount = 0;
this.socket = socket;
logger.info("connect to server: %c", url);
this.accept(socket);
});
}, "connect");
connect(true);
}
async stop() {
this.socket?.close();
}
}
Adapter2.WsClientBase = WsClientBase;
class WsClient extends WsClientBase {
constructor(ctx, bot) {
super(ctx, bot.config);
this.bot = bot;
bot.adapter = this;
}
static {
__name(this, "WsClient");
}
static reusable = true;
getActive() {
return this.bot.isActive;
}
setStatus(status, error) {
this.bot.status = status;
this.bot.error = error;
}
async connect(bot) {
this.start();
}
async disconnect(bot) {
this.stop();
}
}
Adapter2.WsClient = WsClient;
})(Adapter || (Adapter = {}));
// src/message.ts
import h2 from "@satorijs/element";
var AggregateError = class extends Error {
constructor(errors, message = "") {
super(message);
this.errors = errors;
}
static {
__name(this, "AggregateError");
}
};
var MessageEncoder = class {
constructor(bot, channelId, referrer, options = {}) {
this.bot = bot;
this.channelId = channelId;
this.referrer = referrer;
this.options = options;
}
static {
__name(this, "MessageEncoder");
}
errors = [];
results = [];
session;
async prepare() {
}
async render(elements, flush) {
for (const element of elements) {
await this.visit(element);
}
if (flush) {
await this.flush();
}
}
async send(content) {
this.session = this.bot.session({
type: "send",
channel: { id: this.channelId, ...this.options.session?.event.channel },
guild: this.options.session?.event.guild
});
for (const key in this.options.session || {}) {
if (key === "id" || key === "event") continue;
this.session[key] = this.options.session[key];
}
await this.prepare();
const session = this.options.session ?? this.session;
this.session.elements = await session.transform(h2.normalize(content));
const btns = h2.select(this.session.elements, "button").filter((v) => v.attrs.type !== "link" && !v.attrs.id);
for (const btn of btns) {
const r = Math.random().toString(36).slice(2);
btn.attrs.id ||= r;
if (typeof btn.attrs.action === "function") this.bot.callbacks[btn.attrs.id] = btn.attrs.action;
}
if (await this.session.app.serial(this.session, "before-send", this.session, this.options)) return [];
await this.render(this.session.elements);
await this.flush();
if (this.errors.length) {
throw new AggregateError(this.errors);
} else {
return this.results;
}
}
};
// src/index.ts
h3.warn = new Logger2("element").warn;
HTTP.createConfig = /* @__PURE__ */ __name(function createConfig(endpoint) {
return z2.object({
endpoint: z2.string().role("link").description("要连接的服务器地址。").default(typeof endpoint === "string" ? endpoint : void 0).required(typeof endpoint === "boolean" ? endpoint : false),
headers: z2.dict(String).role("table").description("要附加的额外请求头。"),
...this.Config.dict
}).description("请求设置");
}, "createConfig");
var SatoriContext = class extends Context4 {
static {
__name(this, "SatoriContext");
}
constructor(config) {
super(config);
this.provide("satori", void 0, true);
this.plugin(Satori);
}
};
var DisposableSet = class {
constructor(ctx) {
this.ctx = ctx;
defineProperty2(this, Service4.tracker, {
property: "ctx"
});
}
static {
__name(this, "DisposableSet");
}
sn = 0;
map1 = /* @__PURE__ */ new Map();
map2 = /* @__PURE__ */ new Map();
add(...values) {
const sn = ++this.sn;
return this.ctx.effect(() => {
let hasUpdate = false;
for (const value of values) {
if (!this.map2.has(value)) {
this.map2.set(value, /* @__PURE__ */ new Set());
hasUpdate = true;
}
this.map2.get(value).add(sn);
}
this.map1.set(sn, values);
if (hasUpdate) this.ctx.emit("satori/meta");
return () => {
let hasUpdate2 = false;
this.map1.delete(sn);
for (const value of values) {
this.map2.get(value).delete(sn);
if (this.map2.get(value).size === 0) {
this.map2.delete(value);
hasUpdate2 = true;
}
}
if (hasUpdate2) this.ctx.emit("satori/meta");
};
});
}
[Symbol.iterator]() {
return new Set([].concat(...this.map1.values()))[Symbol.iterator]();
}
};
var Satori = class extends Service4 {
static {
__name(this, "Satori");
}
static [Service4.provide] = "satori";
static [Service4.immediate] = true;
uid = Math.random().toString(36).slice(2);
proxyUrls = new DisposableSet(this.ctx);
_internalRouter;
_tempStore = /* @__PURE__ */ Object.create(null);
_loginSeq = 0;
_sessionSeq = 0;
constructor(ctx) {
super(ctx);
ctx.mixin("satori", ["bots", "component"]);
defineProperty2(this.bots, Service4.tracker, {});
const self = this;
ctx.on("http/file", async function(_url, options) {
const url = new URL(_url);
if (url.protocol !== "internal:") return;
const { status, body, headers } = await self.handleInternalRoute("GET", url);
if (status >= 400) throw new Error(`Failed to fetch ${_url}, status code: ${status}`);
if (status >= 300) {
const location = headers?.get("location");
return this.file(location, options);
}
const type = headers?.get("content-type");
const filename = headers?.get("content-disposition")?.split("filename=")[1];
return { data: body, filename, type, mime: type };
});
this._internalRouter = new InternalRouter(ctx);
this.defineInternalRoute("/_tmp/:id", async ({ params, method }) => {
if (method !== "GET") return { status: 405 };
return this._tempStore[params.id] ?? { status: 404 };
});
this.defineInternalRoute("/_api/:name", async ({ bot, headers, params, method, body }) => {
if (method !== "POST") return { status: 405 };
const args = await JsonForm.decode({ body, headers: new Headers(headers) });
if (!args) return { status: 400 };
try {
let root = bot.internal;
for (const part of params.name.split(".")) {
root = root[part];
}
let result = root(...args);
if (headers["satori-pagination"]) {
if (!result?.[Symbol.for("satori.pagination")]) {
return { status: 400, statusText: "This API does not support pagination" };
}
result = await result[Symbol.for("satori.pagination")]();
} else {
result = await result;
}
return { ...await JsonForm.encode(result), status: 200 };
} catch (error) {
if (!ctx.http.isError(error) || !error.response) throw error;
return error.response;
}
});
}
bots = new Proxy([], {
get(target, prop) {
if (prop in target || typeof prop === "symbol") {
return Reflect.get(target, prop);
}
return target.find((bot) => bot.sid === prop);
},
deleteProperty(target, prop) {
if (prop in target || typeof prop === "symbol") {
return Reflect.deleteProperty(target, prop);
}
const bot = target.findIndex((bot2) => bot2.sid === prop);
if (bot < 0) return true;
target.splice(bot, 1);
return true;
}
});
component(name, component, options = {}) {
const render = /* @__PURE__ */ __name(async (attrs, children, session) => {
if (options.session && session.type === "send") {
throw new Error("interactive components is not available outside sessions");
}
const result = await component(attrs, children, session);
return session.transform(h3.normalize(result));
}, "render");
return this.ctx.set("component:" + name, render);
}
defineInternalRoute(path, callback) {
return this._internalRouter.define(path, callback);
}
async handleInternalRoute(method, url, headers = new Headers(), body) {
const capture = /^([^/]+)\/([^/]+)(\/.+)$/.exec(url.pathname);
if (!capture) return { status: 400 };
const [, platform, selfId, path] = capture;
const bot = this.bots[`${platform}:${selfId}`];
if (!bot) return { status: 404 };
let response = await this._internalRouter.handle(bot, method, path, url.searchParams, headers, body);
response ??= await bot._internalRouter.handle(bot, method, path, url.searchParams, headers, body);
if (!response) return { status: 404 };
return response;
}
toJSON(meta = false) {
return {
logins: meta ? void 0 : this.bots.map((bot) => bot.toJSON()),
proxyUrls: [...this.proxyUrls]
};
}
};
var index_default = Satori;
export {
Adapter,
Bot,
SatoriContext as Context,
h3 as Element,
HTTP,
InternalRouter,
JsonForm,
MessageEncoder,
MessageEncoder as Messenger,
MessageEncoder as Modulator,
HTTP as Quester,
Satori,
Session,
Universal,
index_default as default,
defineAccessor,
h3 as h,
h3 as segment
};