@onebots/core 0.5.0 → 1.0.0

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/logger.js ADDED
@@ -0,0 +1,156 @@
1
+ /**
2
+ * 增强的日志系统
3
+ * 提供结构化日志、错误追踪和上下文信息
4
+ */
5
+ import log4js from 'log4js';
6
+ import { ErrorHandler } from './errors.js';
7
+ const { getLogger } = log4js;
8
+ /**
9
+ * 增强的 Logger 类
10
+ */
11
+ export class Logger {
12
+ logger;
13
+ context = {};
14
+ constructor(name, level) {
15
+ this.logger = getLogger(name);
16
+ if (level) {
17
+ this.logger.level = level;
18
+ }
19
+ }
20
+ /**
21
+ * 设置日志级别
22
+ */
23
+ setLevel(level) {
24
+ this.logger.level = level;
25
+ }
26
+ /**
27
+ * 添加上下文信息
28
+ */
29
+ withContext(context) {
30
+ const newLogger = new Logger(this.logger.category, this.logger.level);
31
+ newLogger.context = { ...this.context, ...context };
32
+ return newLogger;
33
+ }
34
+ /**
35
+ * Trace 级别日志
36
+ */
37
+ trace(message, context) {
38
+ this.log('trace', message, context);
39
+ }
40
+ /**
41
+ * Debug 级别日志
42
+ */
43
+ debug(message, context) {
44
+ this.log('debug', message, context);
45
+ }
46
+ /**
47
+ * Info 级别日志
48
+ */
49
+ info(message, context) {
50
+ this.log('info', message, context);
51
+ }
52
+ /**
53
+ * Warn 级别日志
54
+ */
55
+ warn(message, context) {
56
+ this.log('warn', message, context);
57
+ }
58
+ /**
59
+ * Error 级别日志
60
+ */
61
+ error(message, context) {
62
+ if (typeof message === 'object' && message !== null) {
63
+ if (message instanceof Error || message.category !== undefined) {
64
+ const error = ErrorHandler.wrap(message, context);
65
+ this.log('error', error.message, {
66
+ ...context,
67
+ error: error.toJSON(),
68
+ });
69
+ return;
70
+ }
71
+ }
72
+ this.log('error', message, context);
73
+ }
74
+ /**
75
+ * Fatal 级别日志
76
+ */
77
+ fatal(message, context) {
78
+ if (typeof message === 'object' && message !== null) {
79
+ if (message instanceof Error || message.category !== undefined) {
80
+ const error = ErrorHandler.wrap(message, context);
81
+ this.log('fatal', error.message, {
82
+ ...context,
83
+ error: error.toJSON(),
84
+ });
85
+ return;
86
+ }
87
+ }
88
+ this.log('fatal', message, context);
89
+ }
90
+ /**
91
+ * Mark 级别日志
92
+ */
93
+ mark(message, context) {
94
+ this.log('mark', message, context);
95
+ }
96
+ /**
97
+ * 记录性能指标
98
+ */
99
+ performance(operation, duration, context) {
100
+ this.info(`Performance: ${operation} took ${duration}ms`, {
101
+ ...context,
102
+ operation,
103
+ duration,
104
+ type: 'performance',
105
+ });
106
+ }
107
+ /**
108
+ * 记录操作开始
109
+ */
110
+ start(operation, context) {
111
+ const startTime = Date.now();
112
+ this.debug(`Starting: ${operation}`, context);
113
+ return () => {
114
+ const duration = Date.now() - startTime;
115
+ this.performance(operation, duration, context);
116
+ };
117
+ }
118
+ /**
119
+ * 内部日志方法
120
+ */
121
+ log(level, message, context) {
122
+ const mergedContext = { ...this.context, ...context };
123
+ const logMessage = mergedContext && Object.keys(mergedContext).length > 0
124
+ ? `${message} ${JSON.stringify(mergedContext)}`
125
+ : message;
126
+ switch (level) {
127
+ case 'trace':
128
+ this.logger.trace(logMessage);
129
+ break;
130
+ case 'debug':
131
+ this.logger.debug(logMessage);
132
+ break;
133
+ case 'info':
134
+ this.logger.info(logMessage);
135
+ break;
136
+ case 'warn':
137
+ this.logger.warn(logMessage);
138
+ break;
139
+ case 'error':
140
+ this.logger.error(logMessage);
141
+ break;
142
+ case 'fatal':
143
+ this.logger.fatal(logMessage);
144
+ break;
145
+ case 'mark':
146
+ this.logger.mark(logMessage);
147
+ break;
148
+ }
149
+ }
150
+ }
151
+ /**
152
+ * 创建 Logger 实例
153
+ */
154
+ export function createLogger(name, level) {
155
+ return new Logger(name, level);
156
+ }
package/lib/protocol.d.ts CHANGED
@@ -3,7 +3,6 @@ import { Account } from "./account.js";
3
3
  import { Adapter } from "./adapter.js";
