teh-bot 1.0.2 → 1.0.4
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/index.js +130 -48
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -86,8 +86,14 @@ class TelegramBot extends EventEmitter {
|
|
|
86
86
|
})
|
|
87
87
|
|
|
88
88
|
req.on("error", reject)
|
|
89
|
-
if (body instanceof Stream)
|
|
90
|
-
|
|
89
|
+
if (body instanceof Stream) {
|
|
90
|
+
body.pipe(req)
|
|
91
|
+
body.on("end", () => req.end())
|
|
92
|
+
body.on("error", (err) => {
|
|
93
|
+
req.destroy()
|
|
94
|
+
reject(err)
|
|
95
|
+
})
|
|
96
|
+
} else {
|
|
91
97
|
req.write(body)
|
|
92
98
|
req.end()
|
|
93
99
|
}
|
|
@@ -384,6 +390,11 @@ class TelegramBot extends EventEmitter {
|
|
|
384
390
|
}
|
|
385
391
|
|
|
386
392
|
command(cmd, handler) {
|
|
393
|
+
if (handler === undefined) {
|
|
394
|
+
const commandName = typeof cmd === "string" ? (cmd.startsWith("/") ? cmd : `/${cmd}`) : ""
|
|
395
|
+
return this.commands.get(commandName)
|
|
396
|
+
}
|
|
397
|
+
|
|
387
398
|
if (typeof handler !== "function") {
|
|
388
399
|
throw new Error("Command handler must be a function")
|
|
389
400
|
}
|
|
@@ -597,16 +608,17 @@ class TelegramBot extends EventEmitter {
|
|
|
597
608
|
const message = update.message || update.edited_message || update.channel_post || update.callback_query?.message
|
|
598
609
|
|
|
599
610
|
// Fallback logic for chat extraction from various update types
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
611
|
+
const chat =
|
|
612
|
+
update.message?.chat ||
|
|
613
|
+
update.callback_query?.message?.chat ||
|
|
614
|
+
update.my_chat_member?.chat ||
|
|
615
|
+
update.chat_member?.chat ||
|
|
616
|
+
update.chat_join_request?.chat ||
|
|
617
|
+
update.edited_message?.chat ||
|
|
618
|
+
update.channel_post?.chat
|
|
607
619
|
|
|
608
620
|
const from =
|
|
609
|
-
message?.from ||
|
|
621
|
+
update.message?.from ||
|
|
610
622
|
update.callback_query?.from ||
|
|
611
623
|
update.inline_query?.from ||
|
|
612
624
|
update.chosen_inline_result?.from ||
|
|
@@ -632,18 +644,24 @@ class TelegramBot extends EventEmitter {
|
|
|
632
644
|
|
|
633
645
|
// Baileys-style simplified response
|
|
634
646
|
ctx.send = (content, opts) => {
|
|
635
|
-
const chatId =
|
|
647
|
+
const chatId =
|
|
648
|
+
ctx.chat?.id ||
|
|
649
|
+
update.callback_query?.from?.id ||
|
|
650
|
+
update.inline_query?.from?.id ||
|
|
651
|
+
update.message?.from?.id ||
|
|
652
|
+
from?.id
|
|
653
|
+
|
|
636
654
|
if (!chatId) {
|
|
637
|
-
console.error("[v0] Context update without
|
|
638
|
-
throw new Error("[Teh] Cannot send message: chat_id
|
|
655
|
+
console.error("[v0] Context update without valid chatId destination:", JSON.stringify(update))
|
|
656
|
+
throw new Error("[Teh] Cannot send message: chat_id could not be resolved from this update context")
|
|
639
657
|
}
|
|
640
658
|
return this.sendMessage(chatId, content, opts)
|
|
641
659
|
}
|
|
642
660
|
|
|
643
661
|
ctx.reply = (text, opts) => {
|
|
644
|
-
const chatId = ctx.chat?.id || update.callback_query?.from?.id
|
|
662
|
+
const chatId = ctx.chat?.id || update.callback_query?.from?.id || from?.id
|
|
645
663
|
if (!chatId) {
|
|
646
|
-
throw new Error("[Teh] Cannot reply: chat_id
|
|
664
|
+
throw new Error("[Teh] Cannot reply: chat_id could not be resolved from this update context")
|
|
647
665
|
}
|
|
648
666
|
return this.sendMessage(chatId, text, {
|
|
649
667
|
reply_to_message_id: ctx.message?.message_id,
|
|
@@ -704,54 +722,68 @@ class TelegramBot extends EventEmitter {
|
|
|
704
722
|
}
|
|
705
723
|
|
|
706
724
|
_buildMultipartStream(formData, boundary) {
|
|
707
|
-
const stream = new Readable({
|
|
725
|
+
const stream = new Readable({
|
|
726
|
+
read() {},
|
|
727
|
+
})
|
|
708
728
|
const nl = "\r\n"
|
|
709
729
|
;(async () => {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
730
|
+
try {
|
|
731
|
+
for (const [key, value] of Object.entries(formData)) {
|
|
732
|
+
if (value === undefined || value === null) continue
|
|
733
|
+
|
|
734
|
+
stream.push(`--${boundary}${nl}`)
|
|
735
|
+
if (value && typeof value === "object" && (value.data || value instanceof Stream || Buffer.isBuffer(value))) {
|
|
736
|
+
const fileData = value.data || value
|
|
737
|
+
const filename = value.filename || `file_${Date.now()}.jpg`
|
|
738
|
+
const contentType = value.contentType || this._getMime(extname(filename)) || "image/jpeg"
|
|
739
|
+
|
|
740
|
+
stream.push(`Content-Disposition: form-data; name="${key}"; filename="${filename}"${nl}`)
|
|
741
|
+
stream.push(`Content-Type: ${contentType}${nl}${nl}`)
|
|
742
|
+
|
|
743
|
+
if (fileData instanceof Stream) {
|
|
744
|
+
for await (const chunk of fileData) {
|
|
745
|
+
const canPush = stream.push(chunk)
|
|
746
|
+
if (!canPush) {
|
|
747
|
+
await new Promise((resolve) => stream.once("drain", resolve))
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
} else {
|
|
751
|
+
stream.push(fileData)
|
|
752
|
+
}
|
|
721
753
|
} else {
|
|
722
|
-
stream.push(
|
|
754
|
+
stream.push(`Content-Disposition: form-data; name="${key}"${nl}${nl}`)
|
|
755
|
+
stream.push(typeof value === "object" ? JSON.stringify(value) : String(value))
|
|
723
756
|
}
|
|
724
|
-
|
|
725
|
-
stream.push(`Content-Disposition: form-data; name="${key}"${nl}${nl}`)
|
|
726
|
-
stream.push(typeof value === "object" ? JSON.stringify(value) : String(value))
|
|
757
|
+
stream.push(nl)
|
|
727
758
|
}
|
|
728
|
-
stream.push(nl)
|
|
759
|
+
stream.push(`--${boundary}--${nl}`)
|
|
760
|
+
} catch (err) {
|
|
761
|
+
console.error("[v0] Error building multipart stream:", err)
|
|
762
|
+
} finally {
|
|
763
|
+
stream.push(null)
|
|
729
764
|
}
|
|
730
|
-
stream.push(`--${boundary}--${nl}`)
|
|
731
|
-
stream.push(null)
|
|
732
765
|
})()
|
|
733
766
|
|
|
734
767
|
return stream
|
|
735
768
|
}
|
|
736
769
|
|
|
737
770
|
async _prepareFile(source, type) {
|
|
738
|
-
|
|
739
|
-
|
|
771
|
+
const defaultMime = this._getMime(type) || "image/jpeg"
|
|
772
|
+
|
|
773
|
+
if (source instanceof Stream) return { data: source, contentType: defaultMime }
|
|
774
|
+
if (Buffer.isBuffer(source)) return { data: source, contentType: defaultMime }
|
|
740
775
|
|
|
741
776
|
if (typeof source === "string") {
|
|
742
777
|
if (source.startsWith("http")) {
|
|
743
|
-
// Fetch remote URL and return as stream
|
|
744
778
|
return new Promise((resolve, reject) => {
|
|
745
|
-
|
|
746
|
-
client
|
|
779
|
+
https
|
|
747
780
|
.get(source, (res) => {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}
|
|
781
|
+
const filename = basename(new URL(source).pathname) || `file_${Date.now()}.jpg`
|
|
782
|
+
const contentType = res.headers["content-type"] || defaultMime
|
|
751
783
|
resolve({
|
|
752
784
|
data: res,
|
|
753
|
-
filename:
|
|
754
|
-
contentType:
|
|
785
|
+
filename: filename,
|
|
786
|
+
contentType: contentType,
|
|
755
787
|
})
|
|
756
788
|
})
|
|
757
789
|
.on("error", reject)
|
|
@@ -759,25 +791,34 @@ class TelegramBot extends EventEmitter {
|
|
|
759
791
|
}
|
|
760
792
|
|
|
761
793
|
// Local file
|
|
794
|
+
const filename = basename(source)
|
|
762
795
|
return {
|
|
763
796
|
data: createReadStream(source),
|
|
764
|
-
filename:
|
|
765
|
-
contentType: this._getMime(extname(
|
|
797
|
+
filename: filename,
|
|
798
|
+
contentType: this._getMime(extname(filename)) || defaultMime,
|
|
766
799
|
}
|
|
767
800
|
}
|
|
768
801
|
return source
|
|
769
802
|
}
|
|
770
803
|
|
|
771
|
-
_getMime(
|
|
804
|
+
_getMime(extOrType) {
|
|
772
805
|
const mimes = {
|
|
773
806
|
photo: "image/jpeg",
|
|
807
|
+
image: "image/jpeg",
|
|
774
808
|
video: "video/mp4",
|
|
775
809
|
audio: "audio/mpeg",
|
|
810
|
+
document: "application/octet-stream",
|
|
776
811
|
".jpg": "image/jpeg",
|
|
812
|
+
".jpeg": "image/jpeg",
|
|
777
813
|
".png": "image/png",
|
|
814
|
+
".gif": "image/gif",
|
|
778
815
|
".mp4": "video/mp4",
|
|
816
|
+
".mp3": "audio/mpeg",
|
|
817
|
+
".pdf": "application/pdf",
|
|
818
|
+
".zip": "application/zip",
|
|
779
819
|
}
|
|
780
|
-
|
|
820
|
+
const key = extOrType?.toLowerCase()
|
|
821
|
+
return mimes[key] || (key?.startsWith(".") ? "application/octet-stream" : mimes.photo)
|
|
781
822
|
}
|
|
782
823
|
|
|
783
824
|
_flattenOptions(options) {
|
|
@@ -816,6 +857,47 @@ class TelegramBot extends EventEmitter {
|
|
|
816
857
|
return this.request("getWebhookInfo")
|
|
817
858
|
}
|
|
818
859
|
|
|
860
|
+
async getMe() {
|
|
861
|
+
return this.request("getMe")
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
async _sendFile(method, chatId, source, type, options = {}) {
|
|
865
|
+
const formData = {
|
|
866
|
+
chat_id: chatId,
|
|
867
|
+
[type]: await this._prepareFile(source, type),
|
|
868
|
+
...this._flattenOptions(options),
|
|
869
|
+
}
|
|
870
|
+
return this.request(method, {}, formData)
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
async setMyCommands(commands, options = {}) {
|
|
874
|
+
return this.request("setMyCommands", { commands, ...options })
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
async getMyCommands(options = {}) {
|
|
878
|
+
return this.request("getMyCommands", options)
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
async setChatMenuButton(options = {}) {
|
|
882
|
+
return this.request("setChatMenuButton", options)
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
async getChatMenuButton(options = {}) {
|
|
886
|
+
return this.request("getChatMenuButton", options)
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
async getUserProfilePhotos(userId, options = {}) {
|
|
890
|
+
return this.request("getUserProfilePhotos", { user_id: userId, ...options })
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
async createChatInviteLink(chatId, options = {}) {
|
|
894
|
+
return this.request("createChatInviteLink", { chat_id: chatId, ...options })
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
async revokeChatInviteLink(chatId, inviteLink) {
|
|
898
|
+
return this.request("revokeChatInviteLink", { chat_id: chatId, invite_link: inviteLink })
|
|
899
|
+
}
|
|
900
|
+
|
|
819
901
|
static InlineKeyboard() {
|
|
820
902
|
return new InlineKeyboardBuilder()
|
|
821
903
|
}
|