grammy-message-queue 0.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/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # grammy-message-queue
2
+
3
+ [![npm version](https://img.shields.io/npm/v/grammy-message-queue?style=flat-square)](https://www.npmjs.com/package/grammy-message-queue)
4
+ [![npm downloads](https://img.shields.io/npm/dm/grammy-message-queue?style=flat-square)](https://www.npmjs.com/package/grammy-message-queue)
5
+ [![GitHub](https://img.shields.io/badge/GitHub-Repository-black?style=flat-square&logo=github)](https://github.com/snipe-dev/grammy-message-queue)
6
+
7
+ Reliable sequential message delivery queue for Telegram bots built with
8
+ **grammy**.
9
+
10
+ - Preserves message order
11
+ - Automatic Telegram 429 rate limit handling
12
+ - Supports `retry_after`
13
+ - Separate send & edit queues
14
+ - ESM + CommonJS compatible
15
+ - Node.js \>= 16
16
+
17
+ ------------------------------------------------------------------------
18
+
19
+ ## Installation
20
+
21
+ ``` bash
22
+ npm install grammy-message-queue
23
+ npm install grammy
24
+ ```
25
+
26
+ ------------------------------------------------------------------------
27
+
28
+ ## Usage (ESM)
29
+
30
+ ``` ts
31
+ import { Bot } from "grammy";
32
+ import { TelegramQueue } from "grammy-message-queue";
33
+
34
+ const bot = new Bot(process.env.BOT_TOKEN!);
35
+ const queue = new TelegramQueue(bot.api);
36
+
37
+ await queue.sendMessage(123456789, "<b>Hello from queue</b>");
38
+ ```
39
+
40
+ ------------------------------------------------------------------------
41
+
42
+ ## Usage (CommonJS)
43
+
44
+ ``` js
45
+ const { Bot } = require("grammy");
46
+ const { TelegramQueue } = require("grammy-message-queue");
47
+
48
+ const bot = new Bot(process.env.BOT_TOKEN);
49
+ const queue = new TelegramQueue(bot.api);
50
+
51
+ queue.sendMessage(123456789, "<b>Hello from queue</b>");
52
+ ```
53
+
54
+ ------------------------------------------------------------------------
55
+
56
+ ## API
57
+
58
+ ### new TelegramQueue(api: Api)
59
+
60
+ Creates a new transport-safe queue instance.
61
+
62
+ ### sendMessage(chatId, text, buttons?)
63
+
64
+ Sequential queued send.
65
+
66
+ Returns:
67
+
68
+ ``` ts
69
+ Promise<number>
70
+ ```
71
+
72
+ ### editMessage(chatId, msgId, text, buttons?)
73
+
74
+ Queued edit.
75
+
76
+ Returns:
77
+
78
+ ``` ts
79
+ Promise<boolean>
80
+ ```
81
+
82
+ ### sendSingleMessage(...)
83
+
84
+ Immediate send without queue.
85
+
86
+ ### sendSinglePhoto(...)
87
+
88
+ Immediate photo send.
89
+
90
+ ### editSingleMessage(...)
91
+
92
+ Immediate edit.
93
+
94
+ ------------------------------------------------------------------------
95
+
96
+ ## Build
97
+
98
+ ``` bash
99
+ npm run build
100
+ ```
101
+
102
+ ------------------------------------------------------------------------
103
+
104
+ ## Publish
105
+
106
+ ``` bash
107
+ npm pack
108
+ npm publish --access public
109
+ ```
110
+
111
+ ------------------------------------------------------------------------
112
+
113
+ ## Repository
114
+
115
+ https://github.com/snipe-dev/grammy-message-queue
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TelegramQueue = exports.sleep = void 0;
4
+ exports.applyDefaults = applyDefaults;
5
+ const grammy_1 = require("grammy");
6
+ /**
7
+ * Utility function to delay execution.
8
+ */
9
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
10
+ exports.sleep = sleep;
11
+ /**
12
+ * Applies default Telegram API options.
13
+ */
14
+ function applyDefaults(method, payload) {
15
+ if (!payload || typeof payload !== "object") {
16
+ return;
17
+ }
18
+ if (!payload.parse_mode) {
19
+ payload.parse_mode = "HTML";
20
+ }
21
+ if ((method === "sendMessage" || method === "editMessageText") &&
22
+ !payload.link_preview_options) {
23
+ payload.link_preview_options = { is_disabled: true };
24
+ }
25
+ }
26
+ /**
27
+ * TelegramQueue
28
+ *
29
+ * Sequential and rate-limit-safe outgoing message queue
30
+ * for Telegram bots built with grammy.
31
+ */
32
+ class TelegramQueue {
33
+ constructor(api) {
34
+ this.botId = "unnamedbot";
35
+ this.sendQueue = [];
36
+ this.isProcessingSendQueue = false;
37
+ this.pendingSendMessages = new Map();
38
+ this.editQueue = [];
39
+ this.isProcessingEditQueue = false;
40
+ this.pendingEditMessages = new Map();
41
+ this.api = api;
42
+ this.setupApiMiddleware();
43
+ this.api
44
+ .getMe()
45
+ .then((me) => {
46
+ this.botId = me.username?.toLowerCase() || "unnamedbot";
47
+ })
48
+ .catch(() => {
49
+ // Silent failure
50
+ });
51
+ }
52
+ setupApiMiddleware() {
53
+ this.api.config.use((prev, method, payload) => {
54
+ applyDefaults(method, payload);
55
+ return prev(method, payload);
56
+ });
57
+ }
58
+ async sendMessage(chatId, text, buttons) {
59
+ return this.enqueueSendMessage(chatId, text, buttons);
60
+ }
61
+ async enqueueSendMessage(chatId, text, buttons) {
62
+ if (text.length > 4096) {
63
+ throw new Error("Message too long");
64
+ }
65
+ const messageId = `${chatId}_${Date.now()}_${Math.random()}`;
66
+ let resolve;
67
+ let reject;
68
+ const promise = new Promise((res, rej) => {
69
+ resolve = res;
70
+ reject = rej;
71
+ });
72
+ this.sendQueue.push({
73
+ chatId,
74
+ text,
75
+ buttons,
76
+ messageId,
77
+ resolve,
78
+ reject,
79
+ });
80
+ this.pendingSendMessages.set(messageId, promise);
81
+ if (!this.isProcessingSendQueue) {
82
+ this.processSendQueue().catch(() => {
83
+ // Critical failure in queue processor
84
+ console.error("TelegramQueue send processor crashed");
85
+ });
86
+ }
87
+ return promise;
88
+ }
89
+ async processSendQueue() {
90
+ if (this.isProcessingSendQueue)
91
+ return;
92
+ this.isProcessingSendQueue = true;
93
+ while (this.sendQueue.length > 0) {
94
+ const item = this.sendQueue[0];
95
+ try {
96
+ const msg = await this.api.sendMessage(item.chatId, item.text, item.buttons ? { reply_markup: item.buttons } : {});
97
+ this.sendQueue.shift();
98
+ this.pendingSendMessages.delete(item.messageId);
99
+ item.resolve(msg.message_id);
100
+ await (0, exports.sleep)(200);
101
+ }
102
+ catch (err) {
103
+ const action = this.handleError(err, item.chatId);
104
+ if (action.retrySending) {
105
+ await (0, exports.sleep)(action.retryAfter * 1000);
106
+ continue;
107
+ }
108
+ if (action.removeMessage) {
109
+ this.sendQueue.shift();
110
+ this.pendingSendMessages.delete(item.messageId);
111
+ item.reject(err);
112
+ }
113
+ }
114
+ }
115
+ this.isProcessingSendQueue = false;
116
+ }
117
+ async editMessage(chatId, msgId, text, buttons) {
118
+ return this.enqueueEditMessage(chatId, msgId, text, buttons);
119
+ }
120
+ async enqueueEditMessage(chatId, msgId, text, buttons) {
121
+ if (text.length > 4096) {
122
+ throw new Error("Message too long");
123
+ }
124
+ const editId = `${chatId}_${msgId}_${Date.now()}`;
125
+ let resolve;
126
+ let reject;
127
+ const promise = new Promise((res, rej) => {
128
+ resolve = res;
129
+ reject = rej;
130
+ });
131
+ this.editQueue.push({
132
+ chatId,
133
+ msgId,
134
+ text,
135
+ buttons,
136
+ editId,
137
+ resolve,
138
+ reject,
139
+ });
140
+ this.pendingEditMessages.set(editId, promise);
141
+ if (!this.isProcessingEditQueue) {
142
+ this.processEditQueue().catch(() => {
143
+ console.error("TelegramQueue edit processor crashed");
144
+ });
145
+ }
146
+ return promise;
147
+ }
148
+ async processEditQueue() {
149
+ if (this.isProcessingEditQueue)
150
+ return;
151
+ this.isProcessingEditQueue = true;
152
+ while (this.editQueue.length > 0) {
153
+ const item = this.editQueue[0];
154
+ try {
155
+ await this.api.editMessageText(item.chatId, item.msgId, item.text, item.buttons ? { reply_markup: item.buttons } : {});
156
+ this.editQueue.shift();
157
+ this.pendingEditMessages.delete(item.editId);
158
+ item.resolve(true);
159
+ await (0, exports.sleep)(200);
160
+ }
161
+ catch (err) {
162
+ const action = this.handleError(err, item.chatId);
163
+ if (action.retrySending) {
164
+ await (0, exports.sleep)(action.retryAfter * 1000);
165
+ continue;
166
+ }
167
+ if (action.removeMessage) {
168
+ this.editQueue.shift();
169
+ this.pendingEditMessages.delete(item.editId);
170
+ item.reject(err);
171
+ }
172
+ }
173
+ }
174
+ this.isProcessingEditQueue = false;
175
+ }
176
+ async sendSingleMessage(chatId, text, buttons) {
177
+ if (text.length > 4096)
178
+ return null;
179
+ try {
180
+ const msg = await this.api.sendMessage(chatId, text, buttons ? { reply_markup: buttons } : {});
181
+ return msg.message_id;
182
+ }
183
+ catch (err) {
184
+ this.handleError(err, chatId);
185
+ return null;
186
+ }
187
+ }
188
+ async sendSinglePhoto(chatId, text, photo, buttons) {
189
+ if (text.length > 2048)
190
+ return null;
191
+ try {
192
+ const file = new grammy_1.InputFile(photo, "photo.png");
193
+ const msg = await this.api.sendPhoto(chatId, file, {
194
+ caption: text,
195
+ ...(buttons ? { reply_markup: buttons } : {}),
196
+ });
197
+ return msg.message_id;
198
+ }
199
+ catch (err) {
200
+ this.handleError(err, chatId);
201
+ return null;
202
+ }
203
+ }
204
+ async editSingleMessage(chatId, msgId, text, buttons) {
205
+ if (text.length > 4096)
206
+ return null;
207
+ try {
208
+ await this.api.editMessageText(chatId, msgId, text, buttons ? { reply_markup: buttons } : {});
209
+ return msgId;
210
+ }
211
+ catch (err) {
212
+ this.handleError(err, chatId);
213
+ return null;
214
+ }
215
+ }
216
+ handleError(error, chatId) {
217
+ const result = {
218
+ removeMessage: true,
219
+ removeUser: false,
220
+ retrySending: false,
221
+ retryAfter: 1,
222
+ };
223
+ if (!(error instanceof grammy_1.GrammyError)) {
224
+ console.error(`TelegramQueue unknown error for chat ${chatId}:`, error?.message || error);
225
+ return result;
226
+ }
227
+ const errorCode = error.error_code;
228
+ const description = error.description || "";
229
+ if (errorCode === 429) {
230
+ result.retryAfter = error.parameters?.retry_after || 1;
231
+ result.removeMessage = false;
232
+ result.retrySending = true;
233
+ return result;
234
+ }
235
+ if (description.includes("bot was blocked by the user") ||
236
+ description.includes("chat not found") ||
237
+ description.includes("bot was kicked") ||
238
+ description.includes("user is deactivated")) {
239
+ result.removeUser = true;
240
+ return result;
241
+ }
242
+ if (description.includes("message text is invalid") ||
243
+ description.includes("message to edit not found")) {
244
+ return result;
245
+ }
246
+ console.error(`TelegramQueue unhandled error for chat ${chatId}: ${errorCode} - ${description}`);
247
+ return result;
248
+ }
249
+ parseReceiver(msg) {
250
+ const chat = msg.chat;
251
+ const name = chat.username
252
+ ? "@" + chat.username
253
+ : chat.title || `Chat${chat.id}`;
254
+ return {
255
+ chatId: chat.id,
256
+ botId: this.botId,
257
+ type: chat.type,
258
+ fullname: `${this.botId}|${name}`,
259
+ };
260
+ }
261
+ }
262
+ exports.TelegramQueue = TelegramQueue;
@@ -0,0 +1,256 @@
1
+ import { GrammyError, InputFile } from "grammy";
2
+ /**
3
+ * Utility function to delay execution.
4
+ */
5
+ export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
6
+ /**
7
+ * Applies default Telegram API options.
8
+ */
9
+ export function applyDefaults(method, payload) {
10
+ if (!payload || typeof payload !== "object") {
11
+ return;
12
+ }
13
+ if (!payload.parse_mode) {
14
+ payload.parse_mode = "HTML";
15
+ }
16
+ if ((method === "sendMessage" || method === "editMessageText") &&
17
+ !payload.link_preview_options) {
18
+ payload.link_preview_options = { is_disabled: true };
19
+ }
20
+ }
21
+ /**
22
+ * TelegramQueue
23
+ *
24
+ * Sequential and rate-limit-safe outgoing message queue
25
+ * for Telegram bots built with grammy.
26
+ */
27
+ export class TelegramQueue {
28
+ constructor(api) {
29
+ this.botId = "unnamedbot";
30
+ this.sendQueue = [];
31
+ this.isProcessingSendQueue = false;
32
+ this.pendingSendMessages = new Map();
33
+ this.editQueue = [];
34
+ this.isProcessingEditQueue = false;
35
+ this.pendingEditMessages = new Map();
36
+ this.api = api;
37
+ this.setupApiMiddleware();
38
+ this.api
39
+ .getMe()
40
+ .then((me) => {
41
+ this.botId = me.username?.toLowerCase() || "unnamedbot";
42
+ })
43
+ .catch(() => {
44
+ // Silent failure
45
+ });
46
+ }
47
+ setupApiMiddleware() {
48
+ this.api.config.use((prev, method, payload) => {
49
+ applyDefaults(method, payload);
50
+ return prev(method, payload);
51
+ });
52
+ }
53
+ async sendMessage(chatId, text, buttons) {
54
+ return this.enqueueSendMessage(chatId, text, buttons);
55
+ }
56
+ async enqueueSendMessage(chatId, text, buttons) {
57
+ if (text.length > 4096) {
58
+ throw new Error("Message too long");
59
+ }
60
+ const messageId = `${chatId}_${Date.now()}_${Math.random()}`;
61
+ let resolve;
62
+ let reject;
63
+ const promise = new Promise((res, rej) => {
64
+ resolve = res;
65
+ reject = rej;
66
+ });
67
+ this.sendQueue.push({
68
+ chatId,
69
+ text,
70
+ buttons,
71
+ messageId,
72
+ resolve,
73
+ reject,
74
+ });
75
+ this.pendingSendMessages.set(messageId, promise);
76
+ if (!this.isProcessingSendQueue) {
77
+ this.processSendQueue().catch(() => {
78
+ // Critical failure in queue processor
79
+ console.error("TelegramQueue send processor crashed");
80
+ });
81
+ }
82
+ return promise;
83
+ }
84
+ async processSendQueue() {
85
+ if (this.isProcessingSendQueue)
86
+ return;
87
+ this.isProcessingSendQueue = true;
88
+ while (this.sendQueue.length > 0) {
89
+ const item = this.sendQueue[0];
90
+ try {
91
+ const msg = await this.api.sendMessage(item.chatId, item.text, item.buttons ? { reply_markup: item.buttons } : {});
92
+ this.sendQueue.shift();
93
+ this.pendingSendMessages.delete(item.messageId);
94
+ item.resolve(msg.message_id);
95
+ await sleep(200);
96
+ }
97
+ catch (err) {
98
+ const action = this.handleError(err, item.chatId);
99
+ if (action.retrySending) {
100
+ await sleep(action.retryAfter * 1000);
101
+ continue;
102
+ }
103
+ if (action.removeMessage) {
104
+ this.sendQueue.shift();
105
+ this.pendingSendMessages.delete(item.messageId);
106
+ item.reject(err);
107
+ }
108
+ }
109
+ }
110
+ this.isProcessingSendQueue = false;
111
+ }
112
+ async editMessage(chatId, msgId, text, buttons) {
113
+ return this.enqueueEditMessage(chatId, msgId, text, buttons);
114
+ }
115
+ async enqueueEditMessage(chatId, msgId, text, buttons) {
116
+ if (text.length > 4096) {
117
+ throw new Error("Message too long");
118
+ }
119
+ const editId = `${chatId}_${msgId}_${Date.now()}`;
120
+ let resolve;
121
+ let reject;
122
+ const promise = new Promise((res, rej) => {
123
+ resolve = res;
124
+ reject = rej;
125
+ });
126
+ this.editQueue.push({
127
+ chatId,
128
+ msgId,
129
+ text,
130
+ buttons,
131
+ editId,
132
+ resolve,
133
+ reject,
134
+ });
135
+ this.pendingEditMessages.set(editId, promise);
136
+ if (!this.isProcessingEditQueue) {
137
+ this.processEditQueue().catch(() => {
138
+ console.error("TelegramQueue edit processor crashed");
139
+ });
140
+ }
141
+ return promise;
142
+ }
143
+ async processEditQueue() {
144
+ if (this.isProcessingEditQueue)
145
+ return;
146
+ this.isProcessingEditQueue = true;
147
+ while (this.editQueue.length > 0) {
148
+ const item = this.editQueue[0];
149
+ try {
150
+ await this.api.editMessageText(item.chatId, item.msgId, item.text, item.buttons ? { reply_markup: item.buttons } : {});
151
+ this.editQueue.shift();
152
+ this.pendingEditMessages.delete(item.editId);
153
+ item.resolve(true);
154
+ await sleep(200);
155
+ }
156
+ catch (err) {
157
+ const action = this.handleError(err, item.chatId);
158
+ if (action.retrySending) {
159
+ await sleep(action.retryAfter * 1000);
160
+ continue;
161
+ }
162
+ if (action.removeMessage) {
163
+ this.editQueue.shift();
164
+ this.pendingEditMessages.delete(item.editId);
165
+ item.reject(err);
166
+ }
167
+ }
168
+ }
169
+ this.isProcessingEditQueue = false;
170
+ }
171
+ async sendSingleMessage(chatId, text, buttons) {
172
+ if (text.length > 4096)
173
+ return null;
174
+ try {
175
+ const msg = await this.api.sendMessage(chatId, text, buttons ? { reply_markup: buttons } : {});
176
+ return msg.message_id;
177
+ }
178
+ catch (err) {
179
+ this.handleError(err, chatId);
180
+ return null;
181
+ }
182
+ }
183
+ async sendSinglePhoto(chatId, text, photo, buttons) {
184
+ if (text.length > 2048)
185
+ return null;
186
+ try {
187
+ const file = new InputFile(photo, "photo.png");
188
+ const msg = await this.api.sendPhoto(chatId, file, {
189
+ caption: text,
190
+ ...(buttons ? { reply_markup: buttons } : {}),
191
+ });
192
+ return msg.message_id;
193
+ }
194
+ catch (err) {
195
+ this.handleError(err, chatId);
196
+ return null;
197
+ }
198
+ }
199
+ async editSingleMessage(chatId, msgId, text, buttons) {
200
+ if (text.length > 4096)
201
+ return null;
202
+ try {
203
+ await this.api.editMessageText(chatId, msgId, text, buttons ? { reply_markup: buttons } : {});
204
+ return msgId;
205
+ }
206
+ catch (err) {
207
+ this.handleError(err, chatId);
208
+ return null;
209
+ }
210
+ }
211
+ handleError(error, chatId) {
212
+ const result = {
213
+ removeMessage: true,
214
+ removeUser: false,
215
+ retrySending: false,
216
+ retryAfter: 1,
217
+ };
218
+ if (!(error instanceof GrammyError)) {
219
+ console.error(`TelegramQueue unknown error for chat ${chatId}:`, error?.message || error);
220
+ return result;
221
+ }
222
+ const errorCode = error.error_code;
223
+ const description = error.description || "";
224
+ if (errorCode === 429) {
225
+ result.retryAfter = error.parameters?.retry_after || 1;
226
+ result.removeMessage = false;
227
+ result.retrySending = true;
228
+ return result;
229
+ }
230
+ if (description.includes("bot was blocked by the user") ||
231
+ description.includes("chat not found") ||
232
+ description.includes("bot was kicked") ||
233
+ description.includes("user is deactivated")) {
234
+ result.removeUser = true;
235
+ return result;
236
+ }
237
+ if (description.includes("message text is invalid") ||
238
+ description.includes("message to edit not found")) {
239
+ return result;
240
+ }
241
+ console.error(`TelegramQueue unhandled error for chat ${chatId}: ${errorCode} - ${description}`);
242
+ return result;
243
+ }
244
+ parseReceiver(msg) {
245
+ const chat = msg.chat;
246
+ const name = chat.username
247
+ ? "@" + chat.username
248
+ : chat.title || `Chat${chat.id}`;
249
+ return {
250
+ chatId: chat.id,
251
+ botId: this.botId,
252
+ type: chat.type,
253
+ fullname: `${this.botId}|${name}`,
254
+ };
255
+ }
256
+ }
@@ -0,0 +1,68 @@
1
+ import { Api } from "grammy";
2
+ import type { InlineKeyboard } from "grammy";
3
+ import type { Message } from "grammy/types";
4
+ /**
5
+ * Internal queue item representing a pending send operation.
6
+ */
7
+ export type SendQueueItem = {
8
+ chatId: number | string;
9
+ text: string;
10
+ buttons: InlineKeyboard | undefined;
11
+ messageId: string;
12
+ resolve: (value: number) => void;
13
+ reject: (reason?: any) => void;
14
+ };
15
+ /**
16
+ * Internal queue item representing a pending edit operation.
17
+ */
18
+ export type EditQueueItem = {
19
+ chatId: number | string;
20
+ msgId: number;
21
+ text: string;
22
+ buttons: InlineKeyboard | undefined;
23
+ editId: string;
24
+ resolve: (value: boolean) => void;
25
+ reject: (reason?: any) => void;
26
+ };
27
+ /**
28
+ * Utility function to delay execution.
29
+ */
30
+ export declare const sleep: (ms: number) => Promise<void>;
31
+ /**
32
+ * Applies default Telegram API options.
33
+ */
34
+ export declare function applyDefaults(method: string, payload: any): void;
35
+ /**
36
+ * TelegramQueue
37
+ *
38
+ * Sequential and rate-limit-safe outgoing message queue
39
+ * for Telegram bots built with grammy.
40
+ */
41
+ export declare class TelegramQueue {
42
+ private api;
43
+ private botId;
44
+ private sendQueue;
45
+ private isProcessingSendQueue;
46
+ private pendingSendMessages;
47
+ private editQueue;
48
+ private isProcessingEditQueue;
49
+ private pendingEditMessages;
50
+ constructor(api: Api);
51
+ private setupApiMiddleware;
52
+ sendMessage(chatId: number | string, text: string, buttons?: InlineKeyboard): Promise<number>;
53
+ private enqueueSendMessage;
54
+ private processSendQueue;
55
+ editMessage(chatId: number | string, msgId: number, text: string, buttons?: InlineKeyboard): Promise<boolean>;
56
+ private enqueueEditMessage;
57
+ private processEditQueue;
58
+ sendSingleMessage(chatId: number | string, text: string, buttons?: InlineKeyboard): Promise<number | null>;
59
+ sendSinglePhoto(chatId: number | string, text: string, photo: Buffer, buttons?: InlineKeyboard): Promise<number | null>;
60
+ editSingleMessage(chatId: number | string, msgId: number, text: string, buttons?: InlineKeyboard): Promise<number | null>;
61
+ private handleError;
62
+ parseReceiver(msg: Message): {
63
+ chatId: number;
64
+ botId: string;
65
+ type: "private" | "group" | "supergroup" | "channel";
66
+ fullname: string;
67
+ };
68
+ }
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "grammy-message-queue",
3
+ "version": "0.1.0",
4
+ "description": "Reliable sequential message queue for Telegram bots built with grammy. Handles rate limits (429), retry_after and preserves message order.",
5
+ "keywords": [
6
+ "telegram",
7
+ "telegram-bot",
8
+ "grammy",
9
+ "message-queue",
10
+ "rate-limit",
11
+ "bot",
12
+ "queue"
13
+ ],
14
+ "author": "snipe-dev",
15
+ "license": "MIT",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/snipe-dev/grammy-message-queue.git"
19
+ },
20
+ "homepage": "https://github.com/snipe-dev/grammy-message-queue#readme",
21
+ "bugs": {
22
+ "url": "https://github.com/snipe-dev/grammy-message-queue/issues"
23
+ },
24
+ "type": "module",
25
+ "main": "./dist/cjs/index.js",
26
+ "module": "./dist/esm/index.js",
27
+ "types": "./dist/types/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/types/index.d.ts",
31
+ "require": "./dist/cjs/index.js",
32
+ "import": "./dist/esm/index.js"
33
+ }
34
+ },
35
+ "files": [
36
+ "dist"
37
+ ],
38
+ "scripts": {
39
+ "build:esm": "tsc -p tsconfig.esm.json",
40
+ "build:cjs": "tsc -p tsconfig.cjs.json",
41
+ "build": "npm run build:esm && npm run build:cjs",
42
+ "prepublishOnly": "npm run build"
43
+ },
44
+ "engines": {
45
+ "node": ">=16"
46
+ },
47
+ "peerDependencies": {
48
+ "grammy": "^1.39.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^25.1.0",
52
+ "typescript": "^5.4.0"
53
+ }
54
+ }