@theowlops/channelhub 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/LICENSE +21 -0
- package/README.md +179 -0
- package/bin/cli.ts +36 -0
- package/dist/bridges/mcp/index.d.ts +14 -0
- package/dist/bridges/mcp/index.js +96 -0
- package/dist/bridges/webhook/index.d.ts +32 -0
- package/dist/bridges/webhook/index.js +123 -0
- package/dist/channels/discord/adapter.d.ts +24 -0
- package/dist/channels/discord/index.d.ts +1 -0
- package/dist/channels/discord/index.js +130 -0
- package/dist/channels/slack/adapter.d.ts +20 -0
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.js +122 -0
- package/dist/channels/telegram/adapter.d.ts +21 -0
- package/dist/channels/telegram/index.d.ts +2 -0
- package/dist/channels/telegram/index.js +179 -0
- package/dist/channels/telegram/types.d.ts +6 -0
- package/dist/channels/zalo/adapter.d.ts +22 -0
- package/dist/channels/zalo/index.d.ts +5 -0
- package/dist/channels/zalo/index.js +38337 -0
- package/dist/commands/modules/general.d.ts +4 -0
- package/dist/commands/modules/group.d.ts +4 -0
- package/dist/commands/modules/reaction.d.ts +4 -0
- package/dist/commands/router.d.ts +7 -0
- package/dist/commands/types.d.ts +15 -0
- package/dist/config/env.d.ts +13 -0
- package/dist/core/adapter.d.ts +12 -0
- package/dist/core/bus.d.ts +12 -0
- package/dist/core/context.d.ts +9 -0
- package/dist/core/hub.d.ts +14 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +99 -0
- package/dist/core/types.d.ts +63 -0
- package/dist/index.cjs +39235 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +39191 -0
- package/dist/login_personal.js +60 -0
- package/dist/oa/client.d.ts +25 -0
- package/dist/oa/index.d.ts +3 -0
- package/dist/oa/index.js +556 -0
- package/dist/personal/client.d.ts +162 -0
- package/dist/personal/index.d.ts +5 -0
- package/dist/personal/index.js +37098 -0
- package/package.json +107 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ZaloPersonalBot } from "../personal/client.js";
|
|
2
|
+
export interface CommandContext {
|
|
3
|
+
bot: ZaloPersonalBot;
|
|
4
|
+
msg: any;
|
|
5
|
+
args: string[];
|
|
6
|
+
isGroup: boolean;
|
|
7
|
+
threadId: string;
|
|
8
|
+
}
|
|
9
|
+
export interface Command {
|
|
10
|
+
name: string;
|
|
11
|
+
aliases?: string[];
|
|
12
|
+
description: string;
|
|
13
|
+
groupOnly?: boolean;
|
|
14
|
+
execute: (ctx: CommandContext) => Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { ChannelType, IChannelAdapter, MediaPayload, SendOptions, SentMessageResult } from "./types";
|
|
3
|
+
export declare abstract class BaseChannel extends EventEmitter implements IChannelAdapter {
|
|
4
|
+
abstract readonly name: ChannelType;
|
|
5
|
+
private _connected;
|
|
6
|
+
isConnected(): boolean;
|
|
7
|
+
protected setConnected(value: boolean): void;
|
|
8
|
+
abstract connect(): Promise<void>;
|
|
9
|
+
abstract disconnect(): Promise<void>;
|
|
10
|
+
abstract sendText(chatId: string, text: string, options?: SendOptions): Promise<SentMessageResult>;
|
|
11
|
+
abstract sendMedia(chatId: string, media: MediaPayload, options?: SendOptions): Promise<SentMessageResult>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { ChannelStatus, UnifiedMessage } from "./types";
|
|
3
|
+
export interface ChannelEvents {
|
|
4
|
+
message: [msg: UnifiedMessage];
|
|
5
|
+
error: [err: Error];
|
|
6
|
+
status: [status: ChannelStatus];
|
|
7
|
+
}
|
|
8
|
+
export declare class ChannelEventBus extends EventEmitter {
|
|
9
|
+
emitMessage(msg: UnifiedMessage): boolean;
|
|
10
|
+
emitError(err: Error): boolean;
|
|
11
|
+
emitStatus(status: ChannelStatus): boolean;
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IChannelAdapter, MediaPayload, SendOptions, SentMessageResult, UnifiedMessage } from "./types";
|
|
2
|
+
export interface MessageContext {
|
|
3
|
+
message: UnifiedMessage;
|
|
4
|
+
channel: IChannelAdapter;
|
|
5
|
+
reply: (text: string, options?: SendOptions) => Promise<SentMessageResult>;
|
|
6
|
+
replyMedia: (media: MediaPayload, options?: SendOptions) => Promise<SentMessageResult>;
|
|
7
|
+
react: (emoji: string) => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createMessageContext(message: UnifiedMessage, channel: IChannelAdapter): MessageContext;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type MessageContext } from "./context";
|
|
2
|
+
import type { IChannelAdapter } from "./types";
|
|
3
|
+
export type MessageHandler = (ctx: MessageContext) => Promise<void> | void;
|
|
4
|
+
export declare class ChannelHub {
|
|
5
|
+
private _channels;
|
|
6
|
+
private _bus;
|
|
7
|
+
private _messageHandlers;
|
|
8
|
+
register(channel: IChannelAdapter): this;
|
|
9
|
+
getChannel(name: string): IChannelAdapter | undefined;
|
|
10
|
+
listChannels(): string[];
|
|
11
|
+
onMessage(handler: MessageHandler): this;
|
|
12
|
+
start(): Promise<void>;
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// src/core/adapter.ts
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
|
|
4
|
+
class BaseChannel extends EventEmitter {
|
|
5
|
+
_connected = false;
|
|
6
|
+
isConnected() {
|
|
7
|
+
return this._connected;
|
|
8
|
+
}
|
|
9
|
+
setConnected(value) {
|
|
10
|
+
const changed = this._connected !== value;
|
|
11
|
+
this._connected = value;
|
|
12
|
+
if (changed) {
|
|
13
|
+
this.emit("status", value ? "connected" : "disconnected");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// src/core/bus.ts
|
|
18
|
+
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
19
|
+
|
|
20
|
+
class ChannelEventBus extends EventEmitter2 {
|
|
21
|
+
emitMessage(msg) {
|
|
22
|
+
return this.emit("message", msg);
|
|
23
|
+
}
|
|
24
|
+
emitError(err) {
|
|
25
|
+
return this.emit("error", err);
|
|
26
|
+
}
|
|
27
|
+
emitStatus(status) {
|
|
28
|
+
return this.emit("status", status);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// src/core/context.ts
|
|
32
|
+
function createMessageContext(message, channel) {
|
|
33
|
+
return {
|
|
34
|
+
message,
|
|
35
|
+
channel,
|
|
36
|
+
reply: (text, options) => channel.sendText(message.chat.id, text, {
|
|
37
|
+
replyToId: message.id,
|
|
38
|
+
...options
|
|
39
|
+
}),
|
|
40
|
+
replyMedia: (media, options) => channel.sendMedia(message.chat.id, media, {
|
|
41
|
+
replyToId: message.id,
|
|
42
|
+
...options
|
|
43
|
+
}),
|
|
44
|
+
react: async (emoji) => {
|
|
45
|
+
if (channel.addReaction) {
|
|
46
|
+
await channel.addReaction(message.chat.id, message.id, emoji);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// src/core/hub.ts
|
|
52
|
+
class ChannelHub {
|
|
53
|
+
_channels = new Map;
|
|
54
|
+
_bus = new ChannelEventBus;
|
|
55
|
+
_messageHandlers = [];
|
|
56
|
+
register(channel) {
|
|
57
|
+
if (this._channels.has(channel.name)) {
|
|
58
|
+
throw new Error(`Channel '${channel.name}' is already registered in ChannelHub.`);
|
|
59
|
+
}
|
|
60
|
+
this._channels.set(channel.name, channel);
|
|
61
|
+
channel.on("message", (msg) => {
|
|
62
|
+
this._bus.emitMessage(msg);
|
|
63
|
+
const ctx = createMessageContext(msg, channel);
|
|
64
|
+
for (const handler of this._messageHandlers) {
|
|
65
|
+
Promise.resolve(handler(ctx)).catch((err) => {
|
|
66
|
+
this._bus.emitError(err);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
channel.on("error", (err) => {
|
|
71
|
+
this._bus.emitError(err);
|
|
72
|
+
});
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
getChannel(name) {
|
|
76
|
+
return this._channels.get(name);
|
|
77
|
+
}
|
|
78
|
+
listChannels() {
|
|
79
|
+
return Array.from(this._channels.keys());
|
|
80
|
+
}
|
|
81
|
+
onMessage(handler) {
|
|
82
|
+
this._messageHandlers.push(handler);
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
async start() {
|
|
86
|
+
const promises = Array.from(this._channels.values()).map((ch) => ch.connect());
|
|
87
|
+
await Promise.all(promises);
|
|
88
|
+
}
|
|
89
|
+
async stop() {
|
|
90
|
+
const promises = Array.from(this._channels.values()).map((ch) => ch.disconnect());
|
|
91
|
+
await Promise.all(promises);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
BaseChannel,
|
|
96
|
+
ChannelEventBus,
|
|
97
|
+
ChannelHub,
|
|
98
|
+
createMessageContext
|
|
99
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export type ChannelType = "zalo" | "telegram" | "discord" | "slack" | string;
|
|
2
|
+
export type ChatType = "dm" | "group" | "channel";
|
|
3
|
+
export type MediaType = "image" | "video" | "audio" | "file";
|
|
4
|
+
export interface MediaAttachment {
|
|
5
|
+
type: MediaType;
|
|
6
|
+
url: string;
|
|
7
|
+
filename?: string;
|
|
8
|
+
mimeType?: string;
|
|
9
|
+
size?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface UnifiedMessage {
|
|
12
|
+
id: string;
|
|
13
|
+
channel: ChannelType;
|
|
14
|
+
sender: {
|
|
15
|
+
id: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
username?: string;
|
|
18
|
+
avatarUrl?: string;
|
|
19
|
+
isBot?: boolean;
|
|
20
|
+
};
|
|
21
|
+
chat: {
|
|
22
|
+
id: string;
|
|
23
|
+
type: ChatType;
|
|
24
|
+
title?: string;
|
|
25
|
+
};
|
|
26
|
+
content: {
|
|
27
|
+
text: string;
|
|
28
|
+
attachments?: MediaAttachment[];
|
|
29
|
+
replyToId?: string;
|
|
30
|
+
};
|
|
31
|
+
raw: unknown;
|
|
32
|
+
timestamp: number;
|
|
33
|
+
}
|
|
34
|
+
export interface SendOptions {
|
|
35
|
+
replyToId?: string;
|
|
36
|
+
quote?: boolean;
|
|
37
|
+
metadata?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
export interface MediaPayload {
|
|
40
|
+
type: MediaType;
|
|
41
|
+
source: string | Buffer | Uint8Array;
|
|
42
|
+
filename?: string;
|
|
43
|
+
caption?: string;
|
|
44
|
+
mimeType?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface SentMessageResult {
|
|
47
|
+
messageId: string;
|
|
48
|
+
chatId: string;
|
|
49
|
+
timestamp: number;
|
|
50
|
+
}
|
|
51
|
+
export type ChannelStatus = "connected" | "disconnected" | "reconnecting";
|
|
52
|
+
export interface IChannelAdapter {
|
|
53
|
+
readonly name: ChannelType;
|
|
54
|
+
connect(): Promise<void>;
|
|
55
|
+
disconnect(): Promise<void>;
|
|
56
|
+
isConnected(): boolean;
|
|
57
|
+
sendText(chatId: string, text: string, options?: SendOptions): Promise<SentMessageResult>;
|
|
58
|
+
sendMedia(chatId: string, media: MediaPayload, options?: SendOptions): Promise<SentMessageResult>;
|
|
59
|
+
addReaction?(chatId: string, messageId: string, emoji: string): Promise<void>;
|
|
60
|
+
on(event: "message", handler: (msg: UnifiedMessage) => Promise<void> | void): this;
|
|
61
|
+
on(event: "error", handler: (err: Error) => void): this;
|
|
62
|
+
on(event: "status", handler: (status: ChannelStatus) => void): this;
|
|
63
|
+
}
|