teh-bot 1.0.0 → 1.0.2
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 +80 -50
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -19,10 +19,6 @@ const DEFAULT_OPTIONS = {
|
|
|
19
19
|
baseApiUrl: "https://api.telegram.org",
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
* Modern, High-Performance Telegram Bot API Module
|
|
24
|
-
* Inspired by Baileys simplified API and Telegraf's robust system
|
|
25
|
-
*/
|
|
26
22
|
class TelegramBot extends EventEmitter {
|
|
27
23
|
constructor(token, options = {}) {
|
|
28
24
|
super()
|
|
@@ -121,50 +117,13 @@ class TelegramBot extends EventEmitter {
|
|
|
121
117
|
if (!mediaType) return this.request("sendMessage", { chat_id: chatId, text: content.text, ...options })
|
|
122
118
|
|
|
123
119
|
const method = `send${mediaType.charAt(0).toUpperCase() + mediaType.slice(1)}`
|
|
124
|
-
const formData = { chat_id: chatId, caption, ...rest }
|
|
125
|
-
|
|
126
|
-
if (
|
|
127
|
-
mediaSource instanceof Stream ||
|
|
128
|
-
Buffer.isBuffer(mediaSource) ||
|
|
129
|
-
(typeof mediaSource === "string" && !mediaSource.startsWith("http"))
|
|
130
|
-
) {
|
|
131
|
-
formData[mediaType] = await this._prepareFile(mediaSource, mediaType)
|
|
132
|
-
return this.request(method, {}, formData)
|
|
133
|
-
}
|
|
120
|
+
const formData = { chat_id: chatId, caption, [mediaType]: await this._prepareFile(mediaSource, mediaType), ...rest }
|
|
134
121
|
|
|
135
|
-
|
|
136
|
-
return this.request(method, formData)
|
|
122
|
+
return this.request(method, {}, formData)
|
|
137
123
|
}
|
|
138
124
|
|
|
139
125
|
async sendPhoto(chatId, photo, options = {}) {
|
|
140
|
-
|
|
141
|
-
if (photo.startsWith("http")) {
|
|
142
|
-
return this.request("sendPhoto", {
|
|
143
|
-
chat_id: chatId,
|
|
144
|
-
photo,
|
|
145
|
-
...options,
|
|
146
|
-
})
|
|
147
|
-
} else {
|
|
148
|
-
const fileData = await this._readFileSync(photo)
|
|
149
|
-
const formData = {
|
|
150
|
-
chat_id: chatId,
|
|
151
|
-
photo: {
|
|
152
|
-
stream: true,
|
|
153
|
-
filename: basename(photo),
|
|
154
|
-
contentType: "image/jpeg",
|
|
155
|
-
data: fileData,
|
|
156
|
-
},
|
|
157
|
-
...this._flattenOptions(options),
|
|
158
|
-
}
|
|
159
|
-
return this.request("sendPhoto", {}, formData)
|
|
160
|
-
}
|
|
161
|
-
} else {
|
|
162
|
-
return this.request("sendPhoto", {
|
|
163
|
-
chat_id: chatId,
|
|
164
|
-
photo,
|
|
165
|
-
...options,
|
|
166
|
-
})
|
|
167
|
-
}
|
|
126
|
+
return this._sendFile("sendPhoto", chatId, photo, "photo", options)
|
|
168
127
|
}
|
|
169
128
|
|
|
170
129
|
async sendAudio(chatId, audio, options = {}) {
|
|
@@ -636,8 +595,25 @@ class TelegramBot extends EventEmitter {
|
|
|
636
595
|
|
|
637
596
|
_createContext(update) {
|
|
638
597
|
const message = update.message || update.edited_message || update.channel_post || update.callback_query?.message
|
|
639
|
-
|
|
640
|
-
|
|
598
|
+
|
|
599
|
+
// Fallback logic for chat extraction from various update types
|
|
600
|
+
let chat =
|
|
601
|
+
message?.chat || update.my_chat_member?.chat || update.chat_member?.chat || update.chat_join_request?.chat
|
|
602
|
+
|
|
603
|
+
// Explicit extraction for callback_query which might not have a message (inline buttons)
|
|
604
|
+
if (!chat && update.callback_query) {
|
|
605
|
+
chat = update.callback_query.message?.chat
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const from =
|
|
609
|
+
message?.from ||
|
|
610
|
+
update.callback_query?.from ||
|
|
611
|
+
update.inline_query?.from ||
|
|
612
|
+
update.chosen_inline_result?.from ||
|
|
613
|
+
update.shipping_query?.from ||
|
|
614
|
+
update.pre_checkout_query?.from ||
|
|
615
|
+
update.poll_answer?.user ||
|
|
616
|
+
update.my_chat_member?.from
|
|
641
617
|
|
|
642
618
|
const ctx = {
|
|
643
619
|
update,
|
|
@@ -656,17 +632,20 @@ class TelegramBot extends EventEmitter {
|
|
|
656
632
|
|
|
657
633
|
// Baileys-style simplified response
|
|
658
634
|
ctx.send = (content, opts) => {
|
|
659
|
-
|
|
635
|
+
const chatId = ctx.chat?.id || update.callback_query?.from?.id || update.inline_query?.from?.id
|
|
636
|
+
if (!chatId) {
|
|
637
|
+
console.error("[v0] Context update without chat_id:", JSON.stringify(update))
|
|
660
638
|
throw new Error("[Teh] Cannot send message: chat_id is not available in this context")
|
|
661
639
|
}
|
|
662
|
-
return this.sendMessage(
|
|
640
|
+
return this.sendMessage(chatId, content, opts)
|
|
663
641
|
}
|
|
664
642
|
|
|
665
643
|
ctx.reply = (text, opts) => {
|
|
666
|
-
|
|
644
|
+
const chatId = ctx.chat?.id || update.callback_query?.from?.id
|
|
645
|
+
if (!chatId) {
|
|
667
646
|
throw new Error("[Teh] Cannot reply: chat_id is not available in this context")
|
|
668
647
|
}
|
|
669
|
-
return this.sendMessage(
|
|
648
|
+
return this.sendMessage(chatId, text, {
|
|
670
649
|
reply_to_message_id: ctx.message?.message_id,
|
|
671
650
|
...opts,
|
|
672
651
|
})
|
|
@@ -758,7 +737,28 @@ class TelegramBot extends EventEmitter {
|
|
|
758
737
|
async _prepareFile(source, type) {
|
|
759
738
|
if (source instanceof Stream) return { data: source, contentType: this._getMime(type) }
|
|
760
739
|
if (Buffer.isBuffer(source)) return { data: source, contentType: this._getMime(type) }
|
|
740
|
+
|
|
761
741
|
if (typeof source === "string") {
|
|
742
|
+
if (source.startsWith("http")) {
|
|
743
|
+
// Fetch remote URL and return as stream
|
|
744
|
+
return new Promise((resolve, reject) => {
|
|
745
|
+
const client = source.startsWith("https") ? https : http
|
|
746
|
+
client
|
|
747
|
+
.get(source, (res) => {
|
|
748
|
+
if (res.statusCode !== 200) {
|
|
749
|
+
return reject(new Error(`Failed to fetch remote file: ${res.statusCode}`))
|
|
750
|
+
}
|
|
751
|
+
resolve({
|
|
752
|
+
data: res,
|
|
753
|
+
filename: basename(new URL(source).pathname) || `file_${Date.now()}`,
|
|
754
|
+
contentType: res.headers["content-type"] || this._getMime(type),
|
|
755
|
+
})
|
|
756
|
+
})
|
|
757
|
+
.on("error", reject)
|
|
758
|
+
})
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Local file
|
|
762
762
|
return {
|
|
763
763
|
data: createReadStream(source),
|
|
764
764
|
filename: basename(source),
|
|
@@ -780,6 +780,18 @@ class TelegramBot extends EventEmitter {
|
|
|
780
780
|
return mimes[ext] || "application/octet-stream"
|
|
781
781
|
}
|
|
782
782
|
|
|
783
|
+
_flattenOptions(options) {
|
|
784
|
+
const flat = {}
|
|
785
|
+
for (const [key, value] of Object.entries(options)) {
|
|
786
|
+
if (typeof value === "object" && value !== null) {
|
|
787
|
+
flat[key] = JSON.stringify(value)
|
|
788
|
+
} else {
|
|
789
|
+
flat[key] = value
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return flat
|
|
793
|
+
}
|
|
794
|
+
|
|
783
795
|
_formatError(resp) {
|
|
784
796
|
const err = new Error(resp.description || "Unknown Telegram Error")
|
|
785
797
|
err.code = resp.error_code
|
|
@@ -803,6 +815,24 @@ class TelegramBot extends EventEmitter {
|
|
|
803
815
|
async getWebhookInfo() {
|
|
804
816
|
return this.request("getWebhookInfo")
|
|
805
817
|
}
|
|
818
|
+
|
|
819
|
+
static InlineKeyboard() {
|
|
820
|
+
return new InlineKeyboardBuilder()
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
static ReplyKeyboard() {
|
|
824
|
+
return new ReplyKeyboardBuilder()
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
static RemoveKeyboard(selective = false) {
|
|
828
|
+
return { remove_keyboard: true, selective }
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
static ForceReply(selective = false, placeholder = "") {
|
|
832
|
+
const obj = { force_reply: true, selective }
|
|
833
|
+
if (placeholder) obj.input_field_placeholder = placeholder
|
|
834
|
+
return obj
|
|
835
|
+
}
|
|
806
836
|
}
|
|
807
837
|
|
|
808
838
|
class InlineKeyboardBuilder {
|