maxbot-api-client-ts 1.0.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/LICENSE +21 -0
- package/README.md +158 -0
- package/dist/api.d.mts +723 -0
- package/dist/api.d.ts +723 -0
- package/dist/api.js +884 -0
- package/dist/api.mjs +860 -0
- package/package.json +39 -0
package/dist/api.js
ADDED
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
23
|
+
};
|
|
24
|
+
var __copyProps = (to, from, except, desc) => {
|
|
25
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
26
|
+
for (let key of __getOwnPropNames(from))
|
|
27
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
28
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
29
|
+
}
|
|
30
|
+
return to;
|
|
31
|
+
};
|
|
32
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
33
|
+
var __async = (__this, __arguments, generator) => {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
var fulfilled = (value) => {
|
|
36
|
+
try {
|
|
37
|
+
step(generator.next(value));
|
|
38
|
+
} catch (e) {
|
|
39
|
+
reject(e);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var rejected = (value) => {
|
|
43
|
+
try {
|
|
44
|
+
step(generator.throw(value));
|
|
45
|
+
} catch (e) {
|
|
46
|
+
reject(e);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
50
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// src/api/api.ts
|
|
55
|
+
var api_exports = {};
|
|
56
|
+
__export(api_exports, {
|
|
57
|
+
MaxBotAPI: () => MaxBotAPI
|
|
58
|
+
});
|
|
59
|
+
module.exports = __toCommonJS(api_exports);
|
|
60
|
+
|
|
61
|
+
// src/models/const.ts
|
|
62
|
+
var Defaultbase_url = "https://platform-api.max.ru";
|
|
63
|
+
var Paths = {
|
|
64
|
+
Me: "me",
|
|
65
|
+
Chats: "chats",
|
|
66
|
+
Answers: "answers",
|
|
67
|
+
Updates: "updates",
|
|
68
|
+
Uploads: "uploads",
|
|
69
|
+
Messages: "messages",
|
|
70
|
+
Subscriptions: "subscriptions",
|
|
71
|
+
Videos: "videos"
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// src/client/client.ts
|
|
75
|
+
var RateLimiter = class {
|
|
76
|
+
constructor(rps) {
|
|
77
|
+
this.queue = [];
|
|
78
|
+
this.timeoutId = null;
|
|
79
|
+
this.rps = rps;
|
|
80
|
+
this.tokens = rps;
|
|
81
|
+
this.lastRefill = Date.now();
|
|
82
|
+
}
|
|
83
|
+
wait() {
|
|
84
|
+
return __async(this, null, function* () {
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
this.queue.push(resolve);
|
|
87
|
+
this.processQueue();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
processQueue() {
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
const timePassed = now - this.lastRefill;
|
|
94
|
+
this.tokens += timePassed * (this.rps / 1e3);
|
|
95
|
+
if (this.tokens > this.rps) {
|
|
96
|
+
this.tokens = this.rps;
|
|
97
|
+
}
|
|
98
|
+
this.lastRefill = now;
|
|
99
|
+
while (this.queue.length > 0 && this.tokens >= 1) {
|
|
100
|
+
this.tokens -= 1;
|
|
101
|
+
const resolve = this.queue.shift();
|
|
102
|
+
if (resolve) resolve();
|
|
103
|
+
}
|
|
104
|
+
if (this.queue.length > 0 && !this.timeoutId) {
|
|
105
|
+
const timeToNextToken = Math.ceil(1 / this.rps * 1e3);
|
|
106
|
+
this.timeoutId = setTimeout(() => {
|
|
107
|
+
this.timeoutId = null;
|
|
108
|
+
this.processQueue();
|
|
109
|
+
}, timeToNextToken);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
setLimit(rps) {
|
|
113
|
+
this.rps = rps;
|
|
114
|
+
this.tokens = rps;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var APIClient = class {
|
|
118
|
+
constructor(cfg) {
|
|
119
|
+
if (!cfg.token) {
|
|
120
|
+
throw new Error("Token is not set");
|
|
121
|
+
}
|
|
122
|
+
this.base_url = cfg.base_url || Defaultbase_url;
|
|
123
|
+
this.token = cfg.token;
|
|
124
|
+
this.timeout = cfg.timeout || 35e3;
|
|
125
|
+
const rps = cfg.globalRPS && cfg.globalRPS > 0 ? cfg.globalRPS : 25;
|
|
126
|
+
this.rateLimiter = new RateLimiter(rps);
|
|
127
|
+
}
|
|
128
|
+
request(_0, _1) {
|
|
129
|
+
return __async(this, arguments, function* (method, path, opts = {}) {
|
|
130
|
+
let urlObj;
|
|
131
|
+
if (path.startsWith("http://") || path.startsWith("https://")) {
|
|
132
|
+
urlObj = new URL(path);
|
|
133
|
+
} else {
|
|
134
|
+
urlObj = new URL(path, this.base_url);
|
|
135
|
+
}
|
|
136
|
+
if (opts.query) {
|
|
137
|
+
Object.entries(opts.query).forEach(([key, value]) => {
|
|
138
|
+
if (value !== void 0 && value !== null) {
|
|
139
|
+
if (Array.isArray(value)) {
|
|
140
|
+
value.forEach((v) => urlObj.searchParams.append(key, String(v)));
|
|
141
|
+
} else {
|
|
142
|
+
urlObj.searchParams.set(key, String(value));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
const headers = __spreadValues({
|
|
148
|
+
"Authorization": this.token
|
|
149
|
+
}, opts.headers);
|
|
150
|
+
let body = opts.body;
|
|
151
|
+
if (opts.payload && !body) {
|
|
152
|
+
body = JSON.stringify(opts.payload);
|
|
153
|
+
headers["Content-Type"] = "application/json";
|
|
154
|
+
} else if (!headers["Content-Type"] && !opts.body) {
|
|
155
|
+
headers["Content-Type"] = "application/json";
|
|
156
|
+
}
|
|
157
|
+
const controller = new AbortController();
|
|
158
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
159
|
+
try {
|
|
160
|
+
yield this.rateLimiter.wait();
|
|
161
|
+
const response = yield fetch(urlObj.toString(), {
|
|
162
|
+
method,
|
|
163
|
+
headers,
|
|
164
|
+
body,
|
|
165
|
+
signal: controller.signal
|
|
166
|
+
});
|
|
167
|
+
const text = yield response.text();
|
|
168
|
+
if (!response.ok) {
|
|
169
|
+
throw new Error(`[${method} ${urlObj.pathname}] HTTP ${response.status}: ${text}`);
|
|
170
|
+
}
|
|
171
|
+
if (!text) {
|
|
172
|
+
return {};
|
|
173
|
+
}
|
|
174
|
+
return JSON.parse(text);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
throw error;
|
|
177
|
+
} finally {
|
|
178
|
+
clearTimeout(timeoutId);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
setGlobalRateLimit(rps) {
|
|
183
|
+
this.rateLimiter.setLimit(rps);
|
|
184
|
+
}
|
|
185
|
+
getTimeout() {
|
|
186
|
+
return this.timeout;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// src/api/bots.ts
|
|
191
|
+
var BotsService = class {
|
|
192
|
+
constructor(client) {
|
|
193
|
+
this.client = client;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* GetBot returns information about the current bot (ID, name, description).
|
|
197
|
+
* @returns Promise<BotInfo>
|
|
198
|
+
* @example
|
|
199
|
+
* const response = await bot.bots.getBot();
|
|
200
|
+
* console.log("Connected as:", info.first_name);
|
|
201
|
+
*/
|
|
202
|
+
getBot() {
|
|
203
|
+
return __async(this, null, function* () {
|
|
204
|
+
return this.client.request("GET", Paths.Me);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* PatchBot updates bot information.
|
|
209
|
+
* Fill in only the fields you want to change.
|
|
210
|
+
* @param req - The bot data to update.
|
|
211
|
+
* @returns Promise<BotInfo>
|
|
212
|
+
* @example
|
|
213
|
+
* const response = await bot.bots.patchBot({
|
|
214
|
+
* name: "New Name",
|
|
215
|
+
* description: "New description"
|
|
216
|
+
* });
|
|
217
|
+
*/
|
|
218
|
+
patchBot(req) {
|
|
219
|
+
return __async(this, null, function* () {
|
|
220
|
+
return this.client.request("PATCH", Paths.Me, { payload: req });
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// src/api/chats.ts
|
|
226
|
+
var ChatsService = class {
|
|
227
|
+
constructor(client) {
|
|
228
|
+
this.client = client;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* GetChats returns a list of group chats in which the bot participated.
|
|
232
|
+
* @param req - Filter parameters for chats.
|
|
233
|
+
* @example
|
|
234
|
+
* const response = await bot.chats.getChats({ limit: 10 });
|
|
235
|
+
*/
|
|
236
|
+
getChats(req) {
|
|
237
|
+
return __async(this, null, function* () {
|
|
238
|
+
return this.client.request("GET", Paths.Chats, {
|
|
239
|
+
query: req
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* GetChat returns information about a group chat by its ID.
|
|
245
|
+
* @param req - Object containing the chat_id.
|
|
246
|
+
* @example
|
|
247
|
+
* const response = await bot.chats.getChat({ chat_id: 123456789 });
|
|
248
|
+
*/
|
|
249
|
+
getChat(req) {
|
|
250
|
+
return __async(this, null, function* () {
|
|
251
|
+
return this.client.request("GET", `${Paths.Chats}/${req.chat_id}`);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* EditChat allows you to edit information about a group chat.
|
|
256
|
+
* @param req - Chat edit parameters.
|
|
257
|
+
* @example
|
|
258
|
+
* await bot.chats.editChat({ chat_id: 123456789, title: "New Title" });
|
|
259
|
+
*/
|
|
260
|
+
editChat(req) {
|
|
261
|
+
return __async(this, null, function* () {
|
|
262
|
+
return this.client.request("PATCH", `${Paths.Chats}/${req.chat_id}`, {
|
|
263
|
+
payload: req
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* DeleteChat deletes a group chat for all participants.
|
|
269
|
+
* @example
|
|
270
|
+
* await bot.chats.deleteChat({ chat_id: 123456789 });
|
|
271
|
+
*/
|
|
272
|
+
deleteChat(req) {
|
|
273
|
+
return __async(this, null, function* () {
|
|
274
|
+
return this.client.request("DELETE", `${Paths.Chats}/${req.chat_id}`);
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* SendAction allows sending bot actions to a group chat (e.g., "typing").
|
|
279
|
+
* @example
|
|
280
|
+
* await bot.chats.sendAction({ chat_id: 123456789, action: "typing" });
|
|
281
|
+
*/
|
|
282
|
+
sendAction(req) {
|
|
283
|
+
return __async(this, null, function* () {
|
|
284
|
+
return this.client.request("POST", `${Paths.Chats}/${req.chat_id}/actions`, {
|
|
285
|
+
payload: req
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* GetPinnedMessage returns the pinned message in a chat.
|
|
291
|
+
* @example
|
|
292
|
+
* const response = await bot.chats.getPinnedMessage({ chat_id: 123456789 });
|
|
293
|
+
*/
|
|
294
|
+
getPinnedMessage(req) {
|
|
295
|
+
return __async(this, null, function* () {
|
|
296
|
+
return this.client.request("GET", `${Paths.Chats}/${req.chat_id}/pin`);
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* PinMessage pins a message in a group chat.
|
|
301
|
+
* @example
|
|
302
|
+
* await bot.chats.pinMessage({ chat_id: 123456789, message_id: "456" });
|
|
303
|
+
*/
|
|
304
|
+
pinMessage(req) {
|
|
305
|
+
return __async(this, null, function* () {
|
|
306
|
+
return this.client.request("PUT", `${Paths.Chats}/${req.chat_id}/pin`, {
|
|
307
|
+
payload: req
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* UnpinMessage removes the pinned message in a group chat.
|
|
313
|
+
* @example
|
|
314
|
+
* await bot.chats.unpinMessage({ chat_id: 123456789 });
|
|
315
|
+
*/
|
|
316
|
+
unpinMessage(req) {
|
|
317
|
+
return __async(this, null, function* () {
|
|
318
|
+
return this.client.request("DELETE", `${Paths.Chats}/${req.chat_id}/pin`);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* GetChatMembership returns the bot's membership details in a group chat.
|
|
323
|
+
* @example
|
|
324
|
+
* const response = await bot.chats.getChatMembership({ chat_id: 123456789 });
|
|
325
|
+
*/
|
|
326
|
+
getChatMembership(req) {
|
|
327
|
+
return __async(this, null, function* () {
|
|
328
|
+
return this.client.request("GET", `${Paths.Chats}/${req.chat_id}/members/me`);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* LeaveChat removes the bot from a group chat.
|
|
333
|
+
* @example
|
|
334
|
+
* await bot.chats.leaveChat({ chat_id: 123456789 });
|
|
335
|
+
*/
|
|
336
|
+
leaveChat(req) {
|
|
337
|
+
return __async(this, null, function* () {
|
|
338
|
+
return this.client.request("DELETE", `${Paths.Chats}/${req.chat_id}/members/me`);
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* GetChatAdmins returns a list of all group chat administrators.
|
|
343
|
+
* @example
|
|
344
|
+
* const response = await bot.chats.getChatAdmins({ chat_id: 123456789 });
|
|
345
|
+
*/
|
|
346
|
+
getChatAdmins(req) {
|
|
347
|
+
return __async(this, null, function* () {
|
|
348
|
+
return this.client.request("GET", `${Paths.Chats}/${req.chat_id}/members/admins`);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* SetChatAdmins assigns a group member as an administrator.
|
|
353
|
+
* @example
|
|
354
|
+
* await bot.chats.setChatAdmins({ chat_id: 123456789, user_id: 456 });
|
|
355
|
+
*/
|
|
356
|
+
setChatAdmins(req) {
|
|
357
|
+
return __async(this, null, function* () {
|
|
358
|
+
return this.client.request("POST", `${Paths.Chats}/${req.chat_id}/members/admins`, {
|
|
359
|
+
payload: req
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* DeleteAdmin revokes the user's administrator rights in a group chat.
|
|
365
|
+
* @example
|
|
366
|
+
* await bot.chats.deleteAdmin({ chat_id: 123456789, user_id: 456 });
|
|
367
|
+
*/
|
|
368
|
+
deleteAdmin(req) {
|
|
369
|
+
return __async(this, null, function* () {
|
|
370
|
+
return this.client.request("DELETE", `${Paths.Chats}/${req.chat_id}/members/admins/${req.user_id}`);
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* GetChatMembers returns a list of participants in a group chat.
|
|
375
|
+
* @example
|
|
376
|
+
* const response = await bot.chats.getChatMembers({ chat_id: 123456789, limit: 50 });
|
|
377
|
+
*/
|
|
378
|
+
getChatMembers(req) {
|
|
379
|
+
return __async(this, null, function* () {
|
|
380
|
+
return this.client.request("GET", `${Paths.Chats}/${req.chat_id}/members`, {
|
|
381
|
+
query: req
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* AddMembers adds participants to a group chat.
|
|
387
|
+
* @example
|
|
388
|
+
* await bot.chats.addMembers({ chat_id: 123456789, user_ids: [456, 789] });
|
|
389
|
+
*/
|
|
390
|
+
addMembers(req) {
|
|
391
|
+
return __async(this, null, function* () {
|
|
392
|
+
return this.client.request("POST", `${Paths.Chats}/${req.chat_id}/members`, {
|
|
393
|
+
payload: req
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* DeleteMember removes a participant from a group chat.
|
|
399
|
+
* @example
|
|
400
|
+
* await bot.chats.deleteMember({ chat_id: 123456789, user_id: 456 });
|
|
401
|
+
*/
|
|
402
|
+
deleteMember(req) {
|
|
403
|
+
return __async(this, null, function* () {
|
|
404
|
+
return this.client.request("DELETE", `${Paths.Chats}/${req.chat_id}/members`, {
|
|
405
|
+
query: req
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// src/api/helpers.ts
|
|
412
|
+
var import_os = require("os");
|
|
413
|
+
var import_path2 = require("path");
|
|
414
|
+
var import_promises2 = require("fs/promises");
|
|
415
|
+
|
|
416
|
+
// src/api/uploads.ts
|
|
417
|
+
var import_promises = require("fs/promises");
|
|
418
|
+
var import_path = require("path");
|
|
419
|
+
var import_crypto = require("crypto");
|
|
420
|
+
var UploadsService = class {
|
|
421
|
+
constructor(client) {
|
|
422
|
+
this.client = client;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* UploadFile uploads a file to MAX servers for subsequent transmission.
|
|
426
|
+
* It handles both the initial request for an upload URL and the actual multipart upload.
|
|
427
|
+
* @param req - Upload parameters (type, file_path).
|
|
428
|
+
* @returns Promise<UploadedInfo> containing the file token.
|
|
429
|
+
* @example
|
|
430
|
+
* const response = await bot.uploads.uploadFile({ type: "image", file_path: "./corgi.png" });
|
|
431
|
+
* console.log("File token:", file.token);
|
|
432
|
+
*/
|
|
433
|
+
uploadFile(req) {
|
|
434
|
+
return __async(this, null, function* () {
|
|
435
|
+
const initResp = yield this.getupload_url(req.type);
|
|
436
|
+
if (!initResp.url) {
|
|
437
|
+
if (initResp.token) {
|
|
438
|
+
return { token: initResp.token };
|
|
439
|
+
}
|
|
440
|
+
throw new Error("Upload failed: server did not return an upload URL or token.");
|
|
441
|
+
}
|
|
442
|
+
let multipartResp;
|
|
443
|
+
try {
|
|
444
|
+
multipartResp = yield this.uploadMultipart(initResp.url, req.file_path);
|
|
445
|
+
if (multipartResp) {
|
|
446
|
+
if (multipartResp.token) {
|
|
447
|
+
return { token: multipartResp.token };
|
|
448
|
+
}
|
|
449
|
+
const anyResp = multipartResp;
|
|
450
|
+
if (anyResp.photos) {
|
|
451
|
+
const photoKeys = Object.keys(anyResp.photos);
|
|
452
|
+
if (photoKeys.length > 0 && anyResp.photos[photoKeys[0]].token) {
|
|
453
|
+
return { token: anyResp.photos[photoKeys[0]].token };
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
} catch (err) {
|
|
458
|
+
if (initResp.token) {
|
|
459
|
+
return { token: initResp.token };
|
|
460
|
+
}
|
|
461
|
+
throw err;
|
|
462
|
+
}
|
|
463
|
+
if (initResp.token) {
|
|
464
|
+
return { token: initResp.token };
|
|
465
|
+
}
|
|
466
|
+
throw new Error(`Server did not return a token after upload. Response: ${JSON.stringify(multipartResp)}`);
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
getupload_url(uploadType) {
|
|
470
|
+
return __async(this, null, function* () {
|
|
471
|
+
return this.client.request("POST", Paths.Uploads, {
|
|
472
|
+
query: { type: uploadType }
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
uploadMultipart(upload_url, file_path) {
|
|
477
|
+
return __async(this, null, function* () {
|
|
478
|
+
const fileData = yield (0, import_promises.readFile)(file_path);
|
|
479
|
+
const filename = (0, import_path.basename)(file_path);
|
|
480
|
+
const boundary = "----MaxBotFormBoundary" + (0, import_crypto.randomBytes)(16).toString("hex");
|
|
481
|
+
const CRLF = "\r\n";
|
|
482
|
+
const header = Buffer.from(
|
|
483
|
+
`--${boundary}${CRLF}Content-Disposition: form-data; name="file"; filename="${filename}"${CRLF}Content-Type: application/octet-stream${CRLF}${CRLF}`
|
|
484
|
+
);
|
|
485
|
+
const footer = Buffer.from(`${CRLF}--${boundary}--${CRLF}`);
|
|
486
|
+
const payload = Buffer.concat([header, fileData, footer]);
|
|
487
|
+
return this.client.request("POST", upload_url, {
|
|
488
|
+
body: payload,
|
|
489
|
+
headers: {
|
|
490
|
+
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
491
|
+
"Content-Length": payload.length.toString()
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
// src/models/schema.ts
|
|
499
|
+
function attachImage(token, url) {
|
|
500
|
+
const payload = {};
|
|
501
|
+
if (token) payload.token = token;
|
|
502
|
+
if (url) payload.url = url;
|
|
503
|
+
return {
|
|
504
|
+
type: "image" /* Image */,
|
|
505
|
+
payload
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
function attachVideo(token, url) {
|
|
509
|
+
const payload = {};
|
|
510
|
+
if (token) payload.token = token;
|
|
511
|
+
if (url) payload.url = url;
|
|
512
|
+
return {
|
|
513
|
+
type: "video" /* Video */,
|
|
514
|
+
payload
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
function attachAudio(token, url) {
|
|
518
|
+
const payload = {};
|
|
519
|
+
if (token) payload.token = token;
|
|
520
|
+
if (url) payload.url = url;
|
|
521
|
+
return {
|
|
522
|
+
type: "audio" /* Audio */,
|
|
523
|
+
payload
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function attachFile(token, url, filename) {
|
|
527
|
+
const payload = { filename: filename || "" };
|
|
528
|
+
if (token) payload.token = token;
|
|
529
|
+
if (url) payload.url = url;
|
|
530
|
+
return {
|
|
531
|
+
type: "file" /* File */,
|
|
532
|
+
payload
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/api/helpers.ts
|
|
537
|
+
var MIME_TO_EXT = {
|
|
538
|
+
"image/jpeg": ".jpg",
|
|
539
|
+
"image/png": ".png",
|
|
540
|
+
"image/webp": ".webp",
|
|
541
|
+
"video/mp4": ".mp4",
|
|
542
|
+
"audio/mpeg": ".mp3",
|
|
543
|
+
"audio/ogg": ".ogg",
|
|
544
|
+
"audio/wav": ".wav",
|
|
545
|
+
"application/pdf": ".pdf"
|
|
546
|
+
};
|
|
547
|
+
var HelpersService = class {
|
|
548
|
+
constructor(client) {
|
|
549
|
+
this.client = client;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* SendFile simplifies file sending by automatically determining if the source is a URL or a local path.
|
|
553
|
+
* @param req - File send request parameters.
|
|
554
|
+
* @example
|
|
555
|
+
* await bot.helpers.sendFile({ chat_id: 123, file_source: "./photo.jpg" });
|
|
556
|
+
* await bot.helpers.sendFile({ chat_id: 123, file_source: "https://site.com/image.png" });
|
|
557
|
+
*/
|
|
558
|
+
sendFile(req) {
|
|
559
|
+
return __async(this, null, function* () {
|
|
560
|
+
if (this.isURL(req.file_source)) {
|
|
561
|
+
return this.sendFileByUrl(req);
|
|
562
|
+
}
|
|
563
|
+
return this.sendFileByUpload(req);
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* SendFileByUrl sends a file using a direct URL. If the file is not an image,
|
|
568
|
+
* it will be downloaded to a temporary directory and uploaded to MAX servers.
|
|
569
|
+
* @param req - File send request with a URL in file_source.
|
|
570
|
+
*/
|
|
571
|
+
sendFileByUrl(req) {
|
|
572
|
+
return __async(this, null, function* () {
|
|
573
|
+
const extInUrl = this.getExtension(req.file_source);
|
|
574
|
+
if (this.determineUploadType(extInUrl) === "image" /* Image */) {
|
|
575
|
+
const attachment2 = {
|
|
576
|
+
type: "image" /* Image */,
|
|
577
|
+
payload: { url: req.file_source }
|
|
578
|
+
};
|
|
579
|
+
return this.sendInternal(req, attachment2);
|
|
580
|
+
}
|
|
581
|
+
const { tempPath, ext } = yield this.downloadTempFile(req.file_source);
|
|
582
|
+
const uploadType = this.determineUploadType(ext);
|
|
583
|
+
const uploader = new UploadsService(this.client);
|
|
584
|
+
const uploadResp = yield uploader.uploadFile({
|
|
585
|
+
type: uploadType,
|
|
586
|
+
file_path: tempPath
|
|
587
|
+
});
|
|
588
|
+
const filename = (0, import_path2.basename)(req.file_source);
|
|
589
|
+
const attachment = this.buildAttachmentFromToken(uploadType, uploadResp.token, filename);
|
|
590
|
+
return this.sendInternal(req, attachment);
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* SendFileByUpload uploads a local file to MAX servers and sends it to the chat.
|
|
595
|
+
* @param req - File send request with a local path in file_source.
|
|
596
|
+
*/
|
|
597
|
+
sendFileByUpload(req) {
|
|
598
|
+
return __async(this, null, function* () {
|
|
599
|
+
const ext = this.getExtension(req.file_source);
|
|
600
|
+
const uploadType = this.determineUploadType(ext);
|
|
601
|
+
const uploader = new UploadsService(this.client);
|
|
602
|
+
const uploadResp = yield uploader.uploadFile({
|
|
603
|
+
type: uploadType,
|
|
604
|
+
file_path: req.file_source
|
|
605
|
+
});
|
|
606
|
+
if (!uploadResp.token) {
|
|
607
|
+
throw new Error("Failed to auto-upload file: no token returned");
|
|
608
|
+
}
|
|
609
|
+
const filename = (0, import_path2.basename)(req.file_source);
|
|
610
|
+
const attachment = this.buildAttachmentFromToken(uploadType, uploadResp.token, filename);
|
|
611
|
+
return this.sendInternal(req, attachment);
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
sendInternal(req, attachment) {
|
|
615
|
+
return __async(this, null, function* () {
|
|
616
|
+
const allAttachments = [...req.attachments || [], attachment];
|
|
617
|
+
const requestPayload = {
|
|
618
|
+
user_id: req.user_id,
|
|
619
|
+
chat_id: req.chat_id,
|
|
620
|
+
text: req.text,
|
|
621
|
+
format: req.format,
|
|
622
|
+
attachments: allAttachments,
|
|
623
|
+
notify: req.notify,
|
|
624
|
+
link: req.link,
|
|
625
|
+
disable_link_preview: req.disable_link_preview
|
|
626
|
+
};
|
|
627
|
+
let lastErr;
|
|
628
|
+
for (let i = 0; i < 3; i++) {
|
|
629
|
+
try {
|
|
630
|
+
const response = yield this.client.request("POST", Paths.Messages, {
|
|
631
|
+
query: requestPayload,
|
|
632
|
+
payload: requestPayload
|
|
633
|
+
});
|
|
634
|
+
return response;
|
|
635
|
+
} catch (err) {
|
|
636
|
+
lastErr = err;
|
|
637
|
+
if (err.message && err.message.includes("not.ready")) {
|
|
638
|
+
yield new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
throw lastErr;
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
isURL(str) {
|
|
648
|
+
try {
|
|
649
|
+
const u = new URL(str);
|
|
650
|
+
return u.protocol === "http:" || u.protocol === "https:";
|
|
651
|
+
} catch (e) {
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
getExtension(source) {
|
|
656
|
+
if (this.isURL(source)) {
|
|
657
|
+
try {
|
|
658
|
+
const u = new URL(source);
|
|
659
|
+
return (0, import_path2.extname)(u.pathname).toLowerCase();
|
|
660
|
+
} catch (e) {
|
|
661
|
+
return "";
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
return (0, import_path2.extname)(source).toLowerCase();
|
|
665
|
+
}
|
|
666
|
+
determineUploadType(ext) {
|
|
667
|
+
switch (ext) {
|
|
668
|
+
case ".jpg":
|
|
669
|
+
case ".jpeg":
|
|
670
|
+
case ".png":
|
|
671
|
+
case ".webp":
|
|
672
|
+
return "image" /* Image */;
|
|
673
|
+
case ".mp4":
|
|
674
|
+
case ".avi":
|
|
675
|
+
case ".mov":
|
|
676
|
+
return "video" /* Video */;
|
|
677
|
+
case ".mp3":
|
|
678
|
+
case ".ogg":
|
|
679
|
+
case ".wav":
|
|
680
|
+
return "audio" /* Audio */;
|
|
681
|
+
default:
|
|
682
|
+
return "file" /* File */;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
buildAttachmentFromToken(uType, token, filename) {
|
|
686
|
+
switch (uType) {
|
|
687
|
+
case "image" /* Image */:
|
|
688
|
+
return attachImage(token, "");
|
|
689
|
+
case "video" /* Video */:
|
|
690
|
+
return attachVideo(token, "");
|
|
691
|
+
case "audio" /* Audio */:
|
|
692
|
+
return attachAudio(token, "");
|
|
693
|
+
default:
|
|
694
|
+
return attachFile(token, "", filename);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
downloadTempFile(urlStr) {
|
|
698
|
+
return __async(this, null, function* () {
|
|
699
|
+
const resp = yield fetch(urlStr);
|
|
700
|
+
if (!resp.ok) {
|
|
701
|
+
throw new Error(`Failed to download file: ${resp.statusText}`);
|
|
702
|
+
}
|
|
703
|
+
let contentType = resp.headers.get("Content-Type") || "";
|
|
704
|
+
contentType = contentType.split(";")[0].trim();
|
|
705
|
+
let ext = MIME_TO_EXT[contentType];
|
|
706
|
+
if (!ext) {
|
|
707
|
+
ext = this.getExtension(urlStr);
|
|
708
|
+
}
|
|
709
|
+
if (!ext) {
|
|
710
|
+
ext = ".bin";
|
|
711
|
+
}
|
|
712
|
+
const buffer = yield resp.arrayBuffer();
|
|
713
|
+
const tempFileName = `maxbot_${Date.now()}_${Math.floor(Math.random() * 1e4)}${ext}`;
|
|
714
|
+
const tempPath = (0, import_path2.join)((0, import_os.tmpdir)(), tempFileName);
|
|
715
|
+
yield (0, import_promises2.writeFile)(tempPath, Buffer.from(buffer));
|
|
716
|
+
return { tempPath, ext };
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
// src/api/messages.ts
|
|
722
|
+
var MessagesService = class {
|
|
723
|
+
constructor(client) {
|
|
724
|
+
this.client = client;
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* GetMessages returns information about a message or an array of messages from a chat.
|
|
728
|
+
* @param req - Query parameters (chat_id, user_id, limit, etc.).
|
|
729
|
+
* @example
|
|
730
|
+
* const response = await bot.messages.getMessages({ chat_id: 123, limit: 10 });
|
|
731
|
+
*/
|
|
732
|
+
getMessages(req) {
|
|
733
|
+
return __async(this, null, function* () {
|
|
734
|
+
return this.client.request("GET", Paths.Messages, {
|
|
735
|
+
query: req
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* SendMessage sends a text or media message to a specified user or chat.
|
|
741
|
+
* @param req - Message parameters including text and attachments.
|
|
742
|
+
* @example
|
|
743
|
+
* await bot.messages.sendMessage({ user_id: 123, text: "Hello!" });
|
|
744
|
+
*/
|
|
745
|
+
sendMessage(req) {
|
|
746
|
+
return __async(this, null, function* () {
|
|
747
|
+
return this.client.request("POST", Paths.Messages, {
|
|
748
|
+
query: req,
|
|
749
|
+
payload: req
|
|
750
|
+
});
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* EditMessage edits the text or media of a previously sent message.
|
|
755
|
+
* @param req - Edit parameters (message_id, new text, etc.).
|
|
756
|
+
* @example
|
|
757
|
+
* await bot.messages.editMessage({ message_id: 456, text: "Updated text" });
|
|
758
|
+
*/
|
|
759
|
+
editMessage(req) {
|
|
760
|
+
return __async(this, null, function* () {
|
|
761
|
+
return this.client.request("PUT", Paths.Messages, {
|
|
762
|
+
query: req,
|
|
763
|
+
payload: req
|
|
764
|
+
});
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* DeleteMessage deletes a message from a chat.
|
|
769
|
+
* @example
|
|
770
|
+
* await bot.messages.deleteMessage({ chat_id: 123, message_id: 456 });
|
|
771
|
+
*/
|
|
772
|
+
deleteMessage(req) {
|
|
773
|
+
return __async(this, null, function* () {
|
|
774
|
+
return this.client.request("DELETE", Paths.Messages, {
|
|
775
|
+
query: req
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* GetMessage extracts the content and metadata of a specific message by its ID.
|
|
781
|
+
* @example
|
|
782
|
+
* const response = await bot.messages.getMessage({ message_id: 456 });
|
|
783
|
+
*/
|
|
784
|
+
getMessage(req) {
|
|
785
|
+
return __async(this, null, function* () {
|
|
786
|
+
return this.client.request("GET", `${Paths.Messages}/${req.message_id}`);
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* GetVideoInfo returns detailed information about an attached video.
|
|
791
|
+
* @example
|
|
792
|
+
* const response = await bot.messages.getVideoInfo({ video_token: "video123" });
|
|
793
|
+
*/
|
|
794
|
+
getVideoInfo(req) {
|
|
795
|
+
return __async(this, null, function* () {
|
|
796
|
+
return this.client.request("GET", `${Paths.Videos}/${req.video_token}`);
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* AnswerCallback sends a response after a user clicks a button.
|
|
801
|
+
* @example
|
|
802
|
+
* await bot.messages.answerCallback({ callback_id: "cb123", text: "Got it!" });
|
|
803
|
+
*/
|
|
804
|
+
answerCallback(req) {
|
|
805
|
+
return __async(this, null, function* () {
|
|
806
|
+
return this.client.request("POST", Paths.Answers, {
|
|
807
|
+
query: req,
|
|
808
|
+
payload: req
|
|
809
|
+
});
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
// src/api/subscriptions.ts
|
|
815
|
+
var SubscriptionsService = class {
|
|
816
|
+
constructor(client) {
|
|
817
|
+
this.client = client;
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* GetSubscriptions returns a list of webhook notification subscriptions.
|
|
821
|
+
* @example
|
|
822
|
+
* const response = await bot.subscriptions.getSubscriptions();
|
|
823
|
+
*/
|
|
824
|
+
getSubscriptions() {
|
|
825
|
+
return __async(this, null, function* () {
|
|
826
|
+
return this.client.request("GET", Paths.Subscriptions);
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Subscribe configures the delivery of bot events via a webhook.
|
|
831
|
+
* @param req - Subscription parameters (url, types).
|
|
832
|
+
* @example
|
|
833
|
+
* await bot.subscriptions.subscribe({ url: "https://my.site/webhook", types: ["message.created"] });
|
|
834
|
+
*/
|
|
835
|
+
subscribe(req) {
|
|
836
|
+
return __async(this, null, function* () {
|
|
837
|
+
return this.client.request("POST", Paths.Subscriptions, {
|
|
838
|
+
payload: req
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Unsubscribe cancels the bot's subscription to receiving updates via webhook.
|
|
844
|
+
* @example
|
|
845
|
+
* await bot.subscriptions.unsubscribe({ url: "https://my.site/webhook" });
|
|
846
|
+
*/
|
|
847
|
+
unsubscribe(req) {
|
|
848
|
+
return __async(this, null, function* () {
|
|
849
|
+
return this.client.request("DELETE", Paths.Subscriptions, {
|
|
850
|
+
query: req
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* GetUpdates retrieves incoming updates (Long-polling).
|
|
856
|
+
* @param req - Polling parameters (marker, timeout, limit).
|
|
857
|
+
* @example
|
|
858
|
+
* const response = await bot.subscriptions.getUpdates({ timeout: 25 });
|
|
859
|
+
*/
|
|
860
|
+
getUpdates(req) {
|
|
861
|
+
return __async(this, null, function* () {
|
|
862
|
+
return this.client.request("GET", Paths.Updates, {
|
|
863
|
+
query: req
|
|
864
|
+
});
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
// src/api/api.ts
|
|
870
|
+
var MaxBotAPI = class {
|
|
871
|
+
constructor(cfg) {
|
|
872
|
+
this.client = new APIClient(cfg);
|
|
873
|
+
this.bots = new BotsService(this.client);
|
|
874
|
+
this.chats = new ChatsService(this.client);
|
|
875
|
+
this.helpers = new HelpersService(this.client);
|
|
876
|
+
this.messages = new MessagesService(this.client);
|
|
877
|
+
this.subscriptions = new SubscriptionsService(this.client);
|
|
878
|
+
this.uploads = new UploadsService(this.client);
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
882
|
+
0 && (module.exports = {
|
|
883
|
+
MaxBotAPI
|
|
884
|
+
});
|