4
4
  import { Dict } from "./types.js";
5
5
  import { Router } from "./router.js";
6
- import { BaseApp } from "./base-app.js";
7
6
  /**
8
7
  * Base Protocol class
9
8
  * Represents a communication protocol (e.g., OneBot, Milky, Satori)
@@ -14,7 +13,7 @@ export declare abstract class Protocol<V extends string = string, C = any> exten
14
13
  config: Protocol.FullConfig<C>;
15
14
  abstract readonly name: string;
16
15
  abstract readonly version: V;
17
- get app(): BaseApp;
16
+ get app(): import("./base-app.js").BaseApp;
18
17
  get router(): Router;
19
18
  get logger(): import("log4js").Logger;
20
19
  constructor(adapter: Adapter, account: Account, config: Protocol.FullConfig<C>);
@@ -95,6 +94,6 @@ export declare namespace Protocol {
95
94
  */
96
95
  export type Factory<T extends Protocol = Protocol> = Creator<T> | Construct<T>;
97
96
  export function isClassFactory<T extends Protocol = Protocol>(factory: Factory<T>): factory is Construct<T>;
98
- export function createFilter(filters: Filters): (event: Dict) => any;
97
+ export function createFilter(filters?: Filters): any;
99
98
  export {};
100
99
  }
package/lib/protocol.js CHANGED
@@ -41,6 +41,10 @@ export class Protocol extends EventEmitter {
41
41
  }
42
42
  Protocol.isClassFactory = isClassFactory;
