teh-bot 1.0.3 → 1.0.5
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/README.md +571 -349
- package/{index.js → dist/index.cjs} +130 -132
- package/{index.d.ts → dist/index.d.ts} +518 -23
- package/dist/index.mjs +1002 -0
- package/package.json +27 -11
|
@@ -65,7 +65,7 @@ class TelegramBot extends EventEmitter {
|
|
|
65
65
|
method: "POST",
|
|
66
66
|
headers: {
|
|
67
67
|
...headers,
|
|
68
|
-
"User-Agent": "TehBot/1.0.
|
|
68
|
+
"User-Agent": "TehBot/1.0.5 (Modern; High-Performance)",
|
|
69
69
|
},
|
|
70
70
|
timeout: this.options.requestTimeout,
|
|
71
71
|
}
|
|
@@ -86,16 +86,46 @@ 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
|
}
|
|
94
100
|
})
|
|
95
101
|
}
|
|
96
102
|
|
|
103
|
+
async getMe() {
|
|
104
|
+
return this.request("getMe")
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async getUpdates(params = {}) {
|
|
108
|
+
return this.request("getUpdates", {
|
|
109
|
+
offset: this.offset,
|
|
110
|
+
timeout: this.options.pollingTimeout,
|
|
111
|
+
allowed_updates: this.options.allowedUpdates,
|
|
112
|
+
...params,
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async setWebhook(url, params = {}) {
|
|
117
|
+
return this.request("setWebhook", { url, ...params })
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async deleteWebhook(params = {}) {
|
|
121
|
+
return this.request("deleteWebhook", params)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async getWebhookInfo() {
|
|
125
|
+
return this.request("getWebhookInfo")
|
|
126
|
+
}
|
|
127
|
+
|
|
97
128
|
async sendMessage(chatId, content, options = {}) {
|
|
98
|
-
// content can be string (text) or object { image: ..., caption: ... }
|
|
99
129
|
if (typeof content === "string") {
|
|
100
130
|
return this.request("sendMessage", { chat_id: chatId, text: content, ...options })
|
|
101
131
|
}
|
|
@@ -601,7 +631,6 @@ class TelegramBot extends EventEmitter {
|
|
|
601
631
|
_createContext(update) {
|
|
602
632
|
const message = update.message || update.edited_message || update.channel_post || update.callback_query?.message
|
|
603
633
|
|
|
604
|
-
// Fallback logic for chat extraction from various update types
|
|
605
634
|
const chat =
|
|
606
635
|
update.message?.chat ||
|
|
607
636
|
update.callback_query?.message?.chat ||
|
|
@@ -636,7 +665,6 @@ class TelegramBot extends EventEmitter {
|
|
|
636
665
|
chatMember: update.chat_member,
|
|
637
666
|
}
|
|
638
667
|
|
|
639
|
-
// Baileys-style simplified response
|
|
640
668
|
ctx.send = (content, opts) => {
|
|
641
669
|
const chatId =
|
|
642
670
|
ctx.chat?.id ||
|
|
@@ -646,7 +674,7 @@ class TelegramBot extends EventEmitter {
|
|
|
646
674
|
from?.id
|
|
647
675
|
|
|
648
676
|
if (!chatId) {
|
|
649
|
-
console.error("[
|
|
677
|
+
console.error("[Teh] Context update without valid chatId destination:", JSON.stringify(update))
|
|
650
678
|
throw new Error("[Teh] Cannot send message: chat_id could not be resolved from this update context")
|
|
651
679
|
}
|
|
652
680
|
return this.sendMessage(chatId, content, opts)
|
|
@@ -663,13 +691,11 @@ class TelegramBot extends EventEmitter {
|
|
|
663
691
|
})
|
|
664
692
|
}
|
|
665
693
|
|
|
666
|
-
// Context helpers for media
|
|
667
694
|
ctx.replyWithPhoto = (photo, opts) => ctx.send({ image: photo, ...opts })
|
|
668
695
|
ctx.replyWithVideo = (video, opts) => ctx.send({ video, ...opts })
|
|
669
696
|
ctx.replyWithAudio = (audio, opts) => ctx.send({ audio, ...opts })
|
|
670
697
|
ctx.replyWithDocument = (doc, opts) => ctx.send({ document: doc, ...opts })
|
|
671
698
|
|
|
672
|
-
// Helper methods for callback queries
|
|
673
699
|
ctx.answerCallbackQuery = (options = {}) => {
|
|
674
700
|
if (!ctx.callbackQuery?.id) return Promise.resolve(false)
|
|
675
701
|
return this.answerCallbackQuery(ctx.callbackQuery.id, options)
|
|
@@ -677,7 +703,6 @@ class TelegramBot extends EventEmitter {
|
|
|
677
703
|
|
|
678
704
|
ctx.editMessageText = (text, options = {}) => {
|
|
679
705
|
if (!ctx.callbackQuery?.message) {
|
|
680
|
-
// If it's an inline message (no message object), we need the inline_message_id
|
|
681
706
|
if (ctx.callbackQuery?.inline_message_id) {
|
|
682
707
|
return this.editMessageText(text, {
|
|
683
708
|
inline_message_id: ctx.callbackQuery.inline_message_id,
|
|
@@ -716,116 +741,103 @@ class TelegramBot extends EventEmitter {
|
|
|
716
741
|
}
|
|
717
742
|
|
|
718
743
|
_buildMultipartStream(formData, boundary) {
|
|
719
|
-
const stream = new Readable({
|
|
744
|
+
const stream = new Readable({
|
|
745
|
+
read() {},
|
|
746
|
+
})
|
|
720
747
|
const nl = "\r\n"
|
|
721
748
|
;(async () => {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
749
|
+
try {
|
|
750
|
+
for (const [key, value] of Object.entries(formData)) {
|
|
751
|
+
if (value === undefined || value === null) continue
|
|
752
|
+
|
|
753
|
+
stream.push(`--${boundary}${nl}`)
|
|
754
|
+
if (value && typeof value === "object" && (value.data || value instanceof Stream || Buffer.isBuffer(value))) {
|
|
755
|
+
const fileData = value.data || value
|
|
756
|
+
const filename = value.filename || `file_${Date.now()}.jpg`
|
|
757
|
+
const contentType = value.contentType || this._getMime(extname(filename)) || "image/jpeg"
|
|
758
|
+
|
|
759
|
+
stream.push(`Content-Disposition: form-data; name="${key}"; filename="${filename}"${nl}`)
|
|
760
|
+
stream.push(`Content-Type: ${contentType}${nl}${nl}`)
|
|
761
|
+
|
|
762
|
+
if (fileData instanceof Stream) {
|
|
763
|
+
fileData.pipe(stream, { end: false })
|
|
764
|
+
await new Promise((resolve, reject) => {
|
|
765
|
+
fileData.on("end", resolve)
|
|
766
|
+
fileData.on("error", reject)
|
|
767
|
+
})
|
|
768
|
+
} else {
|
|
769
|
+
stream.push(fileData)
|
|
770
|
+
}
|
|
733
771
|
} else {
|
|
734
|
-
stream.push(
|
|
772
|
+
stream.push(`Content-Disposition: form-data; name="${key}"${nl}${nl}`)
|
|
773
|
+
stream.push(String(value))
|
|
735
774
|
}
|
|
736
|
-
|
|
737
|
-
stream.push(`Content-Disposition: form-data; name="${key}"${nl}${nl}`)
|
|
738
|
-
stream.push(typeof value === "object" ? JSON.stringify(value) : String(value))
|
|
775
|
+
stream.push(`${nl}`)
|
|
739
776
|
}
|
|
740
|
-
stream.push(nl)
|
|
777
|
+
stream.push(`--${boundary}--${nl}`)
|
|
778
|
+
stream.push(null)
|
|
779
|
+
} catch (err) {
|
|
780
|
+
stream.destroy(err)
|
|
741
781
|
}
|
|
742
|
-
stream.push(`--${boundary}--${nl}`)
|
|
743
|
-
stream.push(null)
|
|
744
782
|
})()
|
|
745
|
-
|
|
746
783
|
return stream
|
|
747
784
|
}
|
|
748
785
|
|
|
749
|
-
async _prepareFile(source, type) {
|
|
750
|
-
if (source instanceof Stream) return { data: source, contentType: this._getMime(type) }
|
|
751
|
-
if (Buffer.isBuffer(source)) return { data: source, contentType: this._getMime(type) }
|
|
752
|
-
|
|
753
|
-
if (typeof source === "string") {
|
|
754
|
-
if (source.startsWith("http")) {
|
|
755
|
-
// Fetch remote URL and return as stream
|
|
756
|
-
return new Promise((resolve, reject) => {
|
|
757
|
-
const client = source.startsWith("https") ? https : http
|
|
758
|
-
client
|
|
759
|
-
.get(source, (res) => {
|
|
760
|
-
if (res.statusCode !== 200) {
|
|
761
|
-
return reject(new Error(`Failed to fetch remote file: ${res.statusCode}`))
|
|
762
|
-
}
|
|
763
|
-
resolve({
|
|
764
|
-
data: res,
|
|
765
|
-
filename: basename(new URL(source).pathname) || `file_${Date.now()}`,
|
|
766
|
-
contentType: res.headers["content-type"] || this._getMime(type),
|
|
767
|
-
})
|
|
768
|
-
})
|
|
769
|
-
.on("error", reject)
|
|
770
|
-
})
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
// Local file
|
|
774
|
-
return {
|
|
775
|
-
data: createReadStream(source),
|
|
776
|
-
filename: basename(source),
|
|
777
|
-
contentType: this._getMime(extname(source)),
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
return source
|
|
781
|
-
}
|
|
782
|
-
|
|
783
786
|
_getMime(ext) {
|
|
784
|
-
const
|
|
785
|
-
photo: "image/jpeg",
|
|
786
|
-
video: "video/mp4",
|
|
787
|
-
audio: "audio/mpeg",
|
|
787
|
+
const mimeTypes = {
|
|
788
788
|
".jpg": "image/jpeg",
|
|
789
|
+
".jpeg": "image/jpeg",
|
|
789
790
|
".png": "image/png",
|
|
791
|
+
".gif": "image/gif",
|
|
790
792
|
".mp4": "video/mp4",
|
|
793
|
+
".avi": "video/x-msvideo",
|
|
794
|
+
".webm": "video/webm",
|
|
795
|
+
".mp3": "audio/mpeg",
|
|
796
|
+
".ogg": "audio/ogg",
|
|
797
|
+
".wav": "audio/wav",
|
|
798
|
+
".pdf": "application/pdf",
|
|
799
|
+
".doc": "application/msword",
|
|
800
|
+
".txt": "text/plain",
|
|
791
801
|
}
|
|
792
|
-
return
|
|
802
|
+
return mimeTypes[ext.toLowerCase()] || "application/octet-stream"
|
|
793
803
|
}
|
|
794
804
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
flat[key] = JSON.stringify(value)
|
|
800
|
-
} else {
|
|
801
|
-
flat[key] = value
|
|
805
|
+
async _prepareFile(source, type) {
|
|
806
|
+
if (typeof source === "string") {
|
|
807
|
+
if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
808
|
+
return source
|
|
802
809
|
}
|
|
803
|
-
}
|
|
804
|
-
return flat
|
|
805
|
-
}
|
|
806
810
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
811
|
+
try {
|
|
812
|
+
const stat = statSync(source)
|
|
813
|
+
if (stat.isFile()) {
|
|
814
|
+
return {
|
|
815
|
+
data: createReadStream(source),
|
|
816
|
+
filename: basename(source),
|
|
817
|
+
contentType: this._getMime(extname(source)),
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
} catch (e) {
|
|
821
|
+
return source
|
|
822
|
+
}
|
|
823
|
+
}
|
|
815
824
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
825
|
+
if (Buffer.isBuffer(source) || source instanceof Stream) {
|
|
826
|
+
return {
|
|
827
|
+
data: source,
|
|
828
|
+
filename: `file_${Date.now()}.jpg`,
|
|
829
|
+
contentType: "image/jpeg",
|
|
830
|
+
}
|
|
831
|
+
}
|
|
819
832
|
|
|
820
|
-
|
|
821
|
-
return this.request("setWebhook", {
|
|
822
|
-
url,
|
|
823
|
-
...options,
|
|
824
|
-
})
|
|
833
|
+
return source
|
|
825
834
|
}
|
|
826
835
|
|
|
827
|
-
|
|
828
|
-
|
|
836
|
+
_formatError(response) {
|
|
837
|
+
const error = new Error(response.description || "Telegram API Error")
|
|
838
|
+
error.response = response
|
|
839
|
+
error.errorCode = response.error_code
|
|
840
|
+
return error
|
|
829
841
|
}
|
|
830
842
|
|
|
831
843
|
static InlineKeyboard() {
|
|
@@ -836,25 +848,22 @@ class TelegramBot extends EventEmitter {
|
|
|
836
848
|
return new ReplyKeyboardBuilder()
|
|
837
849
|
}
|
|
838
850
|
|
|
839
|
-
static RemoveKeyboard(
|
|
840
|
-
return { remove_keyboard: true
|
|
851
|
+
static RemoveKeyboard() {
|
|
852
|
+
return { remove_keyboard: true }
|
|
841
853
|
}
|
|
842
854
|
|
|
843
|
-
static ForceReply(
|
|
844
|
-
|
|
845
|
-
if (placeholder) obj.input_field_placeholder = placeholder
|
|
846
|
-
return obj
|
|
855
|
+
static ForceReply() {
|
|
856
|
+
return { force_reply: true }
|
|
847
857
|
}
|
|
848
858
|
}
|
|
849
859
|
|
|
850
860
|
class InlineKeyboardBuilder {
|
|
851
861
|
constructor() {
|
|
852
|
-
this.keyboard = []
|
|
853
|
-
this.currentRow = []
|
|
862
|
+
this.keyboard = [[]]
|
|
854
863
|
}
|
|
855
864
|
|
|
856
865
|
text(text, callbackData) {
|
|
857
|
-
this.
|
|
866
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
858
867
|
text,
|
|
859
868
|
callback_data: callbackData,
|
|
860
869
|
})
|
|
@@ -862,7 +871,7 @@ class InlineKeyboardBuilder {
|
|
|
862
871
|
}
|
|
863
872
|
|
|
864
873
|
url(text, url) {
|
|
865
|
-
this.
|
|
874
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
866
875
|
text,
|
|
867
876
|
url,
|
|
868
877
|
})
|
|
@@ -870,7 +879,7 @@ class InlineKeyboardBuilder {
|
|
|
870
879
|
}
|
|
871
880
|
|
|
872
881
|
login(text, loginUrl) {
|
|
873
|
-
this.
|
|
882
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
874
883
|
text,
|
|
875
884
|
login_url: loginUrl,
|
|
876
885
|
})
|
|
@@ -878,7 +887,7 @@ class InlineKeyboardBuilder {
|
|
|
878
887
|
}
|
|
879
888
|
|
|
880
889
|
switchInline(text, query = "") {
|
|
881
|
-
this.
|
|
890
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
882
891
|
text,
|
|
883
892
|
switch_inline_query: query,
|
|
884
893
|
})
|
|
@@ -886,7 +895,7 @@ class InlineKeyboardBuilder {
|
|
|
886
895
|
}
|
|
887
896
|
|
|
888
897
|
switchInlineCurrent(text, query = "") {
|
|
889
|
-
this.
|
|
898
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
890
899
|
text,
|
|
891
900
|
switch_inline_query_current_chat: query,
|
|
892
901
|
})
|
|
@@ -894,7 +903,7 @@ class InlineKeyboardBuilder {
|
|
|
894
903
|
}
|
|
895
904
|
|
|
896
905
|
game(text) {
|
|
897
|
-
this.
|
|
906
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
898
907
|
text,
|
|
899
908
|
callback_game: {},
|
|
900
909
|
})
|
|
@@ -902,7 +911,7 @@ class InlineKeyboardBuilder {
|
|
|
902
911
|
}
|
|
903
912
|
|
|
904
913
|
pay(text) {
|
|
905
|
-
this.
|
|
914
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
906
915
|
text,
|
|
907
916
|
pay: true,
|
|
908
917
|
})
|
|
@@ -910,35 +919,28 @@ class InlineKeyboardBuilder {
|
|
|
910
919
|
}
|
|
911
920
|
|
|
912
921
|
row() {
|
|
913
|
-
|
|
914
|
-
this.keyboard.push([...this.currentRow])
|
|
915
|
-
this.currentRow = []
|
|
916
|
-
}
|
|
922
|
+
this.keyboard.push([])
|
|
917
923
|
return this
|
|
918
924
|
}
|
|
919
925
|
|
|
920
926
|
build() {
|
|
921
|
-
this.
|
|
922
|
-
return {
|
|
923
|
-
inline_keyboard: this.keyboard,
|
|
924
|
-
}
|
|
927
|
+
return { inline_keyboard: this.keyboard }
|
|
925
928
|
}
|
|
926
929
|
}
|
|
927
930
|
|
|
928
931
|
class ReplyKeyboardBuilder {
|
|
929
932
|
constructor() {
|
|
930
|
-
this.keyboard = []
|
|
931
|
-
this.currentRow = []
|
|
933
|
+
this.keyboard = [[]]
|
|
932
934
|
this.options = {}
|
|
933
935
|
}
|
|
934
936
|
|
|
935
937
|
text(text) {
|
|
936
|
-
this.
|
|
938
|
+
this.keyboard[this.keyboard.length - 1].push({ text })
|
|
937
939
|
return this
|
|
938
940
|
}
|
|
939
941
|
|
|
940
942
|
requestContact(text) {
|
|
941
|
-
this.
|
|
943
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
942
944
|
text,
|
|
943
945
|
request_contact: true,
|
|
944
946
|
})
|
|
@@ -946,15 +948,15 @@ class ReplyKeyboardBuilder {
|
|
|
946
948
|
}
|
|
947
949
|
|
|
948
950
|
requestLocation(text) {
|
|
949
|
-
this.
|
|
951
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
950
952
|
text,
|
|
951
953
|
request_location: true,
|
|
952
954
|
})
|
|
953
955
|
return this
|
|
954
956
|
}
|
|
955
957
|
|
|
956
|
-
requestPoll(text, type) {
|
|
957
|
-
this.
|
|
958
|
+
requestPoll(text, type = "quiz") {
|
|
959
|
+
this.keyboard[this.keyboard.length - 1].push({
|
|
958
960
|
text,
|
|
959
961
|
request_poll: { type },
|
|
960
962
|
})
|
|
@@ -962,10 +964,7 @@ class ReplyKeyboardBuilder {
|
|
|
962
964
|
}
|
|
963
965
|
|
|
964
966
|
row() {
|
|
965
|
-
|
|
966
|
-
this.keyboard.push([...this.currentRow])
|
|
967
|
-
this.currentRow = []
|
|
968
|
-
}
|
|
967
|
+
this.keyboard.push([])
|
|
969
968
|
return this
|
|
970
969
|
}
|
|
971
970
|
|
|
@@ -990,7 +989,6 @@ class ReplyKeyboardBuilder {
|
|
|
990
989
|
}
|
|
991
990
|
|
|
992
991
|
build() {
|
|
993
|
-
this.row()
|
|
994
992
|
return {
|
|
995
993
|
keyboard: this.keyboard,
|
|
996
994
|
...this.options,
|