koishi-core
Version:
Core features for Koishi
780 lines (779 loc) • 33.8 kB
TypeScript
/// <reference types="lru-cache" />
/// <reference types="node" />
/// <reference types="koa__router" />
/// <reference types="ws" />
import * as utils from 'koishi-utils';
import { Observed, Logger } from 'koishi-utils';
import LruCache from 'lru-cache';
import { AxiosRequestConfig } from 'axios';
import { Server } from 'http';
import { inspect } from 'util';
import Router from '@koa/router';
import WebSocket from 'ws';
export type TableType = keyof Tables;
export interface Tables {
user: User;
channel: Channel;
}
export namespace Tables {
type IndexType = string | number;
type IndexKeys<O, T = any> = string & {
[K in keyof O]: O[K] extends T ? K : never;
}[keyof O];
type QueryMap<O> = {
[K in keyof O]?: O[K][];
};
export type Index<T extends TableType> = IndexKeys<Tables[T], IndexType>;
export type Query<T extends TableType> = IndexType[] | QueryMap<Tables[T]>;
export type Field<T extends TableType> = string & keyof Tables[T];
interface Meta<O> {
primary?: keyof O;
unique?: (keyof O)[];
type?: 'incremental';
}
export const config: {
[T in TableType]?: Meta<Tables[T]>;
};
export function extend<T extends TableType>(name: T, meta?: Meta<Tables[T]>): void;
export function resolveQuery<T extends TableType>(name: T, query: Query<T>): Record<string, any[]>;
export {};
}
export interface User extends Record<Platform, string> {
id: string;
flag: number;
authority: number;
name: string;
usage: Record<string, number>;
timers: Record<string, number>;
}
export namespace User {
export enum Flag {
ignore = 1
}
export type Field = keyof User;
export const fields: Field[];
export type Index = Platform | 'name' | 'id';
export type Observed<K extends Field = Field> = utils.Observed<Pick<User, K>, Promise<void>>;
type Getter = <T extends Index>(type: T, id: string) => Partial<User>;
export function extend(getter: Getter): void;
export function create<T extends Index>(type: T, id: string): User;
export {};
}
export interface Channel {
id: string;
flag: number;
assignee: string;
disable: string[];
}
export namespace Channel {
export enum Flag {
ignore = 1,
silent = 4
}
export type Field = keyof Channel;
export const fields: Field[];
export type Observed<K extends Field = Field> = utils.Observed<Pick<Channel, K>, Promise<void>>;
type Getter = (type: Platform, id: string) => Partial<Channel>;
export function extend(getter: Getter): void;
export function create(type: Platform, id: string): Channel;
export {};
}
type MaybeArray<T> = T | T[];
export interface Database {
get<T extends TableType, F extends Tables.Field<T>>(table: T, query: Tables.Query<T>, fields?: readonly F[]): Promise<Pick<Tables[T], F>[]>;
remove<T extends TableType>(table: T, query: Tables.Query<T>): Promise<void>;
create<T extends TableType>(table: T, data: Partial<Tables[T]>): Promise<Tables[T]>;
update<T extends TableType>(table: T, data: Partial<Tables[T]>[], key?: Tables.Index<T>): Promise<void>;
getUser<K extends User.Field, T extends User.Index>(type: T, id: string, fields?: readonly K[]): Promise<Pick<User, K | T>>;
getUser<K extends User.Field, T extends User.Index>(type: T, ids: readonly string[], fields?: readonly K[]): Promise<Pick<User, K | T>[]>;
setUser<T extends User.Index>(type: T, id: string, data: Partial<User>): Promise<void>;
createUser<T extends User.Index>(type: T, id: string, data: Partial<User>): Promise<void>;
removeUser<T extends User.Index>(type: T, id: string): Promise<void>;
getChannel<K extends Channel.Field>(type: Platform, id: string, fields?: readonly K[]): Promise<Pick<Channel, K | 'id'>>;
getChannel<K extends Channel.Field>(type: Platform, ids: readonly string[], fields?: readonly K[]): Promise<Pick<Channel, K | 'id'>[]>;
getChannel<K extends Channel.Field>(type: Platform, id: MaybeArray<string>, fields?: readonly K[]): Promise<any>;
getAssignedChannels<K extends Channel.Field>(fields?: readonly K[], assignMap?: Record<string, readonly string[]>): Promise<Pick<Channel, K>[]>;
setChannel(type: Platform, id: string, data: Partial<Channel>): Promise<void>;
createChannel(type: Platform, id: string, data: Partial<Channel>): Promise<void>;
removeChannel(type: Platform, id: string): Promise<void>;
}
type Methods<S, T> = {
[K in keyof S]?: S[K] extends (...args: infer R) => infer U ? (this: T, ...args: R) => U : S[K];
};
export namespace Database {
export interface Statics {
}
type Constructor<T> = new (...args: any[]) => T;
type ExtensionMethods<T> = Methods<Database, T extends Constructor<infer I> ? I : never>;
type Extension<T> = ((Database: T) => void) | ExtensionMethods<T>;
export function extend<K extends keyof Statics>(module: K, extension: Extension<Statics[K]>): void;
export function extend<T extends Constructor<unknown>>(module: T, extension: Extension<T>): void;
export {};
}
export interface Assets {
types: readonly Assets.Type[];
upload(url: string, file: string): Promise<string>;
stats(): Promise<Assets.Stats>;
}
export namespace Assets {
type Type = 'image' | 'audio' | 'video';
interface Stats {
assetCount?: number;
assetSize?: number;
}
}
export function getCommandNames(session: Session): string[];
export interface DelayOptions {
character?: number;
message?: number;
cancel?: number;
broadcast?: number;
prompt?: number;
}
export interface AppOptions extends BotOptions {
port?: number;
bots?: BotOptions[];
prefix?: string | string[];
nickname?: string | string[];
maxListeners?: number;
prettyErrors?: boolean;
processMessage?: (message: string) => string;
delay?: DelayOptions;
autoAssign?: boolean | ((session: Session) => boolean);
autoAuthorize?: number | ((session: Session) => number);
userCacheAge?: number;
userCacheLength?: number;
channelCacheLength?: number;
channelCacheAge?: number;
minSimilarity?: number;
selfUrl?: string;
axiosConfig?: AxiosRequestConfig;
}
export class App extends Context {
app: this;
options: AppOptions;
status: App.Status;
adapters: Adapter.Instances;
registry: Map<Plugin<any>, Plugin.State>;
_bots: Bot<never>[] & Record<string, Bot<never>>;
_commands: Command[];
_commandMap: Record<string, Command>;
_shortcuts: Command.Shortcut[];
_hooks: Record<keyof any, [Context, (...args: any[]) => any][]>;
_userCache: Record<string, LruCache<string, Observed<Partial<User>, Promise<void>>>>;
_channelCache: LruCache<string, Observed<Partial<Channel>, Promise<void>>>;
_httpServer?: Server;
_sessions: Record<string, Session>;
private _nameRE;
private _prefixRE;
static defaultConfig: AppOptions;
constructor(options?: AppOptions);
createServer(): void;
prepare(): void;
start(): Promise<void>;
private _listen;
stop(): Promise<void>;
private _close;
private _process;
private _suggest;
private _handleMessage;
private _handleArgv;
private _handleShortcut;
}
export namespace App {
enum Status {
closed = 0,
opening = 1,
open = 2,
closing = 3
}
}
export type NextFunction = (next?: NextFunction) => Promise<void>;
export type Middleware = (session: Session, next: NextFunction) => any;
export type Promisify<T> = T extends Promise<unknown> ? T : Promise<T>;
export type Awaitable<T> = T extends Promise<unknown> ? T : T | Promise<T>;
export type Await<T> = T extends Promise<infer U> ? U : T;
export type Disposable = () => void;
export type Plugin<T = any> = Plugin.Function<T> | Plugin.Object<T>;
export namespace Plugin {
export type Function<T = any> = (ctx: Context, options: T) => void;
export interface Meta {
name?: string;
sideEffect?: boolean;
}
export interface Object<T = any> extends Meta {
apply: Function<T>;
}
export type Config<T extends Plugin> = T extends Function<infer U> ? U : T extends Object<infer U> ? U : never;
export interface State extends Meta {
parent: State;
children: Plugin[];
disposables: Disposable[];
dependencies: Set<State>;
}
export interface Packages {
}
export type Teleporter<D extends readonly (keyof Packages)[]> = (ctx: Context, ...modules: From<D>) => void;
type From<D extends readonly unknown[]> = D extends readonly [infer L, ...infer R] ? [L extends keyof Packages ? Packages[L] : unknown, ...From<R>] : [];
export {};
}
type Filter = (session: Session) => boolean;
type PartialSeletor<T> = (...values: T[]) => Context;
interface Selector<T> extends PartialSeletor<T> {
except?: PartialSeletor<T>;
}
export class Context {
filter: Filter;
app?: App;
private _plugin;
static readonly middleware: unique symbol;
static readonly current: unique symbol;
protected _bots: Bot[] & Record<string, Bot>;
database: Database;
assets: Assets;
router: Router;
protected constructor(filter: Filter, app?: App, _plugin?: Plugin);
[inspect.custom](): string;
private createSelector;
get user(): Selector<string>;
get self(): Selector<string>;
get group(): Selector<string>;
get channel(): Selector<string>;
get platform(): Selector<never>;
get private(): Selector<string>;
get bots(): Bot<never>[] & Record<string, Bot<never>>;
logger(name: string): Logger;
select<K extends keyof Session>(key: K, ...values: Session[K][]): Context;
unselect<K extends keyof Session>(key: K, ...values: Session[K][]): Context;
all(): Context;
union(arg: Filter | Context): Context;
intersect(arg: Filter | Context): Context;
match(session?: Session): boolean;
get state(): Plugin.State;
addSideEffect(state?: Plugin.State): void;
private teleport;
with<D extends readonly (keyof Plugin.Packages)[]>(deps: D, callback: Plugin.Teleporter<D>): this;
plugin<T extends Plugin>(plugin: T, options?: Plugin.Config<T>): this;
dispose(plugin?: Plugin<any>): Promise<void>;
parallel<K extends EventName>(name: K, ...args: Parameters<EventMap[K]>): Promise<Await<ReturnType<EventMap[K]>>[]>;
parallel<K extends EventName>(session: Session, name: K, ...args: Parameters<EventMap[K]>): Promise<Await<ReturnType<EventMap[K]>>[]>;
emit<K extends EventName>(name: K, ...args: Parameters<EventMap[K]>): void;
emit<K extends EventName>(session: Session, name: K, ...args: Parameters<EventMap[K]>): void;
waterfall<K extends EventName>(name: K, ...args: Parameters<EventMap[K]>): Promisify<ReturnType<EventMap[K]>>;
waterfall<K extends EventName>(session: Session, name: K, ...args: Parameters<EventMap[K]>): Promisify<ReturnType<EventMap[K]>>;
chain<K extends EventName>(name: K, ...args: Parameters<EventMap[K]>): ReturnType<EventMap[K]>;
chain<K extends EventName>(session: Session, name: K, ...args: Parameters<EventMap[K]>): ReturnType<EventMap[K]>;
serial<K extends EventName>(name: K, ...args: Parameters<EventMap[K]>): Promisify<ReturnType<EventMap[K]>>;
serial<K extends EventName>(session: Session, name: K, ...args: Parameters<EventMap[K]>): Promisify<ReturnType<EventMap[K]>>;
bail<K extends EventName>(name: K, ...args: Parameters<EventMap[K]>): ReturnType<EventMap[K]>;
bail<K extends EventName>(session: Session, name: K, ...args: Parameters<EventMap[K]>): ReturnType<EventMap[K]>;
on<K extends EventName>(name: K, listener: EventMap[K], prepend?: boolean): () => boolean;
before<K extends BeforeEventName>(name: K, listener: BeforeEventMap[K], append?: boolean): () => boolean;
once<K extends EventName>(name: K, listener: EventMap[K], prepend?: boolean): () => boolean;
off<K extends EventName>(name: K, listener: EventMap[K]): boolean;
middleware(middleware: Middleware, prepend?: boolean): () => boolean;
private createTimerDispose;
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): () => boolean;
setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): () => boolean;
command<D extends string>(def: D, config?: Command.Config): Command<never, never, Domain.ArgumentType<D>>;
command<D extends string>(def: D, desc: string, config?: Command.Config): Command<never, never, Domain.ArgumentType<D>>;
transformAssets(content: string, assets?: Assets): Promise<string>;
getBot(platform: Platform, selfId?: string): Bot<never>;
getSelfIds(type?: Platform, assignees?: readonly string[]): Record<string, readonly string[]>;
broadcast(content: string, forced?: boolean): Promise<string[]>;
broadcast(channels: readonly string[], content: string, forced?: boolean): Promise<string[]>;
static delegate(key: string & keyof Context): void;
}
type FlattenEvents<T> = {
[K in keyof T & string]: K | `${K}/${FlattenEvents<T[K]>}`;
}[keyof T & string];
type SessionEventMap = {
[K in FlattenEvents<Session.Events>]: K extends `${infer X}/${infer R}` ? R extends `${infer Y}/${any}` ? (session: Session.Payload<X, Y>) => void : (session: Session.Payload<X, R>) => void : (session: Session.Payload<K>) => void;
};
type EventName = keyof EventMap;
type OmitSubstring<S extends string, T extends string> = S extends `${infer L}${T}${infer R}` ? `${L}${R}` : never;
type BeforeEventName = OmitSubstring<EventName & string, 'before-'>;
type BeforeEventMap = {
[E in EventName & string as OmitSubstring<E, 'before-'>]: EventMap[E];
};
export interface EventMap extends SessionEventMap {
[Context.middleware]: Middleware;
'appellation'(name: string, session: Session): string;
'before-parse'(content: string, session: Session): Argv;
'parse'(argv: Argv, session: Session): string;
'before-attach-channel'(session: Session, fields: Set<Channel.Field>): void;
'attach-channel'(session: Session): Awaitable<void | boolean>;
'before-attach-user'(session: Session, fields: Set<User.Field>): void;
'attach-user'(session: Session): Awaitable<void | boolean>;
'before-attach'(session: Session): void;
'attach'(session: Session): void;
'before-send'(session: Session<never, never, Platform, 'send'>): Awaitable<void | boolean>;
'before-command'(argv: Argv): Awaitable<void | string>;
'command'(argv: Argv): Awaitable<void>;
'middleware'(session: Session): void;
'plugin-added'(plugin: Plugin, registry: Map<Plugin, Plugin.State>): void;
'plugin-removed'(plugin: Plugin, registry: Map<Plugin, Plugin.State>): void;
'before-connect'(): Awaitable<void>;
'connect'(): void;
'before-disconnect'(): Awaitable<void>;
'disconnect'(): void;
}
export interface Domain {
string: string;
number: number;
boolean: boolean;
text: string;
user: string;
channel: string;
integer: number;
posint: number;
date: Date;
}
export namespace Domain {
type Builtin = keyof Domain;
type ParamType<S extends string, F> = S extends `${any}:${infer T}` ? T extends Builtin ? Domain[T] : F : F;
type Replace<S extends string, X extends string, Y extends string> = S extends `${infer L}${X}${infer R}` ? `${L}${Y}${Replace<R, X, Y>}` : S;
type ExtractAll<S extends string, F> = S extends `${infer L}]${infer R}` ? [ParamType<L, F>, ...ExtractAll<R, F>] : [];
type ExtractFirst<S extends string, F> = S extends `${infer L}]${any}` ? ParamType<L, F> : boolean;
type ExtractSpread<S extends string> = S extends `${infer L}...${infer R}` ? [...ExtractAll<L, string>, ...ExtractFirst<R, string>[]] : [...ExtractAll<S, string>, ...string[]];
export type ArgumentType<S extends string> = ExtractSpread<Replace<S, '>', ']'>>;
export type OptionType<S extends string, T extends Type> = [T] extends [Builtin] ? Domain[T] : [T] extends [RegExp] ? string : T extends (source: string) => infer R ? R : ExtractFirst<Replace<S, '>', ']'>, any>;
export type Type = Builtin | RegExp | Transform<any>;
export interface Declaration {
name?: string;
type?: Type;
fallback?: any;
variadic?: boolean;
required?: boolean;
}
export type Transform<T> = (source: string, session: Session) => T;
export function create<K extends keyof Domain>(name: K, callback: Transform<Domain[K]>): void;
export interface OptionConfig<T extends Type = Type> {
value?: any;
fallback?: any;
type?: T;
/** hide the option by default */
hidden?: boolean | ((session: Session) => boolean);
authority?: number;
notUsage?: boolean;
}
export interface OptionDeclaration extends Declaration, OptionConfig {
description?: string;
values?: Record<string, any>;
}
type OptionDeclarationMap = Record<string, OptionDeclaration>;
export class CommandBase {
name: string;
description: string;
declaration: string;
_arguments: Declaration[];
_options: OptionDeclarationMap;
private _error;
private _namedOptions;
private _symbolicOptions;
constructor(name: string, declaration: string, description: string);
_createOption(name: string, def: string, config?: OptionConfig): void;
private _assignOption;
removeOption<K extends string>(name: K): boolean;
private _parseValue;
parse(argv: Argv): Argv;
parse(source: string, terminator?: string): Argv;
private stringifyArg;
stringify(args: readonly string[], options: any): string;
}
export {};
}
export interface Token {
rest?: string;
content: string;
quoted: boolean;
terminator: string;
inters: Argv[];
}
export interface Argv<U extends User.Field = never, G extends Channel.Field = never, A extends any[] = any[], O = {}> {
args?: A;
options?: O;
error?: string;
source?: string;
initiator?: string;
terminator?: string;
session?: Session<U, G>;
command?: Command<U, G, A, O>;
rest?: string;
pos?: number;
root?: boolean;
tokens?: Token[];
name?: string;
next?: NextFunction;
}
export namespace Argv {
interface Interpolation {
terminator?: string;
parse?(source: string): Argv;
}
function interpolate(initiator: string, terminator: string, parse?: (source: string) => Argv): void;
class Tokenizer {
private bracs;
constructor();
interpolate(initiator: string, terminator: string, parse?: (source: string) => Argv): void;
parseToken(source: string, stopReg?: string): Token;
parse(source: string, terminator?: string): Argv;
stringify(argv: Argv): string;
}
function parse(source: string, terminator?: string): Argv<never, never, any[], {}>;
function stringify(argv: Argv): string;
function revert(token: Token): void;
const createDomain: typeof Domain.create;
function parsePid(target: string): [Platform, string];
}
export type UserType<T, U extends User.Field = User.Field> = T | ((user: Pick<User, U>) => T);
export type Extend<O extends {}, K extends string, T> = {
[P in K | keyof O]?: (P extends keyof O ? O[P] : unknown) & (P extends K ? T : unknown);
};
export namespace Command {
interface Config {
/** hide all options by default */
hideOptions?: boolean;
/** hide command */
hidden?: boolean;
/** min authority */
authority?: number;
/** disallow unknown options */
checkUnknown?: boolean;
/** check argument count */
checkArgCount?: boolean;
/** show command warnings */
showWarning?: boolean;
/** usage identifier */
usageName?: string;
/** max usage per day */
maxUsage?: UserType<number>;
/** min interval */
minInterval?: UserType<number>;
/** depend on existing commands */
patch?: boolean;
}
interface Shortcut {
name?: string | RegExp;
command?: Command;
authority?: number;
prefix?: boolean;
fuzzy?: boolean;
args?: string[];
greedy?: boolean;
options?: Record<string, any>;
}
type Action<U extends User.Field = never, G extends Channel.Field = never, A extends any[] = any[], O extends {} = {}> = (argv: Argv<U, G, A, O>, ...args: A) => void | string | Promise<void | string>;
type Usage<U extends User.Field = never, G extends Channel.Field = never> = string | ((session: Session<U, G>) => string | Promise<string>);
}
export class Command<U extends User.Field = never, G extends Channel.Field = never, A extends any[] = any[], O extends {} = {}> extends Domain.CommandBase {
context: Context;
config: Command.Config;
children: Command[];
parent: Command;
_aliases: string[];
_examples: string[];
_usage?: Command.Usage;
_disposed?: boolean;
_disposables?: Disposable[];
private _userFields;
private _channelFields;
private _actions;
private _checkers;
static defaultConfig: Command.Config;
static defaultOptionConfig: Domain.OptionConfig;
private static _userFields;
private static _channelFields;
static userFields(fields: FieldCollector<'user'>): typeof Command;
static channelFields(fields: FieldCollector<'channel'>): typeof Command;
constructor(name: string, decl: string, desc: string, context: Context);
get app(): App;
private _registerAlias;
[inspect.custom](): string;
userFields<T extends User.Field = never>(fields: FieldCollector<'user', T, A, O>): Command<U | T, G, A, O>;
channelFields<T extends Channel.Field = never>(fields: FieldCollector<'channel', T, A, O>): Command<U, G | T, A, O>;
alias(...names: string[]): this;
shortcut(name: string | RegExp, config?: Command.Shortcut): this;
subcommand<D extends string>(def: D, config?: Command.Config): Command<never, never, Domain.ArgumentType<D>>;
subcommand<D extends string>(def: D, desc: string, config?: Command.Config): Command<never, never, Domain.ArgumentType<D>>;
usage(text: Command.Usage<U, G>): this;
example(example: string): this;
option<K extends string, D extends string, T extends Domain.Type>(name: K, desc: D, config?: Domain.OptionConfig<T>): Command<U, G, A, Extend<O, K, Domain.OptionType<D, T>>>;
match(session: Session): boolean;
getConfig<K extends keyof Command.Config>(key: K, session: Session): Exclude<Command.Config[K], (user: User) => any>;
check(callback: Command.Action<U, G, A, O>, prepend?: boolean): this;
action(callback: Command.Action<U, G, A, O>, append?: boolean): this;
execute(argv0: Argv<U, G, A, O>, next?: NextFunction): Promise<string>;
dispose(): void;
}
export function getUsageName(command: Command): string;
export type ValidationField = 'authority' | 'usage' | 'timers';
export function getUsage(name: string, user: Pick<User, 'usage'>): number;
export function checkUsage(name: string, user: Pick<User, 'usage'>, maxUsage?: number): boolean;
export function checkTimer(name: string, { timers }: Pick<User, 'timers'>, offset?: number): boolean;
type UnionToIntersection<U> = (U extends any ? (key: U) => void : never) extends (key: infer I) => void ? I : never;
type Flatten<T, K extends keyof T = keyof T> = UnionToIntersection<T[K]>;
type InnerKeys<T, K extends keyof T = keyof T> = keyof Flatten<T> & keyof Flatten<T, K>;
export interface Session<U, G, P, X, Y> extends MessageBase, Partial<ChannelInfo>, Partial<GroupInfo> {
}
export namespace Session {
type Genres = 'friend' | 'channel' | 'group' | 'group-member' | 'group-role' | 'group-file' | 'group-emoji';
type Actions = 'added' | 'deleted' | 'updated';
export interface Events extends Record<`${Genres}-${Actions}`, {}> {
}
export type MessageAction = 'message' | 'message-deleted' | 'message-updated' | 'send';
export type Message = Session<never, never, Platform, MessageAction>;
export interface Events extends Record<MessageAction, MessageType> {
}
export type RequestAction = 'friend-request' | 'group-request' | 'group-member-request';
export type Request = Session<never, never, Platform, RequestAction>;
export interface Events extends Record<RequestAction, {}> {
}
export interface Events {
'friend-request': {};
'group-request': {};
'group-member-request': {};
'group-added': GroupMemberChangeType;
'group-member-added': GroupMemberChangeType;
'group-deleted': GroupMemberChangeType;
'group-member-deleted': GroupMemberChangeType;
'group-member': {
'role': {};
'ban': {};
};
'notice': {
'poke': {};
'lucky-king': {};
'honor': {
'talkative': {};
'performer': {};
'emotion': {};
};
};
}
export interface GroupMemberChangeType {
'active': {};
'passive': {};
}
export interface MessageType {
'private': {};
'group': {};
}
type ParamX<X> = Extract<keyof Events, X>;
type ParamY<X, Y> = Extract<InnerKeys<Events, ParamX<X>>, Y>;
export type Payload<X, Y = any> = Session<never, never, Platform, ParamX<X>, ParamY<X, Y>>;
export {};
}
export interface Parsed {
content: string;
prefix: string;
appel: boolean;
}
export class Session<U extends User.Field = never, G extends Channel.Field = never, P extends Platform = Platform, X extends keyof Session.Events = keyof Session.Events, Y extends InnerKeys<Session.Events, X> = InnerKeys<Session.Events, X>> {
type?: X;
subtype?: Y;
subsubtype?: InnerKeys<UnionToIntersection<Session.Events[X]>, Y>;
platform?: P;
selfId?: string;
operatorId?: string;
targetId?: string;
duration?: number;
file?: FileInfo;
readonly app: App;
readonly bot: Bot.Instance<P>;
readonly sid: string;
uid: string;
cid: string;
gid: string;
id?: string;
argv?: Argv<U, G>;
user?: User.Observed<U>;
channel?: Channel.Observed<G>;
parsed?: Parsed;
private _delay?;
private _queued;
private _hooks;
private _promise;
static readonly send: unique symbol;
constructor(app: App, session: Partial<Session>);
toJSON(): Partial<Session>;
private _preprocess;
preprocess(): Promise<string>;
get username(): string;
get database(): Database;
send(message: string): Promise<void>;
cancelQueued(delay?: number): void;
sendQueued(content: string, delay?: number): Promise<void>;
resolveValue<T>(source: T | ((session: Session) => T)): T;
getChannel<K extends Channel.Field = never>(id?: string, assignee?: string, fields?: readonly K[]): Promise<Pick<Channel, "id" | K>>;
/** 在当前会话上绑定一个可观测频道实例 */
observeChannel<T extends Channel.Field = never>(fields?: Iterable<T>): Promise<Channel.Observed<T | G>>;
getUser<K extends User.Field = never>(id?: string, authority?: number, fields?: readonly K[]): Promise<Pick<User, P | K>>;
/** 在当前会话上绑定一个可观测用户实例 */
observeUser<T extends User.Field = never>(fields?: Iterable<T>): Promise<User.Observed<T | U>>;
collect<T extends TableType>(key: T, argv: Argv, fields?: Set<keyof Tables[T]>): Set<keyof Tables[T]>;
resolve(argv: Argv): Command<never, never, any[], {}>;
execute(content: string, next?: true | NextFunction): Promise<string>;
execute(argv: Argv, next?: true | NextFunction): Promise<string>;
middleware(middleware: Middleware): () => boolean;
prompt(timeout?: number): Promise<string>;
suggest(options: SuggestOptions): Promise<void>;
}
export interface SuggestOptions {
target: string;
items: string[];
next?: NextFunction;
prefix?: string;
suffix: string;
minSimilarity?: number;
apply: (this: Session, suggestion: string, next: NextFunction) => void;
}
export function getSessionId(session: Session): string;
export type FieldCollector<T extends TableType, K = keyof Tables[T], A extends any[] = any[], O = {}> = Iterable<K> | ((argv: Argv<never, never, A, O>, fields: Set<keyof Tables[T]>) => void);
export interface FileInfo {
id: string;
name: string;
size: number;
busid: number;
}
export interface BotOptions {
type?: string;
token?: string;
selfId?: string;
}
type BotList<T extends Bot> = Array<T> & Record<string, T>;
export function createBots<T extends Bot>(key: 'selfId' | 'sid'): BotList<T>;
export abstract class Adapter<P extends Platform = Platform> {
app: App;
private Bot?;
bots: BotList<Bot.Instance<P>>;
abstract start(): Promise<void>;
abstract stop?(): void;
constructor(app: App, Bot?: Bot.Constructor<P>);
create(options: BotOptions, constructor?: Bot.Constructor<P>): Bot.Instance<P>;
dispatch(session: Session): void;
}
export namespace Adapter {
type Constructor<T extends Platform = Platform> = new (app: App, bot: BotOptions) => Adapter<T>;
type Instances = {
[K in string]: K extends `${infer T}:${any}` ? Adapter<T & Platform> : Adapter<K & Platform>;
};
const types: Record<string, Constructor>;
function from(app: App, bot: BotOptions): Adapter<never>;
function redirect(target: string | ((bot: BotOptions) => string)): Constructor<never>;
interface WsClientOptions {
retryLazy?: number;
retryTimes?: number;
retryInterval?: number;
}
abstract class WsClient<P extends Platform = Platform> extends Adapter<P> {
abstract prepare(bot: Bot.Instance<P>): WebSocket | Promise<WebSocket>;
abstract connect(bot: Bot.Instance<P>): Promise<void>;
private _listening;
options: WsClientOptions;
static options: WsClientOptions;
constructor(app: App, Bot: Bot.Constructor<P>, options?: WsClientOptions);
private _listen;
start(): Promise<void>;
stop(): void;
}
}
export interface Bot<P = Platform> extends BotOptions, UserBase {
[Session.send](session: Session, message: string): Promise<void>;
status: Bot.Status;
socket?: WebSocket;
version?: string;
getStatus(): Promise<Bot.Status>;
sendMessage(channelId: string, content: string): Promise<string>;
sendPrivateMessage(userId: string, content: string): Promise<string>;
getMessage(channelId: string, messageId: string): Promise<MessageInfo>;
editMessage(channelId: string, messageId: string, content: string): Promise<void>;
deleteMessage(channelId: string, messageId: string): Promise<void>;
getSelf(): Promise<UserInfo>;
getUser(userId: string): Promise<UserInfo>;
getFriendList(): Promise<UserInfo[]>;
getGroup(groupId: string): Promise<GroupInfo>;
getGroupList(): Promise<GroupInfo[]>;
getGroupMember(groupId: string, userId: string): Promise<GroupMemberInfo>;
getGroupMemberList(groupId: string): Promise<GroupMemberInfo[]>;
getChannel(channelId: string): Promise<ChannelInfo>;
getChannelList(groupId: string): Promise<ChannelInfo[]>;
handleFriendRequest(messageId: string, approve: boolean, comment?: string): Promise<void>;
handleGroupRequest(messageId: string, approve: boolean, comment?: string): Promise<void>;
handleGroupMemberRequest(messageId: string, approve: boolean, comment?: string): Promise<void>;
}
export class Bot<P extends Platform> {
adapter: Adapter<P>;
readonly app: App;
readonly logger: Logger;
readonly platform: P;
constructor(adapter: Adapter<P>, options: BotOptions);
get sid(): string;
createSession(session: Partial<Session<never, never, P, 'send'>>): Session<never, never, P, "send", "private" | "group">;
getGroupMemberMap(groupId: string): Promise<{
[k: string]: string;
}>;
broadcast(channels: string[], content: string, delay?: number): Promise<string[]>;
}
export namespace Bot {
interface Platforms {
}
type Instance<T extends Platform> = [T] extends [never] ? Bot<T> : Platforms[T];
type Constructor<T extends Platform> = new (adapter: Adapter, options: BotOptions) => Instance<T>;
enum Status {
/** 正常运行 */
GOOD = 0,
/** 机器人处于闲置状态 */
BOT_IDLE = 1,
/** 机器人离线 */
BOT_OFFLINE = 2,
/** 无法获得状态 */
NET_ERROR = 3,
/** 服务器状态异常 */
SERVER_ERROR = 4,
/** 机器人被封禁 */
BANNED = 5,
/** 正在尝试连接 */
CONNECTING = 6
}
}
export type Platform = keyof Bot.Platforms;
export interface ChannelInfo {
channelId: string;
channelName: string;
}
export interface GroupInfo {
groupId: string;
groupName: string;
}
export interface UserBase {
username: string;
nickname?: string;
avatar?: string;
discriminator?: string;
isBot?: boolean;
}
export interface UserInfo extends UserBase {
userId: string;
}
export interface GroupMemberInfo extends UserInfo {
roles?: string[];
}
export interface AuthorInfo extends GroupMemberInfo {
anonymous?: string;
}
export interface MessageBase {
messageId?: string;
channelId?: string;
groupId?: string;
userId?: string;
content?: string;
timestamp?: number;
author?: AuthorInfo;
quote?: MessageInfo;
}
export interface MessageInfo extends MessageBase {
subtype?: keyof Session.Events['message'];
}
export * from 'koishi-utils';
export const version: string;export default function apply(ctx: Context): void;