43
43
  function createFilter(filters) {
44
+ // 如果没有 filters,返回始终为 true 的过滤器
45
+ if (!filters || Object.keys(filters).length === 0) {
46
+ return () => true;
47
+ }
44
48
  const isLogicKey = (key) => {
45
49
  return [
46
50
  "$and",
@@ -0,0 +1,88 @@
1
+ /**
2
+ * API 速率限制器
3
+ * 防止触发平台的速率限制
4
+ */
5
+ export interface RateLimiterOptions {
6
+ /** 时间窗口内允许的最大请求数 */
7
+ maxRequests: number;
8
+ /** 时间窗口大小(毫秒) */
9
+ windowMs: number;
10
+ /** 请求之间的最小间隔(毫秒) */
11
+ minInterval?: number;
12
+ /** 超出限制时是否排队等待 */
13
+ queueExcess?: boolean;
14
+ /** 队列最大长度 */
15
+ maxQueueSize?: number;
16
+ }
17
+ /**
18
+ * 令牌桶速率限制器
19
+ */
20
+ export declare class RateLimiter {
21
+ private tokens;
22
+ private lastRefill;
23
+ private queue;
24
+ private processing;
25
+ private lastRequest;
26
+ private readonly maxRequests;
27
+ private readonly windowMs;
28
+ private readonly minInterval;
29
+ private readonly queueExcess;
30
+ private readonly maxQueueSize;
31
+ constructor(options: RateLimiterOptions);
32
+ /**
33
+ * 补充令牌
34
+ */
35
+ private refillTokens;
36
+ /**
37
+ * 尝试获取令牌
38
+ */
39
+ private tryAcquire;
40
+ /**
41
+ * 计算需要等待的时间
42
+ */
43
+ private getWaitTime;
44
+ /**
45
+ * 执行受限函数
46
+ */
47
+ execute<T>(fn: () => Promise<T>): Promise<T>;
48
+ /**
49
+ * 处理队列
50
+ */
51
+ private processQueue;
52
+ /**
53
+ * 获取当前状态
54
+ */
55
+ getStatus(): {
56
+ availableTokens: number;
57
+ queueLength: number;
58
+ isProcessing: boolean;
59
+ };
60
+ /**
61
+ * 清空队列
62
+ */
63
+ clearQueue(): void;
64
+ private sleep;
65
+ }
66
+ /**
67
+ * 速率限制错误
68
+ */
69
+ export declare class RateLimitError extends Error {
70
+ constructor(message: string);
71
+ }
72
+ /**
73
+ * 平台速率限制预设
74
+ */
75
+ export declare const RateLimitPresets: {
76
+ /** Discord - 50 请求/秒 */
77
+ discord: RateLimiterOptions;
78
+ /** Telegram - 30 消息/秒(群组 20/分钟) */
79
+ telegram: RateLimiterOptions;
80
+ /** QQ - 5 消息/秒 */
81
+ qq: RateLimiterOptions;
82
+ /** 通用 - 10 请求/秒 */
83
+ default: RateLimiterOptions;
84
+ };
85
+ /**
86
+ * 创建带速率限制的函数包装器
87
+ */
88
+ export declare function withRateLimit<T extends (...args: any[]) => Promise<any>>(fn: T, limiter: RateLimiter): T;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * API 速率限制器
3
+ * 防止触发平台的速率限制
4
+ */
5
+ /**
6
+ * 令牌桶速率限制器
7
+ */
8
+ export class RateLimiter {
9
+ tokens;
10
+ lastRefill;
11
+ queue = [];
12
+ processing = false;
13
+ lastRequest = 0;
14
+ maxRequests;
15
+ windowMs;
16
+ minInterval;
17
+ queueExcess;
18
+ maxQueueSize;
19
+ constructor(options) {
20
+ this.maxRequests = options.maxRequests;
21
+ this.windowMs = options.windowMs;
22
+ this.minInterval = options.minInterval ?? 0;
23
+ this.queueExcess = options.queueExcess ?? true;
24
+ this.maxQueueSize = options.maxQueueSize ?? 100;
25
+ this.tokens = this.maxRequests;
26
+ this.lastRefill = Date.now();
27
+ }
28
+ /**
29
+ * 补充令牌
30
+ */
31
+ refillTokens() {
32
+ const now = Date.now();
33
+ const elapsed = now - this.lastRefill;
34
+ const tokensToAdd = (elapsed / this.windowMs) * this.maxRequests;
35
+ this.tokens = Math.min(this.maxRequests, this.tokens + tokensToAdd);
36
+ this.lastRefill = now;
37
+ }
38
+ /**
39
+ * 尝试获取令牌
40
+ */
41
+ tryAcquire() {
42
+ this.refillTokens();
43
+ if (this.tokens >= 1) {
44
+ this.tokens -= 1;
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+ /**
50
+ * 计算需要等待的时间
51
+ */
52
+ getWaitTime() {
53
+ this.refillTokens();
54
+ if (this.tokens >= 1) {
55
+ return 0;
56
+ }
57
+ // 计算获得一个令牌需要的时间
58
+ const tokensNeeded = 1 - this.tokens;
59
+ return (tokensNeeded / this.maxRequests) * this.windowMs;
60
+ }
61
+ /**
62
+ * 执行受限函数
63
+ */
64
+ async execute(fn) {
65
+ // 检查最小间隔
66
+ const now = Date.now();
67
+ const timeSinceLastRequest = now - this.lastRequest;
68
+ if (timeSinceLastRequest < this.minInterval) {
69
+ await this.sleep(this.minInterval - timeSinceLastRequest);
70
+ }
71
+ // 尝试获取令牌
72
+ if (this.tryAcquire()) {
73
+ this.lastRequest = Date.now();
74
+ return fn();
75
+ }
76
+ // 如果不排队,直接抛出错误
77
+ if (!this.queueExcess) {
78
+ throw new RateLimitError('Rate limit exceeded');
79
+ }
80
+ // 检查队列大小
81
+ if (this.queue.length >= this.maxQueueSize) {
82
+ throw new RateLimitError('Rate limit queue is full');
83
+ }
84
+ // 加入队列
85
+ return new Promise((resolve, reject) => {
86
+ this.queue.push({ execute: fn, resolve, reject });
87
+ this.processQueue();
88
+ });
89
+ }
90
+ /**
91
+ * 处理队列
92
+ */
93
+ async processQueue() {
94
+ if (this.processing || this.queue.length === 0) {
95
+ return;
96
+ }
97
+ this.processing = true;
98
+ while (this.queue.length > 0) {
99
+ const waitTime = this.getWaitTime();
100
+ if (waitTime > 0) {
101
+ await this.sleep(waitTime);
102
+ }
103
+ // 检查最小间隔
104
+ const timeSinceLastRequest = Date.now() - this.lastRequest;
105
+ if (timeSinceLastRequest < this.minInterval) {
106
+ await this.sleep(this.minInterval - timeSinceLastRequest);
107
+ }
108
+ if (this.tryAcquire()) {
109
+ const request = this.queue.shift();
110
+ if (request) {
111
+ this.lastRequest = Date.now();
112
+ try {
113
+ const result = await request.execute();
114
+ request.resolve(result);
115
+ }
116
+ catch (error) {
117
+ request.reject(error instanceof Error ? error : new Error(String(error)));
118
+ }
119
+ }
120
+ }
121
+ }
122
+ this.processing = false;
123
+ }
124
+ /**
125
+ * 获取当前状态
126
+ */
127
+ getStatus() {
128
+ this.refillTokens();
129
+ return {
130
+ availableTokens: Math.floor(this.tokens),
131
+ queueLength: this.queue.length,
132
+ isProcessing: this.processing,
133
+ };
134
+ }
135
+ /**
136
+ * 清空队列
137
+ */
138
+ clearQueue() {
139
+ const error = new RateLimitError('Queue cleared');
140
+ this.queue.forEach(request => request.reject(error));
141
+ this.queue = [];
142
+ }
143
+ sleep(ms) {
144
+ return new Promise(resolve => setTimeout(resolve, ms));
145
+ }
146
+ }
147
+ /**
148
+ * 速率限制错误
149
+ */
150
+ export class RateLimitError extends Error {
151
+ constructor(message) {
152
+ super(message);
153
+ this.name = 'RateLimitError';
154
+ }
155
+ }
156
+ /**
157
+ * 平台速率限制预设
158
+ */
159
+ export const RateLimitPresets = {
160
+ /** Discord - 50 请求/秒 */
161
+ discord: {
162
+ maxRequests: 50,
163
+ windowMs: 1000,
164
+ minInterval: 50,
165
+ queueExcess: true,
166
+ },
167
+ /** Telegram - 30 消息/秒(群组 20/分钟) */
168
+ telegram: {
169
+ maxRequests: 30,
170
+ windowMs: 1000,
171
+ minInterval: 50,
172
+ queueExcess: true,
173
+ },
174
+ /** QQ - 5 消息/秒 */
175
+ qq: {
176
+ maxRequests: 5,
177
+ windowMs: 1000,
178
+ minInterval: 200,
179
+ queueExcess: true,
180
+ },
181
+ /** 通用 - 10 请求/秒 */
182
+ default: {
183
+ maxRequests: 10,
184
+ windowMs: 1000,
185
+ minInterval: 100,
186
+ queueExcess: true,
187
+ },
188
+ };
189
+ /**
190
+ * 创建带速率限制的函数包装器
191
+ */
192
+ export function withRateLimit(fn, limiter) {
193
+ return ((...args) => {
194
+ return limiter.execute(() => fn(...args));
195
+ });
196
+ }
package/lib/registry.js CHANGED
@@ -83,11 +83,6 @@ export class ProtocolRegistry {
83
83
  */
84
84
  static create(name, version, adapter, account, config) {
85
85
  const factory = this.get(name, version);
86
- console.log({
87
- name,
88
- version,
89
- account: account.account_id
90
- });
91
86
  if (!factory) {
92
87
  throw new Error(`Protocol ${name}/${version} not registered`);
93
88
  }
package/lib/retry.d.ts ADDED
@@ -0,0 +1,87 @@
1
+ /**
2
+ * 重试策略和网络请求重试机制
3
+ * 提供统一的重试逻辑,支持指数退避
4
+ */
5
+ export interface RetryOptions {
6
+ /** 最大重试次数 */
7
+ maxRetries?: number;
8
+ /** 初始延迟时间(毫秒) */
9
+ initialDelay?: number;
10
+ /** 最大延迟时间(毫秒) */
11
+ maxDelay?: number;
12
+ /** 退避倍数 */
13
+ backoffMultiplier?: number;
14
+ /** 是否添加随机抖动 */
15
+ jitter?: boolean;
16
+ /** 判断是否应该重试的函数 */
17
+ shouldRetry?: (error: Error, attempt: number) => boolean;
18
+ /** 重试前的回调 */
19
+ onRetry?: (error: Error, attempt: number, delay: number) => void;
20
+ }
21
+ /**
22
+ * 带重试的异步函数执行器
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const result = await retry(
27
+ * () => fetch('https://api.example.com/data'),
28
+ * { maxRetries: 3, initialDelay: 1000 }
29
+ * );
30
+ * ```
31
+ */
32
+ export declare function retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
33
+ /**
34
+ * 创建一个带重试功能的函数包装器
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * const fetchWithRetry = withRetry(fetch, { maxRetries: 3 });
39
+ * const response = await fetchWithRetry('https://api.example.com/data');
40
+ * ```
41
+ */
42
+ export declare function withRetry<T extends (...args: any[]) => Promise<any>>(fn: T, options?: RetryOptions): T;
43
+ /**
44
+ * 重试策略预设
45
+ */
46
+ export declare const RetryPresets: {
47
+ /** 快速重试:3次,1秒起始 */
48
+ fast: RetryOptions;
49
+ /** 标准重试:5次,2秒起始 */
50
+ standard: RetryOptions;
51
+ /** 持久重试:10次,5秒起始 */
52
+ persistent: RetryOptions;
53
+ /** WebSocket 重连:无限重试 */
54
+ websocket: RetryOptions;
55
+ };
56
+ /**
57
+ * 连接管理器 - 用于 WebSocket 等长连接的重连管理
58
+ */
59
+ export declare class ConnectionManager {
60
+ private connect;
61
+ private reconnectAttempt;
62
+ private reconnectTimer;
63
+ private isConnecting;
64
+ private options;
65
+ constructor(connect: () => Promise<void>, options?: RetryOptions);
66
+ /**
67
+ * 开始连接
68
+ */
69
+ start(): Promise<void>;
70
+ /**
71
+ * 停止连接和重连
72
+ */
73
+ stop(): void;
74
+ /**
75
+ * 触发重连
76
+ */
77
+ scheduleReconnect(error?: Error): void;
78
+ /**
79
+ * 重置重连计数(连接成功时调用)
80
+ */
81
+ resetAttempts(): void;
82
+ /**
83
+ * 获取当前重连次数
84
+ */
85
+ getAttempts(): number;
86
+ private tryConnect;
87
+ }