@theowlops/channelhub 1.0.0 → 1.1.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/dist/channels/discord/adapter.d.ts +2 -0
- package/dist/channels/discord/index.js +13 -0
- package/dist/channels/slack/adapter.d.ts +2 -0
- package/dist/channels/slack/index.js +13 -0
- package/dist/channels/telegram/adapter.d.ts +2 -0
- package/dist/channels/telegram/index.js +18 -0
- package/dist/channels/zalo/adapter.d.ts +13 -1
- package/dist/channels/zalo/index.js +168 -31
- package/dist/core/context.d.ts +3 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +132 -0
- package/dist/core/stream.d.ts +16 -0
- package/dist/core/types.d.ts +2 -0
- package/dist/index.cjs +345 -33
- package/dist/index.js +345 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20519,9 +20519,9 @@ var require_websocket_server = __commonJS(function(exports, module) {
|
|
|
20519
20519
|
});
|
|
20520
20520
|
|
|
20521
20521
|
// node_modules/ws/wrapper.mjs
|
|
20522
|
-
var
|
|
20522
|
+
var import_stream2, import_extension, import_permessage_deflate, import_receiver, import_sender, import_subprotocol, import_websocket, import_websocket_server, wrapper_default;
|
|
20523
20523
|
var init_wrapper = __esm(() => {
|
|
20524
|
-
|
|
20524
|
+
import_stream2 = __toESM(require_stream(), 1);
|
|
20525
20525
|
import_extension = __toESM(require_extension(), 1);
|
|
20526
20526
|
import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
|
|
20527
20527
|
import_receiver = __toESM(require_receiver(), 1);
|
|
@@ -37499,6 +37499,126 @@ class ChannelEventBus extends EventEmitter2 {
|
|
|
37499
37499
|
return this.emit("status", status);
|
|
37500
37500
|
}
|
|
37501
37501
|
}
|
|
37502
|
+
// src/core/stream.ts
|
|
37503
|
+
class SmartStreamer {
|
|
37504
|
+
adapter;
|
|
37505
|
+
options;
|
|
37506
|
+
constructor(adapter, options = {}) {
|
|
37507
|
+
this.adapter = adapter;
|
|
37508
|
+
this.options = {
|
|
37509
|
+
editDebounceMs: 1000,
|
|
37510
|
+
typingIntervalMs: 4000,
|
|
37511
|
+
chunkMode: "sentence",
|
|
37512
|
+
minSentenceLength: 60,
|
|
37513
|
+
initialPlaceholder: "...",
|
|
37514
|
+
...options
|
|
37515
|
+
};
|
|
37516
|
+
}
|
|
37517
|
+
async stream(chatId, tokenStream, sendOptions) {
|
|
37518
|
+
let typingActive = true;
|
|
37519
|
+
const triggerTyping = async () => {
|
|
37520
|
+
if (this.adapter.sendTyping) {
|
|
37521
|
+
try {
|
|
37522
|
+
await this.adapter.sendTyping(chatId);
|
|
37523
|
+
} catch {}
|
|
37524
|
+
}
|
|
37525
|
+
};
|
|
37526
|
+
await triggerTyping();
|
|
37527
|
+
const typingTimer = setInterval(() => {
|
|
37528
|
+
if (typingActive)
|
|
37529
|
+
triggerTyping();
|
|
37530
|
+
}, this.options.typingIntervalMs);
|
|
37531
|
+
try {
|
|
37532
|
+
if (typeof this.adapter.editText === "function") {
|
|
37533
|
+
return await this.streamWithEdit(chatId, tokenStream, sendOptions);
|
|
37534
|
+
} else {
|
|
37535
|
+
return await this.streamWithoutEdit(chatId, tokenStream, sendOptions);
|
|
37536
|
+
}
|
|
37537
|
+
} finally {
|
|
37538
|
+
typingActive = false;
|
|
37539
|
+
clearInterval(typingTimer);
|
|
37540
|
+
}
|
|
37541
|
+
}
|
|
37542
|
+
async streamWithEdit(chatId, tokenStream, sendOptions) {
|
|
37543
|
+
let accumulated = "";
|
|
37544
|
+
let sentMsg = null;
|
|
37545
|
+
let lastEditTime = 0;
|
|
37546
|
+
let pendingEditTimeout = null;
|
|
37547
|
+
const performEdit = async (text) => {
|
|
37548
|
+
if (sentMsg && this.adapter.editText) {
|
|
37549
|
+
await this.adapter.editText(chatId, sentMsg.messageId, text);
|
|
37550
|
+
lastEditTime = Date.now();
|
|
37551
|
+
}
|
|
37552
|
+
};
|
|
37553
|
+
for await (const chunk of tokenStream) {
|
|
37554
|
+
accumulated += chunk;
|
|
37555
|
+
if (!sentMsg) {
|
|
37556
|
+
sentMsg = await this.adapter.sendText(chatId, accumulated.trim() || this.options.initialPlaceholder, sendOptions);
|
|
37557
|
+
lastEditTime = Date.now();
|
|
37558
|
+
continue;
|
|
37559
|
+
}
|
|
37560
|
+
const now = Date.now();
|
|
37561
|
+
const elapsed = now - lastEditTime;
|
|
37562
|
+
if (elapsed >= this.options.editDebounceMs) {
|
|
37563
|
+
if (pendingEditTimeout) {
|
|
37564
|
+
clearTimeout(pendingEditTimeout);
|
|
37565
|
+
pendingEditTimeout = null;
|
|
37566
|
+
}
|
|
37567
|
+
await performEdit(accumulated);
|
|
37568
|
+
} else if (!pendingEditTimeout) {
|
|
37569
|
+
pendingEditTimeout = setTimeout(async () => {
|
|
37570
|
+
pendingEditTimeout = null;
|
|
37571
|
+
await performEdit(accumulated);
|
|
37572
|
+
}, this.options.editDebounceMs - elapsed);
|
|
37573
|
+
}
|
|
37574
|
+
}
|
|
37575
|
+
if (pendingEditTimeout) {
|
|
37576
|
+
clearTimeout(pendingEditTimeout);
|
|
37577
|
+
pendingEditTimeout = null;
|
|
37578
|
+
}
|
|
37579
|
+
if (sentMsg && accumulated) {
|
|
37580
|
+
await performEdit(accumulated);
|
|
37581
|
+
return [sentMsg];
|
|
37582
|
+
} else if (!sentMsg && accumulated) {
|
|
37583
|
+
const res = await this.adapter.sendText(chatId, accumulated, sendOptions);
|
|
37584
|
+
return [res];
|
|
37585
|
+
}
|
|
37586
|
+
return sentMsg ? [sentMsg] : [];
|
|
37587
|
+
}
|
|
37588
|
+
async streamWithoutEdit(chatId, tokenStream, sendOptions) {
|
|
37589
|
+
const results = [];
|
|
37590
|
+
if (this.options.chunkMode === "accumulate") {
|
|
37591
|
+
let accumulated = "";
|
|
37592
|
+
for await (const chunk of tokenStream) {
|
|
37593
|
+
accumulated += chunk;
|
|
37594
|
+
}
|
|
37595
|
+
if (accumulated.trim()) {
|
|
37596
|
+
const res = await this.adapter.sendText(chatId, accumulated, sendOptions);
|
|
37597
|
+
results.push(res);
|
|
37598
|
+
}
|
|
37599
|
+
return results;
|
|
37600
|
+
}
|
|
37601
|
+
let buffer = "";
|
|
37602
|
+
const sentenceEndRegex = /[.?!;\n]\s*$/;
|
|
37603
|
+
for await (const chunk of tokenStream) {
|
|
37604
|
+
buffer += chunk;
|
|
37605
|
+
if (buffer.length >= this.options.minSentenceLength && sentenceEndRegex.test(buffer.trimEnd())) {
|
|
37606
|
+
const textToSend = buffer.trim();
|
|
37607
|
+
if (textToSend) {
|
|
37608
|
+
const res = await this.adapter.sendText(chatId, textToSend, sendOptions);
|
|
37609
|
+
results.push(res);
|
|
37610
|
+
buffer = "";
|
|
37611
|
+
}
|
|
37612
|
+
}
|
|
37613
|
+
}
|
|
37614
|
+
if (buffer.trim()) {
|
|
37615
|
+
const res = await this.adapter.sendText(chatId, buffer.trim(), sendOptions);
|
|
37616
|
+
results.push(res);
|
|
37617
|
+
}
|
|
37618
|
+
return results;
|
|
37619
|
+
}
|
|
37620
|
+
}
|
|
37621
|
+
|
|
37502
37622
|
// src/core/context.ts
|
|
37503
37623
|
function createMessageContext(message, channel) {
|
|
37504
37624
|
return {
|
|
@@ -37516,6 +37636,17 @@ function createMessageContext(message, channel) {
|
|
|
37516
37636
|
if (channel.addReaction) {
|
|
37517
37637
|
await channel.addReaction(message.chat.id, message.id, emoji);
|
|
37518
37638
|
}
|
|
37639
|
+
},
|
|
37640
|
+
sendTyping: async () => {
|
|
37641
|
+
if (channel.sendTyping) {
|
|
37642
|
+
await channel.sendTyping(message.chat.id);
|
|
37643
|
+
}
|
|
37644
|
+
},
|
|
37645
|
+
stream: async (tokenStream, options) => {
|
|
37646
|
+
const streamer = new SmartStreamer(channel, options);
|
|
37647
|
+
return await streamer.stream(message.chat.id, tokenStream, {
|
|
37648
|
+
replyToId: message.id
|
|
37649
|
+
});
|
|
37519
37650
|
}
|
|
37520
37651
|
};
|
|
37521
37652
|
}
|
|
@@ -37563,14 +37694,47 @@ class ChannelHub {
|
|
|
37563
37694
|
}
|
|
37564
37695
|
}
|
|
37565
37696
|
// src/channels/zalo/adapter.ts
|
|
37697
|
+
var EMOJI_TO_ZALO = {
|
|
37698
|
+
"❤️": "HEART",
|
|
37699
|
+
"\uD83D\uDC96": "HEART",
|
|
37700
|
+
"\uD83D\uDC4D": "LIKE",
|
|
37701
|
+
"\uD83D\uDE06": "HAHA",
|
|
37702
|
+
"\uD83D\uDE02": "TEARS_OF_JOY",
|
|
37703
|
+
"\uD83D\uDE2E": "WOW",
|
|
37704
|
+
"\uD83D\uDE2D": "CRY",
|
|
37705
|
+
"\uD83D\uDE21": "ANGRY",
|
|
37706
|
+
"\uD83D\uDE18": "KISS",
|
|
37707
|
+
"\uD83D\uDCA9": "SHIT",
|
|
37708
|
+
"\uD83C\uDF39": "ROSE",
|
|
37709
|
+
"\uD83D\uDC94": "BROKEN_HEART",
|
|
37710
|
+
"\uD83D\uDC4E": "DISLIKE",
|
|
37711
|
+
"\uD83D\uDE0D": "LOVE",
|
|
37712
|
+
"\uD83E\uDD14": "CONFUSED",
|
|
37713
|
+
"\uD83D\uDE09": "WINK",
|
|
37714
|
+
heart: "HEART",
|
|
37715
|
+
like: "LIKE",
|
|
37716
|
+
haha: "HAHA",
|
|
37717
|
+
wow: "WOW",
|
|
37718
|
+
cry: "CRY",
|
|
37719
|
+
angry: "ANGRY"
|
|
37720
|
+
};
|
|
37721
|
+
|
|
37566
37722
|
class ZaloChannelAdapter extends BaseChannel {
|
|
37567
37723
|
name = "zalo";
|
|
37568
37724
|
api;
|
|
37569
37725
|
ownId;
|
|
37570
37726
|
config;
|
|
37727
|
+
threadTypeCache = new Map;
|
|
37728
|
+
messageCache = new Map;
|
|
37729
|
+
sendQueue = Promise.resolve();
|
|
37571
37730
|
constructor(config = {}) {
|
|
37572
37731
|
super();
|
|
37573
|
-
this.config =
|
|
37732
|
+
this.config = {
|
|
37733
|
+
minDelayMs: 300,
|
|
37734
|
+
maxDelayMs: 800,
|
|
37735
|
+
cacheLimit: 1000,
|
|
37736
|
+
...config
|
|
37737
|
+
};
|
|
37574
37738
|
if (config.api) {
|
|
37575
37739
|
this.api = config.api;
|
|
37576
37740
|
}
|
|
@@ -37605,17 +37769,101 @@ class ZaloChannelAdapter extends BaseChannel {
|
|
|
37605
37769
|
if (!this.api?.listener?.on)
|
|
37606
37770
|
return;
|
|
37607
37771
|
this.api.listener.on("message", (raw) => {
|
|
37772
|
+
this.recordInbound(raw);
|
|
37608
37773
|
const unified = this.normalizeMessage(raw);
|
|
37609
37774
|
if (unified) {
|
|
37610
37775
|
this.emit("message", unified);
|
|
37611
37776
|
}
|
|
37612
37777
|
});
|
|
37778
|
+
const onSessionDrop = (err) => {
|
|
37779
|
+
this.emit("session:expired", {
|
|
37780
|
+
reason: "SESSION_EXPIRED_OR_DROPPED",
|
|
37781
|
+
raw: err,
|
|
37782
|
+
requiresQrScan: true
|
|
37783
|
+
});
|
|
37784
|
+
this.setConnected(false);
|
|
37785
|
+
};
|
|
37786
|
+
this.api.listener.on("closed", onSessionDrop);
|
|
37787
|
+
this.api.listener.on("error", (err) => {
|
|
37788
|
+
const msg = String(err?.message || err);
|
|
37789
|
+
if (msg.includes("1002") || msg.includes("session") || msg.includes("auth")) {
|
|
37790
|
+
onSessionDrop(err);
|
|
37791
|
+
}
|
|
37792
|
+
});
|
|
37613
37793
|
if (this.api.listener.start) {
|
|
37614
37794
|
try {
|
|
37615
37795
|
this.api.listener.start();
|
|
37616
37796
|
} catch {}
|
|
37617
37797
|
}
|
|
37618
37798
|
}
|
|
37799
|
+
recordInbound(raw) {
|
|
37800
|
+
if (!raw)
|
|
37801
|
+
return;
|
|
37802
|
+
const data = raw.data || raw;
|
|
37803
|
+
const isGroup = raw.type === 1 || raw.type === "group" || Boolean(raw.isGroup);
|
|
37804
|
+
const chatId = String(raw.threadId || data.idTo || data.threadId || "");
|
|
37805
|
+
const msgId = String(data.msgId || raw.msgId || "");
|
|
37806
|
+
const cliMsgId = data.cliMsgId ? String(data.cliMsgId) : undefined;
|
|
37807
|
+
const uidFrom = String(data.uidFrom || raw.senderId || "");
|
|
37808
|
+
const content = typeof data.content === "string" ? data.content : data.msg || "";
|
|
37809
|
+
if (chatId) {
|
|
37810
|
+
this.threadTypeCache.set(chatId, isGroup ? 1 : 0);
|
|
37811
|
+
}
|
|
37812
|
+
const cached = {
|
|
37813
|
+
msgId,
|
|
37814
|
+
cliMsgId,
|
|
37815
|
+
uidFrom,
|
|
37816
|
+
content,
|
|
37817
|
+
threadId: chatId,
|
|
37818
|
+
isGroup
|
|
37819
|
+
};
|
|
37820
|
+
const limit = this.config.cacheLimit || 1000;
|
|
37821
|
+
if (this.messageCache.size >= limit) {
|
|
37822
|
+
const firstKey = this.messageCache.keys().next().value;
|
|
37823
|
+
if (firstKey)
|
|
37824
|
+
this.messageCache.delete(firstKey);
|
|
37825
|
+
}
|
|
37826
|
+
if (msgId)
|
|
37827
|
+
this.messageCache.set(msgId, cached);
|
|
37828
|
+
if (cliMsgId)
|
|
37829
|
+
this.messageCache.set(cliMsgId, cached);
|
|
37830
|
+
}
|
|
37831
|
+
resolveThreadType(chatId) {
|
|
37832
|
+
if (this.threadTypeCache.has(chatId)) {
|
|
37833
|
+
return this.threadTypeCache.get(chatId);
|
|
37834
|
+
}
|
|
37835
|
+
return this.config.defaultIsGroup ?? true ? 1 : 0;
|
|
37836
|
+
}
|
|
37837
|
+
resolveQuote(replyToId) {
|
|
37838
|
+
if (!replyToId)
|
|
37839
|
+
return;
|
|
37840
|
+
const cached = this.messageCache.get(replyToId);
|
|
37841
|
+
if (cached) {
|
|
37842
|
+
return {
|
|
37843
|
+
msgId: cached.msgId,
|
|
37844
|
+
cliMsgId: cached.cliMsgId,
|
|
37845
|
+
uidFrom: cached.uidFrom,
|
|
37846
|
+
content: cached.content
|
|
37847
|
+
};
|
|
37848
|
+
}
|
|
37849
|
+
return replyToId;
|
|
37850
|
+
}
|
|
37851
|
+
async enqueueSend(operation) {
|
|
37852
|
+
const minDelay = this.config.minDelayMs ?? 300;
|
|
37853
|
+
const maxDelay = this.config.maxDelayMs ?? 800;
|
|
37854
|
+
const execute = async () => {
|
|
37855
|
+
if (maxDelay > 0) {
|
|
37856
|
+
const jitter = Math.floor(minDelay + Math.random() * Math.max(0, maxDelay - minDelay));
|
|
37857
|
+
if (jitter > 0) {
|
|
37858
|
+
await new Promise((r) => setTimeout(r, jitter));
|
|
37859
|
+
}
|
|
37860
|
+
}
|
|
37861
|
+
return await operation();
|
|
37862
|
+
};
|
|
37863
|
+
const next = this.sendQueue.then(execute, execute);
|
|
37864
|
+
this.sendQueue = next.catch(() => {});
|
|
37865
|
+
return next;
|
|
37866
|
+
}
|
|
37619
37867
|
normalizeMessage(raw) {
|
|
37620
37868
|
if (!raw)
|
|
37621
37869
|
return null;
|
|
@@ -37649,41 +37897,60 @@ class ZaloChannelAdapter extends BaseChannel {
|
|
|
37649
37897
|
async sendText(chatId, text, options) {
|
|
37650
37898
|
if (!this.api)
|
|
37651
37899
|
throw new Error("Zalo adapter is not connected.");
|
|
37652
|
-
const
|
|
37653
|
-
const
|
|
37654
|
-
const payload = { msg: text, quote
|
|
37655
|
-
|
|
37656
|
-
|
|
37657
|
-
|
|
37658
|
-
|
|
37659
|
-
|
|
37660
|
-
|
|
37661
|
-
|
|
37900
|
+
const threadType = this.resolveThreadType(chatId);
|
|
37901
|
+
const quote = this.resolveQuote(options?.replyToId);
|
|
37902
|
+
const payload = { msg: text, quote };
|
|
37903
|
+
return await this.enqueueSend(async () => {
|
|
37904
|
+
const res = await this.api.sendMessage(payload, chatId, threadType);
|
|
37905
|
+
const resMsgId = res?.message?.msgId || res?.msgId || `z-${Date.now()}`;
|
|
37906
|
+
return {
|
|
37907
|
+
messageId: String(resMsgId),
|
|
37908
|
+
chatId,
|
|
37909
|
+
timestamp: Date.now()
|
|
37910
|
+
};
|
|
37911
|
+
});
|
|
37662
37912
|
}
|
|
37663
|
-
async sendMedia(chatId, media,
|
|
37913
|
+
async sendMedia(chatId, media, options) {
|
|
37664
37914
|
if (!this.api)
|
|
37665
37915
|
throw new Error("Zalo adapter is not connected.");
|
|
37666
|
-
const
|
|
37667
|
-
const
|
|
37668
|
-
|
|
37669
|
-
|
|
37670
|
-
|
|
37671
|
-
|
|
37672
|
-
|
|
37673
|
-
|
|
37674
|
-
|
|
37675
|
-
|
|
37676
|
-
|
|
37677
|
-
|
|
37678
|
-
|
|
37679
|
-
|
|
37680
|
-
|
|
37681
|
-
|
|
37916
|
+
const threadType = this.resolveThreadType(chatId);
|
|
37917
|
+
const quote = this.resolveQuote(options?.replyToId);
|
|
37918
|
+
return await this.enqueueSend(async () => {
|
|
37919
|
+
let res;
|
|
37920
|
+
if (media.type === "image") {
|
|
37921
|
+
res = await this.api.sendMessage({ msg: media.caption || "", attachments: [media.source], quote }, chatId, threadType);
|
|
37922
|
+
} else if (media.type === "video" && this.api.sendVideo) {
|
|
37923
|
+
res = await this.api.sendVideo({ video: media.source, msg: media.caption || "", quote }, chatId, threadType);
|
|
37924
|
+
} else {
|
|
37925
|
+
res = await this.api.sendMessage({ msg: media.caption || "", attachments: [media.source], quote }, chatId, threadType);
|
|
37926
|
+
}
|
|
37927
|
+
const resMsgId = res?.message?.msgId || res?.msgId || `z-${Date.now()}`;
|
|
37928
|
+
return {
|
|
37929
|
+
messageId: String(resMsgId),
|
|
37930
|
+
chatId,
|
|
37931
|
+
timestamp: Date.now()
|
|
37932
|
+
};
|
|
37933
|
+
});
|
|
37682
37934
|
}
|
|
37683
37935
|
async addReaction(chatId, messageId, emoji) {
|
|
37684
|
-
if (this.api?.addReaction)
|
|
37685
|
-
|
|
37686
|
-
|
|
37936
|
+
if (!this.api?.addReaction)
|
|
37937
|
+
return;
|
|
37938
|
+
const threadType = this.resolveThreadType(chatId);
|
|
37939
|
+
const isGroup = threadType === 1;
|
|
37940
|
+
const reactionCode = EMOJI_TO_ZALO[emoji] || emoji;
|
|
37941
|
+
const cached = this.messageCache.get(messageId);
|
|
37942
|
+
const cliMsgId = cached?.cliMsgId || messageId;
|
|
37943
|
+
await this.enqueueSend(async () => {
|
|
37944
|
+
await this.api.addReaction(chatId, messageId, cliMsgId, reactionCode, threadType);
|
|
37945
|
+
});
|
|
37946
|
+
}
|
|
37947
|
+
async sendTyping(chatId) {
|
|
37948
|
+
if (!this.api?.sendTypingEvent)
|
|
37949
|
+
return;
|
|
37950
|
+
const threadType = this.resolveThreadType(chatId);
|
|
37951
|
+
try {
|
|
37952
|
+
await this.api.sendTypingEvent(chatId, true, threadType);
|
|
37953
|
+
} catch {}
|
|
37687
37954
|
}
|
|
37688
37955
|
}
|
|
37689
37956
|
// src/personal/client.ts
|
|
@@ -38561,6 +38828,24 @@ class TelegramChannelAdapter extends BaseChannel {
|
|
|
38561
38828
|
reaction: [{ type: "emoji", emoji }]
|
|
38562
38829
|
});
|
|
38563
38830
|
}
|
|
38831
|
+
async sendTyping(chatId) {
|
|
38832
|
+
await this.callApi("sendChatAction", {
|
|
38833
|
+
chat_id: chatId,
|
|
38834
|
+
action: "typing"
|
|
38835
|
+
});
|
|
38836
|
+
}
|
|
38837
|
+
async editText(chatId, messageId, text) {
|
|
38838
|
+
const res = await this.callApi("editMessageText", {
|
|
38839
|
+
chat_id: chatId,
|
|
38840
|
+
message_id: Number(messageId),
|
|
38841
|
+
text
|
|
38842
|
+
});
|
|
38843
|
+
return {
|
|
38844
|
+
messageId: String(res.message_id || messageId),
|
|
38845
|
+
chatId,
|
|
38846
|
+
timestamp: Date.now()
|
|
38847
|
+
};
|
|
38848
|
+
}
|
|
38564
38849
|
}
|
|
38565
38850
|
// src/channels/discord/adapter.ts
|
|
38566
38851
|
class DiscordChannelAdapter extends BaseChannel {
|
|
@@ -38671,6 +38956,19 @@ class DiscordChannelAdapter extends BaseChannel {
|
|
|
38671
38956
|
const encoded = encodeURIComponent(emoji);
|
|
38672
38957
|
await this.callApi("PUT", `/channels/${chatId}/messages/${messageId}/reactions/${encoded}/@me`);
|
|
38673
38958
|
}
|
|
38959
|
+
async sendTyping(chatId) {
|
|
38960
|
+
await this.callApi("POST", `/channels/${chatId}/typing`, {});
|
|
38961
|
+
}
|
|
38962
|
+
async editText(chatId, messageId, text) {
|
|
38963
|
+
const res = await this.callApi("PATCH", `/channels/${chatId}/messages/${messageId}`, {
|
|
38964
|
+
content: text
|
|
38965
|
+
});
|
|
38966
|
+
return {
|
|
38967
|
+
messageId: String(res.id || messageId),
|
|
38968
|
+
chatId,
|
|
38969
|
+
timestamp: Date.now()
|
|
38970
|
+
};
|
|
38971
|
+
}
|
|
38674
38972
|
}
|
|
38675
38973
|
// src/channels/slack/adapter.ts
|
|
38676
38974
|
class SlackChannelAdapter extends BaseChannel {
|
|
@@ -38773,6 +39071,19 @@ class SlackChannelAdapter extends BaseChannel {
|
|
|
38773
39071
|
name: cleanName
|
|
38774
39072
|
});
|
|
38775
39073
|
}
|
|
39074
|
+
async sendTyping(chatId) {}
|
|
39075
|
+
async editText(chatId, messageId, text) {
|
|
39076
|
+
const res = await this.callApi("chat.update", {
|
|
39077
|
+
channel: chatId,
|
|
39078
|
+
ts: messageId,
|
|
39079
|
+
text
|
|
39080
|
+
});
|
|
39081
|
+
return {
|
|
39082
|
+
messageId: String(res.ts || messageId),
|
|
39083
|
+
chatId,
|
|
39084
|
+
timestamp: Date.now()
|
|
39085
|
+
};
|
|
39086
|
+
}
|
|
38776
39087
|
}
|
|
38777
39088
|
// src/bridges/mcp/index.ts
|
|
38778
39089
|
function getChannelHubMcpTools() {
|
|
@@ -39177,6 +39488,7 @@ export {
|
|
|
39177
39488
|
CommandRouter,
|
|
39178
39489
|
DiscordChannelAdapter,
|
|
39179
39490
|
SlackChannelAdapter,
|
|
39491
|
+
SmartStreamer,
|
|
39180
39492
|
TelegramChannelAdapter,
|
|
39181
39493
|
WebhookBridge,
|
|
39182
39494
|
Zalo,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theowlops/channelhub",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "ChannelHub SDK - Unified multi-channel messaging toolkit (Zalo, Telegram, Discord, Slack) for AI agents, standalone bots, and enterprise automation.",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"main": "dist/index.cjs",
|