koishi-plugin-docker-control 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.
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Notifier = void 0;
4
+ const logger_1 = require("../utils/logger");
5
+ /**
6
+ * 事件消息模板
7
+ */
8
+ const EVENT_TEMPLATES = {
9
+ // 容器生命周期
10
+ 'container.start': '容器已启动',
11
+ 'container.stop': '容器已停止',
12
+ 'container.restart': '容器已重启',
13
+ 'container.die': '容器已异常退出',
14
+ 'container.create': '容器已创建',
15
+ 'container.destroy': '容器已销毁',
16
+ // 健康检查
17
+ 'container.health_status': '容器健康状态变更',
18
+ 'health_status: healthy': '容器健康检查通过',
19
+ 'health_status: unhealthy': '容器健康检查失败',
20
+ // exec 事件
21
+ 'exec_create': '执行命令',
22
+ 'exec_start': '开始执行',
23
+ 'exec_die': '执行结束',
24
+ // 节点事件
25
+ 'node.online': '节点已上线',
26
+ 'node.offline': '节点已离线',
27
+ 'node.error': '节点发生错误',
28
+ // 附加/分离
29
+ 'attach': '容器已附加',
30
+ 'detach': '容器已分离',
31
+ 'kill': '容器已被终止',
32
+ 'oom': '内存不足',
33
+ 'pause': '容器已暂停',
34
+ 'unpause': '容器已恢复',
35
+ };
36
+ /**
37
+ * 容器状态 Emoji
38
+ */
39
+ const STATUS_EMOJI = {
40
+ running: '🟢',
41
+ stopped: '🔴',
42
+ restarting: '🟡',
43
+ paused: '🟣',
44
+ created: '⚪',
45
+ };
46
+ /**
47
+ * 事件级别
48
+ */
49
+ const EVENT_LEVEL = {
50
+ 'container.start': 'info',
51
+ 'container.stop': 'info',
52
+ 'container.restart': 'info',
53
+ 'container.die': 'error',
54
+ 'container.health_status': 'warning',
55
+ 'node.online': 'info',
56
+ 'node.offline': 'warning',
57
+ 'node.error': 'error',
58
+ };
59
+ class Notifier {
60
+ constructor(ctx, config) {
61
+ this.ctx = ctx;
62
+ this.config = config;
63
+ }
64
+ /**
65
+ * 发送通知
66
+ */
67
+ async send(eventType, data) {
68
+ // 检查是否启用
69
+ if (!this.config?.enabled) {
70
+ logger_1.notifierLogger.debug(`通知已禁用`);
71
+ return;
72
+ }
73
+ // 检查事件是否需要通知
74
+ if (!this.config?.events?.includes(eventType)) {
75
+ logger_1.notifierLogger.debug(`事件 ${eventType} 不在通知列表中`);
76
+ return;
77
+ }
78
+ // 检查通知级别
79
+ const level = EVENT_LEVEL[eventType];
80
+ if (this.config.level === 'error' && level !== 'error') {
81
+ logger_1.notifierLogger.debug(`事件级别 ${level} 被通知级别过滤`);
82
+ return;
83
+ }
84
+ // 构建消息
85
+ const message = this.buildMessage(eventType, data);
86
+ logger_1.notifierLogger.debug(`准备发送通知: ${eventType} -> ${message}`);
87
+ // 发送到所有目标群组
88
+ const channels = await this.getTargetChannels();
89
+ logger_1.notifierLogger.debug(`目标群组: ${JSON.stringify(channels)}`);
90
+ for (const channel of channels) {
91
+ try {
92
+ const bot = this.ctx.bots.find(b => b.sid === channel.botId);
93
+ if (bot) {
94
+ await bot.sendMessage(channel.channelId, message);
95
+ logger_1.notifierLogger.debug(`通知已发送: ${channel.channelId}`);
96
+ }
97
+ else {
98
+ logger_1.notifierLogger.debug(`找不到 bot: ${channel.botId}`);
99
+ }
100
+ }
101
+ catch (e) {
102
+ logger_1.notifierLogger.error(`通知发送失败: ${e}`);
103
+ }
104
+ }
105
+ }
106
+ /**
107
+ * 构建消息
108
+ */
109
+ buildMessage(eventType, data) {
110
+ const template = EVENT_TEMPLATES[eventType] || '未知事件';
111
+ const parts = [];
112
+ // 节点信息
113
+ if (data.nodeName) {
114
+ parts.push(`【${data.nodeName}】`);
115
+ }
116
+ // 容器信息
117
+ if (data.containerName) {
118
+ const emoji = this.getContainerEmoji(data);
119
+ parts.push(`${emoji} ${data.containerName}`);
120
+ }
121
+ // 事件描述
122
+ parts.push(template);
123
+ // 额外信息
124
+ if (data.action && !template.includes(data.action)) {
125
+ parts.push(`(${data.action})`);
126
+ }
127
+ if (data.attributes?.image) {
128
+ parts.push(`\n镜像: ${data.attributes.image}`);
129
+ }
130
+ if (data.attributes?.exitCode !== undefined) {
131
+ parts.push(`\n退出码: ${data.attributes.exitCode}`);
132
+ }
133
+ // 组合消息
134
+ return parts.join(' ');
135
+ }
136
+ /**
137
+ * 获取容器状态 Emoji
138
+ */
139
+ getContainerEmoji(data) {
140
+ const status = data.attributes?.status || data.action;
141
+ return STATUS_EMOJI[status] || '📦';
142
+ }
143
+ /**
144
+ * 获取目标频道
145
+ */
146
+ async getTargetChannels() {
147
+ const channels = [];
148
+ if (!this.config?.targetGroups?.length) {
149
+ return channels;
150
+ }
151
+ // 获取所有群组频道
152
+ try {
153
+ const allChannels = await this.ctx.database.get('channel', {
154
+ platform: 'onebot',
155
+ });
156
+ for (const groupId of this.config.targetGroups) {
157
+ const channel = allChannels.find((c) => c.id === groupId);
158
+ if (channel) {
159
+ channels.push({
160
+ botId: channel.assignee || '',
161
+ channelId: groupId,
162
+ });
163
+ }
164
+ }
165
+ }
166
+ catch (e) {
167
+ logger_1.notifierLogger.warn(`获取频道列表失败: ${e}`);
168
+ }
169
+ return channels;
170
+ }
171
+ /**
172
+ * 发送自定义消息
173
+ */
174
+ async notifyCustom(content, targets) {
175
+ const channels = targets || this.config.targetGroups;
176
+ for (const groupId of channels) {
177
+ try {
178
+ // 发送消息给所有机器人的对应群组
179
+ for (const bot of this.ctx.bots.values()) {
180
+ await bot.sendMessage(groupId, content);
181
+ }
182
+ }
183
+ catch (e) {
184
+ logger_1.notifierLogger.error(`自定义通知发送失败: ${e}`);
185
+ }
186
+ }
187
+ }
188
+ }
189
+ exports.Notifier = Notifier;
package/lib/types.d.ts ADDED
@@ -0,0 +1,100 @@
1
+ /**
2
+ * 类型定义 - 简化版,只支持 SSH 直连模式
3
+ */
4
+ export type AuthType = 'key' | 'password';
5
+ export type NodeStatusType = 'disconnected' | 'connecting' | 'connected' | 'error';
6
+ export type ContainerStatusType = 'running' | 'stopped' | 'paused' | 'restarting' | 'created';
7
+ export interface CredentialConfig {
8
+ id: string;
9
+ name: string;
10
+ username: string;
11
+ authType: AuthType;
12
+ password?: string;
13
+ privateKey?: string;
14
+ passphrase?: string;
15
+ }
16
+ export interface NodeConfig {
17
+ id: string;
18
+ name: string;
19
+ tags: string[];
20
+ host: string;
21
+ port: number;
22
+ credentialId: string;
23
+ }
24
+ export interface NotificationConfig {
25
+ enabled: boolean;
26
+ level: 'all' | 'error' | 'none';
27
+ targetGroups: string[];
28
+ events: NotificationEventType[];
29
+ }
30
+ export type NotificationEventType = 'container.start' | 'container.stop' | 'container.restart' | 'container.die' | 'container.health_status' | 'node.online' | 'node.offline' | 'node.error';
31
+ export interface MonitorConfig {
32
+ debounceWait: number;
33
+ flappingWindow: number;
34
+ flappingThreshold: number;
35
+ }
36
+ export interface DockerControlConfig {
37
+ requestTimeout: number;
38
+ debug: boolean;
39
+ imageOutput: boolean;
40
+ defaultLogLines: number;
41
+ monitor: MonitorConfig;
42
+ credentials: CredentialConfig[];
43
+ nodes: NodeConfig[];
44
+ notification: NotificationConfig;
45
+ }
46
+ export interface ContainerInfo {
47
+ Id: string;
48
+ Names: string[];
49
+ Image: string;
50
+ ImageID: string;
51
+ Command: string;
52
+ Created: number;
53
+ Ports: Array<{
54
+ PrivatePort: number;
55
+ PublicPort: number;
56
+ Type: string;
57
+ }>;
58
+ Labels: Record<string, string>;
59
+ State: ContainerStatusType;
60
+ Status: string;
61
+ HostConfig: {
62
+ NetworkMode: string;
63
+ };
64
+ NetworkSettings: {
65
+ Networks: Record<string, {
66
+ IPAddress: string;
67
+ Gateway: string;
68
+ MacAddress: string;
69
+ }>;
70
+ };
71
+ }
72
+ export interface DockerEvent {
73
+ Type: string;
74
+ Action: string;
75
+ Actor: {
76
+ ID: string;
77
+ Attributes: Record<string, string>;
78
+ };
79
+ scope: 'local' | 'swarm';
80
+ time: number;
81
+ timeNano: number;
82
+ }
83
+ export interface SubscriptionConfig {
84
+ /** 订阅 ID */
85
+ id?: number;
86
+ /** 平台 (onebot 等) */
87
+ platform: string;
88
+ /** 频道 ID (群组号或用户号) */
89
+ channelId: string;
90
+ /** 节点 ID (空表示所有节点) */
91
+ nodeId?: string;
92
+ /** 容器名称模式 (空表示所有容器,支持 * 通配符) */
93
+ containerPattern?: string;
94
+ /** 推送的事件类型 */
95
+ eventTypes: string[];
96
+ /** 是否启用 */
97
+ enabled: boolean;
98
+ /** 创建时间 */
99
+ createdAt?: number;
100
+ }
package/lib/types.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * 类型定义 - 简化版,只支持 SSH 直连模式
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 格式化工具
3
+ */
4
+ /**
5
+ * 格式化字节大小
6
+ */
7
+ export declare function formatBytes(bytes: number, decimals?: number): string;
8
+ /**
9
+ * 格式化时间
10
+ */
11
+ export declare function formatTime(timestamp: number | string | Date, format?: 'iso' | 'local' | 'relative'): string;
12
+ /**
13
+ * 相对时间格式化
14
+ */
15
+ export declare function formatRelativeTime(date: Date): string;
16
+ /**
17
+ * 格式化容器状态
18
+ */
19
+ export declare function formatContainerStatus(state: string, running: boolean): string;
20
+ /**
21
+ * 截断字符串
22
+ */
23
+ export declare function truncate(str: string, maxLength: number, suffix?: string): string;
24
+ /**
25
+ * 移除 ANSI 颜色码
26
+ */
27
+ export declare function stripAnsiCodes(str: string): string;
28
+ /**
29
+ * 格式化表格
30
+ */
31
+ export declare function formatTable<T>(data: T[], columns: Array<{
32
+ key: keyof T;
33
+ header: string;
34
+ width: number;
35
+ }>): string;
36
+ /**
37
+ * 颜色状态图标
38
+ */
39
+ export declare function getStatusEmoji(status: string, running: boolean): string;
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * 格式化工具
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.formatBytes = formatBytes;
7
+ exports.formatTime = formatTime;
8
+ exports.formatRelativeTime = formatRelativeTime;
9
+ exports.formatContainerStatus = formatContainerStatus;
10
+ exports.truncate = truncate;
11
+ exports.stripAnsiCodes = stripAnsiCodes;
12
+ exports.formatTable = formatTable;
13
+ exports.getStatusEmoji = getStatusEmoji;
14
+ /**
15
+ * 格式化字节大小
16
+ */
17
+ function formatBytes(bytes, decimals = 2) {
18
+ if (bytes === 0)
19
+ return '0 B';
20
+ const k = 1024;
21
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
22
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
23
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
24
+ }
25
+ /**
26
+ * 格式化时间
27
+ */
28
+ function formatTime(timestamp, format = 'local') {
29
+ const date = timestamp instanceof Date ? timestamp : new Date(timestamp);
30
+ switch (format) {
31
+ case 'iso':
32
+ return date.toISOString();
33
+ case 'relative':
34
+ return formatRelativeTime(date);
35
+ case 'local':
36
+ default:
37
+ return date.toLocaleString('zh-CN');
38
+ }
39
+ }
40
+ /**
41
+ * 相对时间格式化
42
+ */
43
+ function formatRelativeTime(date) {
44
+ const now = new Date();
45
+ const diff = now.getTime() - date.getTime();
46
+ const seconds = Math.floor(diff / 1000);
47
+ const minutes = Math.floor(seconds / 60);
48
+ const hours = Math.floor(minutes / 60);
49
+ const days = Math.floor(hours / 24);
50
+ if (seconds < 60) {
51
+ return '刚刚';
52
+ }
53
+ else if (minutes < 60) {
54
+ return `${minutes} 分钟前`;
55
+ }
56
+ else if (hours < 24) {
57
+ return `${hours} 小时前`;
58
+ }
59
+ else if (days < 7) {
60
+ return `${days} 天前`;
61
+ }
62
+ else {
63
+ return date.toLocaleDateString('zh-CN');
64
+ }
65
+ }
66
+ /**
67
+ * 格式化容器状态
68
+ */
69
+ function formatContainerStatus(state, running) {
70
+ if (running) {
71
+ return `运行中 (${state})`;
72
+ }
73
+ const statusMap = {
74
+ exited: '已停止',
75
+ stopped: '已停止',
76
+ created: '已创建',
77
+ paused: '已暂停',
78
+ restarting: '重启中',
79
+ dead: '已失效',
80
+ };
81
+ return statusMap[state.toLowerCase()] || state;
82
+ }
83
+ /**
84
+ * 截断字符串
85
+ */
86
+ function truncate(str, maxLength, suffix = '...') {
87
+ if (str.length <= maxLength) {
88
+ return str;
89
+ }
90
+ return str.slice(0, maxLength - suffix.length) + suffix;
91
+ }
92
+ /**
93
+ * 移除 ANSI 颜色码
94
+ */
95
+ function stripAnsiCodes(str) {
96
+ return str.replace(/[\x1b\u001b[0-9;]*[a-zA-Z]/g, '');
97
+ }
98
+ /**
99
+ * 格式化表格
100
+ */
101
+ function formatTable(data, columns) {
102
+ if (data.length === 0) {
103
+ return '';
104
+ }
105
+ const lines = [];
106
+ // 表头
107
+ const header = columns
108
+ .map((col) => col.header.padEnd(col.width))
109
+ .join(' | ');
110
+ lines.push(header);
111
+ // 分隔线
112
+ const separator = columns.map((col) => '-'.repeat(col.width)).join('-+-');
113
+ lines.push(separator);
114
+ // 数据行
115
+ for (const row of data) {
116
+ const line = columns
117
+ .map((col) => {
118
+ const value = String(row[col.key] ?? '');
119
+ return value.slice(0, col.width).padEnd(col.width);
120
+ })
121
+ .join(' | ');
122
+ lines.push(line);
123
+ }
124
+ return lines.join('\n');
125
+ }
126
+ /**
127
+ * 颜色状态图标
128
+ */
129
+ function getStatusEmoji(status, running) {
130
+ if (running) {
131
+ return '🟢';
132
+ }
133
+ const statusEmoji = {
134
+ exited: '🔴',
135
+ stopped: '🔴',
136
+ created: '⚪',
137
+ paused: '🟣',
138
+ restarting: '🟡',
139
+ dead: '⚫',
140
+ };
141
+ return statusEmoji[status.toLowerCase()] || '🔴';
142
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * 统一日志模块
3
+ * 提供带命名空间的日志器,支持调试模式
4
+ */
5
+ import { Logger } from 'koishi';
6
+ export declare const logger: Logger;
7
+ export declare const nodeLogger: Logger;
8
+ export declare const connectorLogger: Logger;
9
+ export declare const monitorLogger: Logger;
10
+ export declare const notifierLogger: Logger;
11
+ export declare const commandLogger: Logger;
12
+ /**
13
+ * 创建带命名空间的日志器
14
+ */
15
+ export declare function createLogger(name: string): Logger;
16
+ /**
17
+ * 格式化日志消息
18
+ */
19
+ export declare function formatMessage(message: string, ...args: any[]): string;
20
+ /**
21
+ * 节点操作日志 - 便捷方法
22
+ */
23
+ export declare const node: {
24
+ info: (nodeName: string, message: string, ...args: any[]) => void;
25
+ warn: (nodeName: string, message: string, ...args: any[]) => void;
26
+ error: (nodeName: string, message: string, ...args: any[]) => void;
27
+ debug: (nodeName: string, message: string, ...args: any[]) => void;
28
+ };
29
+ /**
30
+ * 连接器日志 - 便捷方法
31
+ */
32
+ export declare const connector: {
33
+ info: (nodeName: string, message: string, ...args: any[]) => void;
34
+ warn: (nodeName: string, message: string, ...args: any[]) => void;
35
+ error: (nodeName: string, message: string, ...args: any[]) => void;
36
+ debug: (nodeName: string, message: string, ...args: any[]) => void;
37
+ };
38
+ /**
39
+ * 监控日志 - 便捷方法
40
+ */
41
+ export declare const monitor: {
42
+ info: (nodeName: string, message: string, ...args: any[]) => void;
43
+ warn: (nodeName: string, message: string, ...args: any[]) => void;
44
+ error: (nodeName: string, message: string, ...args: any[]) => void;
45
+ debug: (nodeName: string, message: string, ...args: any[]) => void;
46
+ };
47
+ /**
48
+ * 通知日志 - 便捷方法
49
+ */
50
+ export declare const notify: {
51
+ info: (message: string, ...args: any[]) => void;
52
+ warn: (message: string, ...args: any[]) => void;
53
+ error: (message: string, ...args: any[]) => void;
54
+ debug: (message: string, ...args: any[]) => void;
55
+ success: (message: string, ...args: any[]) => void;
56
+ };
57
+ /**
58
+ * 指令日志 - 便捷方法
59
+ */
60
+ export declare const command: {
61
+ info: (message: string, ...args: any[]) => void;
62
+ warn: (message: string, ...args: any[]) => void;
63
+ error: (message: string, ...args: any[]) => void;
64
+ debug: (message: string, ...args: any[]) => void;
65
+ };
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = exports.notify = exports.monitor = exports.connector = exports.node = exports.commandLogger = exports.notifierLogger = exports.monitorLogger = exports.connectorLogger = exports.nodeLogger = exports.logger = void 0;
4
+ exports.createLogger = createLogger;
5
+ exports.formatMessage = formatMessage;
6
+ /**
7
+ * 统一日志模块
8
+ * 提供带命名空间的日志器,支持调试模式
9
+ */
10
+ const koishi_1 = require("koishi");
11
+ // 主日志器
12
+ exports.logger = new koishi_1.Logger('docker-control');
13
+ // 子日志器工厂
14
+ function createSubLogger(name) {
15
+ return exports.logger.extend(name);
16
+ }
17
+ // 子日志器
18
+ exports.nodeLogger = createSubLogger('node');
19
+ exports.connectorLogger = createSubLogger('connector');
20
+ exports.monitorLogger = createSubLogger('monitor');
21
+ exports.notifierLogger = createSubLogger('notifier');
22
+ exports.commandLogger = createSubLogger('command');
23
+ /**
24
+ * 创建带命名空间的日志器
25
+ */
26
+ function createLogger(name) {
27
+ return createSubLogger(name);
28
+ }
29
+ /**
30
+ * 格式化日志消息
31
+ */
32
+ function formatMessage(message, ...args) {
33
+ if (args.length === 0)
34
+ return message;
35
+ try {
36
+ return args.length > 1
37
+ ? message.replace(/\{(\d+)\}/g, (_, index) => String(args[index] || ''))
38
+ : String(args[0]);
39
+ }
40
+ catch {
41
+ return message;
42
+ }
43
+ }
44
+ /**
45
+ * 节点操作日志 - 便捷方法
46
+ */
47
+ exports.node = {
48
+ info: (nodeName, message, ...args) => exports.nodeLogger.info(`[${nodeName}] ${formatMessage(message, ...args)}`),
49
+ warn: (nodeName, message, ...args) => exports.nodeLogger.warn(`[${nodeName}] ${formatMessage(message, ...args)}`),
50
+ error: (nodeName, message, ...args) => exports.nodeLogger.error(`[${nodeName}] ${formatMessage(message, ...args)}`),
51
+ debug: (nodeName, message, ...args) => exports.nodeLogger.debug(`[${nodeName}] ${formatMessage(message, ...args)}`),
52
+ };
53
+ /**
54
+ * 连接器日志 - 便捷方法
55
+ */
56
+ exports.connector = {
57
+ info: (nodeName, message, ...args) => exports.connectorLogger.info(`[${nodeName}] ${formatMessage(message, ...args)}`),
58
+ warn: (nodeName, message, ...args) => exports.connectorLogger.warn(`[${nodeName}] ${formatMessage(message, ...args)}`),
59
+ error: (nodeName, message, ...args) => exports.connectorLogger.error(`[${nodeName}] ${formatMessage(message, ...args)}`),
60
+ debug: (nodeName, message, ...args) => exports.connectorLogger.debug(`[${nodeName}] ${formatMessage(message, ...args)}`),
61
+ };
62
+ /**
63
+ * 监控日志 - 便捷方法
64
+ */
65
+ exports.monitor = {
66
+ info: (nodeName, message, ...args) => exports.monitorLogger.info(`[${nodeName}] ${formatMessage(message, ...args)}`),
67
+ warn: (nodeName, message, ...args) => exports.monitorLogger.warn(`[${nodeName}] ${formatMessage(message, ...args)}`),
68
+ error: (nodeName, message, ...args) => exports.monitorLogger.error(`[${nodeName}] ${formatMessage(message, ...args)}`),
69
+ debug: (nodeName, message, ...args) => exports.monitorLogger.debug(`[${nodeName}] ${formatMessage(message, ...args)}`),
70
+ };
71
+ /**
72
+ * 通知日志 - 便捷方法
73
+ */
74
+ exports.notify = {
75
+ info: (message, ...args) => exports.notifierLogger.info(formatMessage(message, ...args)),
76
+ warn: (message, ...args) => exports.notifierLogger.warn(formatMessage(message, ...args)),
77
+ error: (message, ...args) => exports.notifierLogger.error(formatMessage(message, ...args)),
78
+ debug: (message, ...args) => exports.notifierLogger.debug(formatMessage(message, ...args)),
79
+ success: (message, ...args) => exports.notifierLogger.info(`✓ ${formatMessage(message, ...args)}`),
80
+ };
81
+ /**
82
+ * 指令日志 - 便捷方法
83
+ */
84
+ exports.command = {
85
+ info: (message, ...args) => exports.commandLogger.info(formatMessage(message, ...args)),
86
+ warn: (message, ...args) => exports.commandLogger.warn(formatMessage(message, ...args)),
87
+ error: (message, ...args) => exports.commandLogger.error(formatMessage(message, ...args)),
88
+ debug: (message, ...args) => exports.commandLogger.debug(formatMessage(message, ...args)),
89
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 流处理工具
3
+ */
4
+ /**
5
+ * 将 Stream 转换为字符串
6
+ */
7
+ export declare function streamToString(stream: NodeJS.ReadableStream): Promise<string>;
8
+ /**
9
+ * 将字符串转换为 Stream
10
+ */
11
+ export declare function stringToStream(content: string, encoding?: BufferEncoding): NodeJS.ReadableStream;
12
+ /**
13
+ * 合并多个 Stream
14
+ */
15
+ export declare function mergeStreams(streams: NodeJS.ReadableStream[]): NodeJS.ReadableStream;
16
+ /**
17
+ * 限流 Stream
18
+ * 控制数据输出的速度
19
+ */
20
+ export declare function throttleStream(stream: NodeJS.ReadableStream, maxBytesPerSecond: number): NodeJS.ReadableStream;
21
+ /**
22
+ * 解码 Stream (处理 ANSI 转义码)
23
+ */
24
+ export declare function decodeStream(stream: NodeJS.ReadableStream): NodeJS.ReadableStream;
25
+ /**
26
+ * 截取 Stream 的最后 N 行
27
+ */
28
+ export declare function tailStream(stream: NodeJS.ReadableStream, maxLines: number): NodeJS.ReadableStream;