gramio 0.0.50 → 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 +1 -1
- package/dist/index.cjs +1191 -0
- package/dist/index.d.cts +1012 -0
- package/dist/index.d.ts +1009 -13
- package/dist/index.js +1157 -31
- package/package.json +24 -11
- package/dist/bot.d.ts +0 -404
- package/dist/bot.js +0 -824
- package/dist/composer.d.ts +0 -34
- package/dist/composer.js +0 -71
- package/dist/errors.d.ts +0 -17
- package/dist/errors.js +0 -29
- package/dist/filters.d.ts +0 -20
- package/dist/filters.js +0 -23
- package/dist/plugin.d.ts +0 -218
- package/dist/plugin.js +0 -269
- package/dist/types.d.ts +0 -242
- package/dist/types.js +0 -2
- package/dist/updates.d.ts +0 -17
- package/dist/updates.js +0 -87
- package/dist/webhook/adapters.d.ts +0 -53
- package/dist/webhook/adapters.js +0 -58
- package/dist/webhook/index.d.ts +0 -35
- package/dist/webhook/index.js +0 -46
package/dist/bot.js
DELETED
|
@@ -1,824 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
3
|
-
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
4
|
-
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
5
|
-
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
6
|
-
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
7
|
-
var _, done = false;
|
|
8
|
-
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
9
|
-
var context = {};
|
|
10
|
-
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
11
|
-
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
12
|
-
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
13
|
-
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
14
|
-
if (kind === "accessor") {
|
|
15
|
-
if (result === void 0) continue;
|
|
16
|
-
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
17
|
-
if (_ = accept(result.get)) descriptor.get = _;
|
|
18
|
-
if (_ = accept(result.set)) descriptor.set = _;
|
|
19
|
-
if (_ = accept(result.init)) initializers.unshift(_);
|
|
20
|
-
}
|
|
21
|
-
else if (_ = accept(result)) {
|
|
22
|
-
if (kind === "field") initializers.unshift(_);
|
|
23
|
-
else descriptor[key] = _;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
27
|
-
done = true;
|
|
28
|
-
};
|
|
29
|
-
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
30
|
-
var useValue = arguments.length > 2;
|
|
31
|
-
for (var i = 0; i < initializers.length; i++) {
|
|
32
|
-
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
33
|
-
}
|
|
34
|
-
return useValue ? value : void 0;
|
|
35
|
-
};
|
|
36
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
-
};
|
|
39
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
-
exports.Bot = void 0;
|
|
41
|
-
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
42
|
-
const node_stream_1 = require("node:stream");
|
|
43
|
-
const callback_data_1 = require("@gramio/callback-data");
|
|
44
|
-
const contexts_1 = require("@gramio/contexts");
|
|
45
|
-
const files_1 = require("@gramio/files");
|
|
46
|
-
const format_1 = require("@gramio/format");
|
|
47
|
-
const debug_1 = __importDefault(require("debug"));
|
|
48
|
-
const inspectable_1 = require("inspectable");
|
|
49
|
-
const errors_1 = require("./errors");
|
|
50
|
-
const plugin_1 = require("./plugin");
|
|
51
|
-
const updates_1 = require("./updates");
|
|
52
|
-
const $debugger = (0, debug_1.default)("gramio");
|
|
53
|
-
const debug$api = $debugger.extend("api");
|
|
54
|
-
/** Bot instance
|
|
55
|
-
*
|
|
56
|
-
* @example
|
|
57
|
-
* ```ts
|
|
58
|
-
* import { Bot } from "gramio";
|
|
59
|
-
*
|
|
60
|
-
* const bot = new Bot("") // put you token here
|
|
61
|
-
* .command("start", (context) => context.send("Hi!"))
|
|
62
|
-
* .onStart(console.log);
|
|
63
|
-
*
|
|
64
|
-
* bot.start();
|
|
65
|
-
* ```
|
|
66
|
-
*/
|
|
67
|
-
let Bot = (() => {
|
|
68
|
-
let _classDecorators = [(0, inspectable_1.Inspectable)({
|
|
69
|
-
serialize: () => ({}),
|
|
70
|
-
})];
|
|
71
|
-
let _classDescriptor;
|
|
72
|
-
let _classExtraInitializers = [];
|
|
73
|
-
let _classThis;
|
|
74
|
-
var Bot = class {
|
|
75
|
-
static { _classThis = this; }
|
|
76
|
-
static {
|
|
77
|
-
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
78
|
-
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
79
|
-
Bot = _classThis = _classDescriptor.value;
|
|
80
|
-
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
81
|
-
__runInitializers(_classThis, _classExtraInitializers);
|
|
82
|
-
}
|
|
83
|
-
_ = {
|
|
84
|
-
/** @internal. Remap generic */
|
|
85
|
-
derives: {},
|
|
86
|
-
};
|
|
87
|
-
/** @internal. Remap generic */
|
|
88
|
-
__Derives;
|
|
89
|
-
filters = {
|
|
90
|
-
context: (name) => (context) => context.is(name),
|
|
91
|
-
};
|
|
92
|
-
/** Options provided to instance */
|
|
93
|
-
options;
|
|
94
|
-
/** Bot data (filled in when calling bot.init/bot.start) */
|
|
95
|
-
info;
|
|
96
|
-
/**
|
|
97
|
-
* Send API Request to Telegram Bot API
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* ```ts
|
|
101
|
-
* const response = await bot.api.sendMessage({
|
|
102
|
-
* chat_id: "@gramio_forum",
|
|
103
|
-
* text: "some text",
|
|
104
|
-
* });
|
|
105
|
-
* ```
|
|
106
|
-
*
|
|
107
|
-
* [Documentation](https://gramio.dev/bot-api.html)
|
|
108
|
-
*/
|
|
109
|
-
api = new Proxy({}, {
|
|
110
|
-
get: (_target, method) =>
|
|
111
|
-
// @ts-expect-error
|
|
112
|
-
// biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
|
|
113
|
-
(_target[method] ??= (args) => this._callApi(method, args)),
|
|
114
|
-
});
|
|
115
|
-
lazyloadPlugins = [];
|
|
116
|
-
dependencies = [];
|
|
117
|
-
errorsDefinitions = {
|
|
118
|
-
TELEGRAM: errors_1.TelegramError,
|
|
119
|
-
};
|
|
120
|
-
errorHandler(context, error) {
|
|
121
|
-
if (!this.hooks.onError.length)
|
|
122
|
-
throw error;
|
|
123
|
-
return this.runImmutableHooks("onError", {
|
|
124
|
-
context,
|
|
125
|
-
//@ts-expect-error ErrorKind exists if user register error-class with .error("kind", SomeError);
|
|
126
|
-
kind: error.constructor[errors_1.ErrorKind] ?? "UNKNOWN",
|
|
127
|
-
error: error,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
/** This instance handle updates */
|
|
131
|
-
updates = new updates_1.Updates(this, this.errorHandler.bind(this));
|
|
132
|
-
hooks = {
|
|
133
|
-
preRequest: [],
|
|
134
|
-
onResponse: [],
|
|
135
|
-
onResponseError: [],
|
|
136
|
-
onError: [],
|
|
137
|
-
onStart: [],
|
|
138
|
-
onStop: [],
|
|
139
|
-
};
|
|
140
|
-
constructor(tokenOrOptions, options) {
|
|
141
|
-
const token = typeof tokenOrOptions === "string"
|
|
142
|
-
? tokenOrOptions
|
|
143
|
-
: tokenOrOptions?.token;
|
|
144
|
-
if (!token || typeof token !== "string")
|
|
145
|
-
throw new Error(`Token is ${typeof token} but it should be a string!`);
|
|
146
|
-
this.options = {
|
|
147
|
-
...(typeof tokenOrOptions === "object" ? tokenOrOptions : options),
|
|
148
|
-
token,
|
|
149
|
-
api: {
|
|
150
|
-
baseURL: "https://api.telegram.org/bot",
|
|
151
|
-
retryGetUpdatesWait: 1000,
|
|
152
|
-
...options?.api,
|
|
153
|
-
},
|
|
154
|
-
};
|
|
155
|
-
if (!(options?.plugins &&
|
|
156
|
-
"format" in options.plugins &&
|
|
157
|
-
!options.plugins.format))
|
|
158
|
-
this.extend(new plugin_1.Plugin("@gramio/format").preRequest((context) => {
|
|
159
|
-
if (!context.params)
|
|
160
|
-
return context;
|
|
161
|
-
// @ts-ignore
|
|
162
|
-
const formattable = format_1.FormattableMap[context.method];
|
|
163
|
-
// @ts-ignore add AnyTelegramMethod to @gramio/format
|
|
164
|
-
if (formattable)
|
|
165
|
-
context.params = formattable(context.params);
|
|
166
|
-
return context;
|
|
167
|
-
}));
|
|
168
|
-
}
|
|
169
|
-
async runHooks(type, context) {
|
|
170
|
-
let data = context;
|
|
171
|
-
for await (const hook of this.hooks[type]) {
|
|
172
|
-
data = await hook(data);
|
|
173
|
-
}
|
|
174
|
-
return data;
|
|
175
|
-
}
|
|
176
|
-
async runImmutableHooks(type, ...context) {
|
|
177
|
-
for await (const hook of this.hooks[type]) {
|
|
178
|
-
//TODO: solve that later
|
|
179
|
-
//@ts-expect-error
|
|
180
|
-
await hook(...context);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
async _callApi(method, params = {}) {
|
|
184
|
-
const debug$api$method = debug$api.extend(method);
|
|
185
|
-
const url = `${this.options.api.baseURL}${this.options.token}/${method}`;
|
|
186
|
-
// Omit<
|
|
187
|
-
// NonNullable<Parameters<typeof fetch>[1]>,
|
|
188
|
-
// "headers"
|
|
189
|
-
// > & {
|
|
190
|
-
// headers: Headers;
|
|
191
|
-
// }
|
|
192
|
-
// idk why it cause https://github.com/gramiojs/gramio/actions/runs/10388006206/job/28762703484
|
|
193
|
-
// also in logs types differs
|
|
194
|
-
const reqOptions = {
|
|
195
|
-
method: "POST",
|
|
196
|
-
...this.options.api.fetchOptions,
|
|
197
|
-
// @ts-ignore types node/bun and global missmatch
|
|
198
|
-
headers: new Headers(this.options.api.fetchOptions?.headers),
|
|
199
|
-
};
|
|
200
|
-
const context = await this.runHooks("preRequest",
|
|
201
|
-
// TODO: fix type error
|
|
202
|
-
// @ts-expect-error
|
|
203
|
-
{
|
|
204
|
-
method,
|
|
205
|
-
params,
|
|
206
|
-
});
|
|
207
|
-
// biome-ignore lint/style/noParameterAssign: mutate params
|
|
208
|
-
params = context.params;
|
|
209
|
-
// @ts-ignore
|
|
210
|
-
if (params && (0, files_1.isMediaUpload)(method, params)) {
|
|
211
|
-
// @ts-ignore
|
|
212
|
-
const formData = await (0, files_1.convertJsonToFormData)(method, params);
|
|
213
|
-
reqOptions.body = formData;
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
reqOptions.headers.set("Content-Type", "application/json");
|
|
217
|
-
reqOptions.body = JSON.stringify(params);
|
|
218
|
-
}
|
|
219
|
-
debug$api$method("options: %j", reqOptions);
|
|
220
|
-
const response = await fetch(url, reqOptions);
|
|
221
|
-
const data = (await response.json());
|
|
222
|
-
debug$api$method("response: %j", data);
|
|
223
|
-
if (!data.ok) {
|
|
224
|
-
const err = new errors_1.TelegramError(data, method, params);
|
|
225
|
-
// @ts-expect-error
|
|
226
|
-
this.runImmutableHooks("onResponseError", err, this.api);
|
|
227
|
-
if (!params?.suppress)
|
|
228
|
-
throw err;
|
|
229
|
-
return err;
|
|
230
|
-
}
|
|
231
|
-
this.runImmutableHooks("onResponse",
|
|
232
|
-
// TODO: fix type error
|
|
233
|
-
// @ts-expect-error
|
|
234
|
-
{
|
|
235
|
-
method,
|
|
236
|
-
params,
|
|
237
|
-
response: data.result,
|
|
238
|
-
});
|
|
239
|
-
return data.result;
|
|
240
|
-
}
|
|
241
|
-
async downloadFile(attachment, path) {
|
|
242
|
-
function getFileId(attachment) {
|
|
243
|
-
if (attachment instanceof contexts_1.PhotoAttachment) {
|
|
244
|
-
return attachment.bigSize.fileId;
|
|
245
|
-
}
|
|
246
|
-
if ("fileId" in attachment && typeof attachment.fileId === "string")
|
|
247
|
-
return attachment.fileId;
|
|
248
|
-
if ("file_id" in attachment)
|
|
249
|
-
return attachment.file_id;
|
|
250
|
-
throw new Error("Invalid attachment");
|
|
251
|
-
}
|
|
252
|
-
const fileId = typeof attachment === "string" ? attachment : getFileId(attachment);
|
|
253
|
-
const file = await this.api.getFile({ file_id: fileId });
|
|
254
|
-
const url = `${this.options.api.baseURL.replace("/bot", "/file/bot")}${this.options.token}/${file.file_path}`;
|
|
255
|
-
const res = await fetch(url);
|
|
256
|
-
if (path) {
|
|
257
|
-
if (!res.body)
|
|
258
|
-
throw new Error("Response without body (should be never throw)");
|
|
259
|
-
// @ts-ignore denoo
|
|
260
|
-
await promises_1.default.writeFile(path, node_stream_1.Readable.fromWeb(res.body));
|
|
261
|
-
return path;
|
|
262
|
-
}
|
|
263
|
-
const buffer = await res.arrayBuffer();
|
|
264
|
-
return buffer;
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Register custom class-error for type-safe catch in `onError` hook
|
|
268
|
-
*
|
|
269
|
-
* @example
|
|
270
|
-
* ```ts
|
|
271
|
-
* export class NoRights extends Error {
|
|
272
|
-
* needRole: "admin" | "moderator";
|
|
273
|
-
*
|
|
274
|
-
* constructor(role: "admin" | "moderator") {
|
|
275
|
-
* super();
|
|
276
|
-
* this.needRole = role;
|
|
277
|
-
* }
|
|
278
|
-
* }
|
|
279
|
-
*
|
|
280
|
-
* const bot = new Bot(process.env.TOKEN!)
|
|
281
|
-
* .error("NO_RIGHTS", NoRights)
|
|
282
|
-
* .onError(({ context, kind, error }) => {
|
|
283
|
-
* if (context.is("message") && kind === "NO_RIGHTS")
|
|
284
|
-
* return context.send(
|
|
285
|
-
* format`You don't have enough rights! You need to have an «${bold(
|
|
286
|
-
* error.needRole
|
|
287
|
-
* )}» role.`
|
|
288
|
-
* );
|
|
289
|
-
* });
|
|
290
|
-
*
|
|
291
|
-
* bot.updates.on("message", (context) => {
|
|
292
|
-
* if (context.text === "bun") throw new NoRights("admin");
|
|
293
|
-
* });
|
|
294
|
-
* ```
|
|
295
|
-
*/
|
|
296
|
-
error(kind, error) {
|
|
297
|
-
//@ts-expect-error Set ErrorKind
|
|
298
|
-
error[errors_1.ErrorKind] = kind;
|
|
299
|
-
this.errorsDefinitions[kind] = error;
|
|
300
|
-
return this;
|
|
301
|
-
}
|
|
302
|
-
onError(updateNameOrHandler, handler) {
|
|
303
|
-
if (typeof updateNameOrHandler === "function") {
|
|
304
|
-
this.hooks.onError.push(updateNameOrHandler);
|
|
305
|
-
return this;
|
|
306
|
-
}
|
|
307
|
-
if (handler) {
|
|
308
|
-
this.hooks.onError.push(async (errContext) => {
|
|
309
|
-
if (errContext.context.is(updateNameOrHandler))
|
|
310
|
-
// TODO: Sorry... fix later
|
|
311
|
-
//@ts-expect-error
|
|
312
|
-
await handler(errContext);
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
return this;
|
|
316
|
-
}
|
|
317
|
-
derive(updateNameOrHandler, handler) {
|
|
318
|
-
this.updates.composer.derive(updateNameOrHandler, handler);
|
|
319
|
-
return this;
|
|
320
|
-
}
|
|
321
|
-
decorate(nameOrRecordValue, value) {
|
|
322
|
-
for (const contextName of Object.keys(contexts_1.contextsMappings)) {
|
|
323
|
-
if (typeof nameOrRecordValue === "string")
|
|
324
|
-
// @ts-expect-error
|
|
325
|
-
Object.defineProperty(contexts_1.contextsMappings[contextName].prototype, name, {
|
|
326
|
-
value,
|
|
327
|
-
});
|
|
328
|
-
else
|
|
329
|
-
Object.defineProperties(
|
|
330
|
-
// @ts-expect-error
|
|
331
|
-
contexts_1.contextsMappings[contextName].prototype, Object.keys(nameOrRecordValue).reduce((acc, key) => {
|
|
332
|
-
acc[key] = { value: nameOrRecordValue[key] };
|
|
333
|
-
return acc;
|
|
334
|
-
}, {}));
|
|
335
|
-
}
|
|
336
|
-
return this;
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* This hook called when the bot is `started`.
|
|
340
|
-
*
|
|
341
|
-
* @example
|
|
342
|
-
* ```typescript
|
|
343
|
-
* import { Bot } from "gramio";
|
|
344
|
-
*
|
|
345
|
-
* const bot = new Bot(process.env.TOKEN!).onStart(
|
|
346
|
-
* ({ plugins, info, updatesFrom }) => {
|
|
347
|
-
* console.log(`plugin list - ${plugins.join(", ")}`);
|
|
348
|
-
* console.log(`bot username is @${info.username}`);
|
|
349
|
-
* console.log(`updates from ${updatesFrom}`);
|
|
350
|
-
* }
|
|
351
|
-
* );
|
|
352
|
-
*
|
|
353
|
-
* bot.start();
|
|
354
|
-
* ```
|
|
355
|
-
*
|
|
356
|
-
* [Documentation](https://gramio.dev/hooks/on-start.html)
|
|
357
|
-
* */
|
|
358
|
-
onStart(handler) {
|
|
359
|
-
this.hooks.onStart.push(handler);
|
|
360
|
-
return this;
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* This hook called when the bot stops.
|
|
364
|
-
*
|
|
365
|
-
* @example
|
|
366
|
-
* ```typescript
|
|
367
|
-
* import { Bot } from "gramio";
|
|
368
|
-
*
|
|
369
|
-
* const bot = new Bot(process.env.TOKEN!).onStop(
|
|
370
|
-
* ({ plugins, info, updatesFrom }) => {
|
|
371
|
-
* console.log(`plugin list - ${plugins.join(", ")}`);
|
|
372
|
-
* console.log(`bot username is @${info.username}`);
|
|
373
|
-
* }
|
|
374
|
-
* );
|
|
375
|
-
*
|
|
376
|
-
* bot.start();
|
|
377
|
-
* bot.stop();
|
|
378
|
-
* ```
|
|
379
|
-
*
|
|
380
|
-
* [Documentation](https://gramio.dev/hooks/on-stop.html)
|
|
381
|
-
* */
|
|
382
|
-
onStop(handler) {
|
|
383
|
-
this.hooks.onStop.push(handler);
|
|
384
|
-
return this;
|
|
385
|
-
}
|
|
386
|
-
preRequest(methodsOrHandler, handler) {
|
|
387
|
-
if (typeof methodsOrHandler === "string" ||
|
|
388
|
-
Array.isArray(methodsOrHandler)) {
|
|
389
|
-
// TODO: error
|
|
390
|
-
if (!handler)
|
|
391
|
-
throw new Error("TODO:");
|
|
392
|
-
const methods = typeof methodsOrHandler === "string"
|
|
393
|
-
? [methodsOrHandler]
|
|
394
|
-
: methodsOrHandler;
|
|
395
|
-
// TODO: remove error
|
|
396
|
-
// @ts-expect-error
|
|
397
|
-
this.hooks.preRequest.push(async (context) => {
|
|
398
|
-
// TODO: remove ts-ignore
|
|
399
|
-
// @ts-expect-error
|
|
400
|
-
if (methods.includes(context.method))
|
|
401
|
-
return handler(context);
|
|
402
|
-
return context;
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
else
|
|
406
|
-
this.hooks.preRequest.push(methodsOrHandler);
|
|
407
|
-
return this;
|
|
408
|
-
}
|
|
409
|
-
onResponse(methodsOrHandler, handler) {
|
|
410
|
-
if (typeof methodsOrHandler === "string" ||
|
|
411
|
-
Array.isArray(methodsOrHandler)) {
|
|
412
|
-
// TODO: error
|
|
413
|
-
if (!handler)
|
|
414
|
-
throw new Error("TODO:");
|
|
415
|
-
const methods = typeof methodsOrHandler === "string"
|
|
416
|
-
? [methodsOrHandler]
|
|
417
|
-
: methodsOrHandler;
|
|
418
|
-
this.hooks.onResponse.push(async (context) => {
|
|
419
|
-
// TODO: remove ts-ignore
|
|
420
|
-
// @ts-expect-error
|
|
421
|
-
if (methods.includes(context.method))
|
|
422
|
-
return handler(context);
|
|
423
|
-
return context;
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
else
|
|
427
|
-
this.hooks.onResponse.push(methodsOrHandler);
|
|
428
|
-
return this;
|
|
429
|
-
}
|
|
430
|
-
onResponseError(methodsOrHandler, handler) {
|
|
431
|
-
if (typeof methodsOrHandler === "string" ||
|
|
432
|
-
Array.isArray(methodsOrHandler)) {
|
|
433
|
-
// TODO: error
|
|
434
|
-
if (!handler)
|
|
435
|
-
throw new Error("TODO:");
|
|
436
|
-
const methods = typeof methodsOrHandler === "string"
|
|
437
|
-
? [methodsOrHandler]
|
|
438
|
-
: methodsOrHandler;
|
|
439
|
-
this.hooks.onResponseError.push(async (context) => {
|
|
440
|
-
// TODO: remove ts-ignore
|
|
441
|
-
// @ts-expect-error
|
|
442
|
-
if (methods.includes(context.method))
|
|
443
|
-
return handler(context);
|
|
444
|
-
return context;
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
else
|
|
448
|
-
this.hooks.onResponseError.push(methodsOrHandler);
|
|
449
|
-
return this;
|
|
450
|
-
}
|
|
451
|
-
// onExperimental(
|
|
452
|
-
// // filter: Filters,
|
|
453
|
-
// filter: (
|
|
454
|
-
// f: Filters<
|
|
455
|
-
// Context<typeof this> & Derives["global"],
|
|
456
|
-
// [{ equal: { prop: number }; addition: { some: () => 2 } }]
|
|
457
|
-
// >,
|
|
458
|
-
// ) => Filters,
|
|
459
|
-
// handler: Handler<Context<typeof this> & Derives["global"]>,
|
|
460
|
-
// ) {}
|
|
461
|
-
/** Register handler to one or many Updates */
|
|
462
|
-
on(updateName, handler) {
|
|
463
|
-
this.updates.composer.on(updateName, handler);
|
|
464
|
-
return this;
|
|
465
|
-
}
|
|
466
|
-
/** Register handler to any Updates */
|
|
467
|
-
use(handler) {
|
|
468
|
-
this.updates.composer.use(handler);
|
|
469
|
-
return this;
|
|
470
|
-
}
|
|
471
|
-
/**
|
|
472
|
-
* Extend {@link Plugin} logic and types
|
|
473
|
-
*
|
|
474
|
-
* @example
|
|
475
|
-
* ```ts
|
|
476
|
-
* import { Plugin, Bot } from "gramio";
|
|
477
|
-
*
|
|
478
|
-
* export class PluginError extends Error {
|
|
479
|
-
* wow: "type" | "safe" = "type";
|
|
480
|
-
* }
|
|
481
|
-
*
|
|
482
|
-
* const plugin = new Plugin("gramio-example")
|
|
483
|
-
* .error("PLUGIN", PluginError)
|
|
484
|
-
* .derive(() => {
|
|
485
|
-
* return {
|
|
486
|
-
* some: ["derived", "props"] as const,
|
|
487
|
-
* };
|
|
488
|
-
* });
|
|
489
|
-
*
|
|
490
|
-
* const bot = new Bot(process.env.TOKEN!)
|
|
491
|
-
* .extend(plugin)
|
|
492
|
-
* .onError(({ context, kind, error }) => {
|
|
493
|
-
* if (context.is("message") && kind === "PLUGIN") {
|
|
494
|
-
* console.log(error.wow);
|
|
495
|
-
* }
|
|
496
|
-
* })
|
|
497
|
-
* .use((context) => {
|
|
498
|
-
* console.log(context.some);
|
|
499
|
-
* });
|
|
500
|
-
* ```
|
|
501
|
-
*/
|
|
502
|
-
extend(plugin) {
|
|
503
|
-
if (plugin instanceof Promise) {
|
|
504
|
-
this.lazyloadPlugins.push(plugin);
|
|
505
|
-
return this;
|
|
506
|
-
}
|
|
507
|
-
if (plugin._.dependencies.some((dep) => !this.dependencies.includes(dep)))
|
|
508
|
-
throw new Error(`The «${plugin._.name}» plugin needs dependencies registered before: ${plugin._.dependencies
|
|
509
|
-
.filter((dep) => !this.dependencies.includes(dep))
|
|
510
|
-
.join(", ")}`);
|
|
511
|
-
if (plugin._.composer.length) {
|
|
512
|
-
this.use(plugin._.composer.composed);
|
|
513
|
-
}
|
|
514
|
-
this.decorate(plugin._.decorators);
|
|
515
|
-
for (const [key, value] of Object.entries(plugin._.errorsDefinitions)) {
|
|
516
|
-
if (this.errorsDefinitions[key])
|
|
517
|
-
this.errorsDefinitions[key] = value;
|
|
518
|
-
}
|
|
519
|
-
for (const value of plugin._.preRequests) {
|
|
520
|
-
const [preRequest, updateName] = value;
|
|
521
|
-
if (!updateName)
|
|
522
|
-
this.preRequest(preRequest);
|
|
523
|
-
else
|
|
524
|
-
this.preRequest(updateName, preRequest);
|
|
525
|
-
}
|
|
526
|
-
for (const value of plugin._.onResponses) {
|
|
527
|
-
const [onResponse, updateName] = value;
|
|
528
|
-
if (!updateName)
|
|
529
|
-
this.onResponse(onResponse);
|
|
530
|
-
else
|
|
531
|
-
this.onResponse(updateName, onResponse);
|
|
532
|
-
}
|
|
533
|
-
for (const value of plugin._.onResponseErrors) {
|
|
534
|
-
const [onResponseError, updateName] = value;
|
|
535
|
-
if (!updateName)
|
|
536
|
-
this.onResponseError(onResponseError);
|
|
537
|
-
else
|
|
538
|
-
this.onResponseError(updateName, onResponseError);
|
|
539
|
-
}
|
|
540
|
-
for (const handler of plugin._.groups) {
|
|
541
|
-
this.group(handler);
|
|
542
|
-
}
|
|
543
|
-
this.dependencies.push(plugin._.name);
|
|
544
|
-
return this;
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* Register handler to reaction (`message_reaction` update)
|
|
548
|
-
*
|
|
549
|
-
* @example
|
|
550
|
-
* ```ts
|
|
551
|
-
* new Bot().reaction("👍", async (context) => {
|
|
552
|
-
* await context.reply(`Thank you!`);
|
|
553
|
-
* });
|
|
554
|
-
* ```
|
|
555
|
-
* */
|
|
556
|
-
reaction(trigger, handler) {
|
|
557
|
-
const reactions = Array.isArray(trigger) ? trigger : [trigger];
|
|
558
|
-
return this.on("message_reaction", (context, next) => {
|
|
559
|
-
const newReactions = [];
|
|
560
|
-
for (const reaction of context.newReactions) {
|
|
561
|
-
if (reaction.type !== "emoji")
|
|
562
|
-
continue;
|
|
563
|
-
const foundIndex = context.oldReactions.findIndex((oldReaction) => oldReaction.type === "emoji" &&
|
|
564
|
-
oldReaction.emoji === reaction.emoji);
|
|
565
|
-
if (foundIndex === -1) {
|
|
566
|
-
newReactions.push(reaction);
|
|
567
|
-
}
|
|
568
|
-
else {
|
|
569
|
-
// TODO: REFACTOR
|
|
570
|
-
context.oldReactions.splice(foundIndex, 1);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
if (!newReactions.some((x) => x.type === "emoji" && reactions.includes(x.emoji)))
|
|
574
|
-
return next();
|
|
575
|
-
return handler(context);
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Register handler to `callback_query` event
|
|
580
|
-
*
|
|
581
|
-
* @example
|
|
582
|
-
* ```ts
|
|
583
|
-
* const someData = new CallbackData("example").number("id");
|
|
584
|
-
*
|
|
585
|
-
* new Bot()
|
|
586
|
-
* .command("start", (context) =>
|
|
587
|
-
* context.send("some", {
|
|
588
|
-
* reply_markup: new InlineKeyboard().text(
|
|
589
|
-
* "example",
|
|
590
|
-
* someData.pack({
|
|
591
|
-
* id: 1,
|
|
592
|
-
* })
|
|
593
|
-
* ),
|
|
594
|
-
* })
|
|
595
|
-
* )
|
|
596
|
-
* .callbackQuery(someData, (context) => {
|
|
597
|
-
* context.queryData; // is type-safe
|
|
598
|
-
* });
|
|
599
|
-
* ```
|
|
600
|
-
*/
|
|
601
|
-
callbackQuery(trigger, handler) {
|
|
602
|
-
return this.on("callback_query", (context, next) => {
|
|
603
|
-
if (!context.data)
|
|
604
|
-
return next();
|
|
605
|
-
if (typeof trigger === "string" && context.data !== trigger)
|
|
606
|
-
return next();
|
|
607
|
-
if (trigger instanceof callback_data_1.CallbackData &&
|
|
608
|
-
!trigger.regexp().test(context.data))
|
|
609
|
-
return next();
|
|
610
|
-
if (trigger instanceof RegExp && !trigger.test(context.data))
|
|
611
|
-
return next();
|
|
612
|
-
if (trigger instanceof callback_data_1.CallbackData)
|
|
613
|
-
// @ts-expect-error
|
|
614
|
-
context.queryData = trigger.unpack(context.data);
|
|
615
|
-
//@ts-expect-error
|
|
616
|
-
return handler(context);
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
/** Register handler to `chosen_inline_result` update */
|
|
620
|
-
chosenInlineResult(trigger, handler) {
|
|
621
|
-
return this.on("chosen_inline_result", (context, next) => {
|
|
622
|
-
if ((typeof trigger === "string" && context.query === trigger) ||
|
|
623
|
-
// @ts-expect-error
|
|
624
|
-
(typeof trigger === "function" && trigger(context)) ||
|
|
625
|
-
(trigger instanceof RegExp && trigger.test(context.query))) {
|
|
626
|
-
//@ts-expect-error
|
|
627
|
-
context.args =
|
|
628
|
-
trigger instanceof RegExp ? context.query?.match(trigger) : null;
|
|
629
|
-
// TODO: remove
|
|
630
|
-
//@ts-expect-error
|
|
631
|
-
return handler(context);
|
|
632
|
-
}
|
|
633
|
-
return next();
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
/**
|
|
637
|
-
* Register handler to `inline_query` update
|
|
638
|
-
*
|
|
639
|
-
* @example
|
|
640
|
-
* ```ts
|
|
641
|
-
* new Bot().inlineQuery(
|
|
642
|
-
* /regular expression with (.*)/i,
|
|
643
|
-
* async (context) => {
|
|
644
|
-
* if (context.args) {
|
|
645
|
-
* await context.answer(
|
|
646
|
-
* [
|
|
647
|
-
* InlineQueryResult.article(
|
|
648
|
-
* "id-1",
|
|
649
|
-
* context.args[1],
|
|
650
|
-
* InputMessageContent.text("some"),
|
|
651
|
-
* {
|
|
652
|
-
* reply_markup: new InlineKeyboard().text(
|
|
653
|
-
* "some",
|
|
654
|
-
* "callback-data"
|
|
655
|
-
* ),
|
|
656
|
-
* }
|
|
657
|
-
* ),
|
|
658
|
-
* ],
|
|
659
|
-
* {
|
|
660
|
-
* cache_time: 0,
|
|
661
|
-
* }
|
|
662
|
-
* );
|
|
663
|
-
* }
|
|
664
|
-
* },
|
|
665
|
-
* {
|
|
666
|
-
* onResult: (context) => context.editText("Message edited!"),
|
|
667
|
-
* }
|
|
668
|
-
* );
|
|
669
|
-
* ```
|
|
670
|
-
* */
|
|
671
|
-
inlineQuery(trigger, handler, options = {}) {
|
|
672
|
-
// @ts-expect-error fix later...
|
|
673
|
-
if (options.onResult)
|
|
674
|
-
this.chosenInlineResult(trigger, options.onResult);
|
|
675
|
-
return this.on("inline_query", (context, next) => {
|
|
676
|
-
if ((typeof trigger === "string" && context.query === trigger) ||
|
|
677
|
-
// @ts-expect-error
|
|
678
|
-
(typeof trigger === "function" && trigger(context)) ||
|
|
679
|
-
(trigger instanceof RegExp && trigger.test(context.query))) {
|
|
680
|
-
//@ts-expect-error
|
|
681
|
-
context.args =
|
|
682
|
-
trigger instanceof RegExp ? context.query?.match(trigger) : null;
|
|
683
|
-
// TODO: remove
|
|
684
|
-
//@ts-expect-error
|
|
685
|
-
return handler(context);
|
|
686
|
-
}
|
|
687
|
-
return next();
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
/**
|
|
691
|
-
* Register handler to `message` and `business_message` event
|
|
692
|
-
*
|
|
693
|
-
* new Bot().hears(/regular expression with (.*)/i, async (context) => {
|
|
694
|
-
* if (context.args) await context.send(`Params ${context.args[1]}`);
|
|
695
|
-
* });
|
|
696
|
-
*/
|
|
697
|
-
hears(trigger, handler) {
|
|
698
|
-
return this.on("message", (context, next) => {
|
|
699
|
-
const text = context.text ?? context.caption;
|
|
700
|
-
if ((typeof trigger === "string" && text === trigger) ||
|
|
701
|
-
// @ts-expect-error
|
|
702
|
-
(typeof trigger === "function" && trigger(context)) ||
|
|
703
|
-
(trigger instanceof RegExp && text && trigger.test(text))) {
|
|
704
|
-
//@ts-expect-error
|
|
705
|
-
context.args = trigger instanceof RegExp ? text?.match(trigger) : null;
|
|
706
|
-
// TODO: remove
|
|
707
|
-
//@ts-expect-error
|
|
708
|
-
return handler(context);
|
|
709
|
-
}
|
|
710
|
-
return next();
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
/**
|
|
714
|
-
* Register handler to `message` and `business_message` event when entities contains a command
|
|
715
|
-
*
|
|
716
|
-
* new Bot().command("start", async (context) => {
|
|
717
|
-
* return context.send(`You message is /start ${context.args}`);
|
|
718
|
-
* });
|
|
719
|
-
*/
|
|
720
|
-
command(command, handler, options) {
|
|
721
|
-
if (command.startsWith("/"))
|
|
722
|
-
throw new Error("Do not use / in command name");
|
|
723
|
-
return this.on(["message", "business_message"], (context, next) => {
|
|
724
|
-
// TODO: change to find
|
|
725
|
-
if (context.entities?.some((entity) => {
|
|
726
|
-
if (entity.type !== "bot_command" || entity.offset > 0)
|
|
727
|
-
return false;
|
|
728
|
-
const cmd = context.text
|
|
729
|
-
?.slice(1, entity.length)
|
|
730
|
-
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
731
|
-
?.replace(`@${this.info.username}`, "");
|
|
732
|
-
// @ts-expect-error
|
|
733
|
-
context.args = context.text?.slice(entity.length).trim() || null;
|
|
734
|
-
return cmd === command;
|
|
735
|
-
}))
|
|
736
|
-
// @ts-expect-error
|
|
737
|
-
return handler(context);
|
|
738
|
-
return next();
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
/** Currently not isolated!!! */
|
|
742
|
-
group(grouped) {
|
|
743
|
-
return grouped(this);
|
|
744
|
-
}
|
|
745
|
-
/**
|
|
746
|
-
* Init bot. Call it manually only if you doesn't use {@link Bot.start}
|
|
747
|
-
*/
|
|
748
|
-
async init() {
|
|
749
|
-
await Promise.all(this.lazyloadPlugins.map(async (plugin) => this.extend(await plugin)));
|
|
750
|
-
const info = await this.api.getMe({
|
|
751
|
-
suppress: true,
|
|
752
|
-
});
|
|
753
|
-
if (info instanceof errors_1.TelegramError) {
|
|
754
|
-
if (info.code === 404)
|
|
755
|
-
info.message = "The bot token is incorrect. Check it in BotFather.";
|
|
756
|
-
throw info;
|
|
757
|
-
}
|
|
758
|
-
this.info = info;
|
|
759
|
-
}
|
|
760
|
-
/**
|
|
761
|
-
* Start receive updates via long-polling or webhook
|
|
762
|
-
*
|
|
763
|
-
* @example
|
|
764
|
-
* ```ts
|
|
765
|
-
* import { Bot } from "gramio";
|
|
766
|
-
*
|
|
767
|
-
* const bot = new Bot("") // put you token here
|
|
768
|
-
* .command("start", (context) => context.send("Hi!"))
|
|
769
|
-
* .onStart(console.log);
|
|
770
|
-
*
|
|
771
|
-
* bot.start();
|
|
772
|
-
* ```
|
|
773
|
-
*/
|
|
774
|
-
async start({ webhook, dropPendingUpdates, allowedUpdates, } = {}) {
|
|
775
|
-
await this.init();
|
|
776
|
-
if (!webhook) {
|
|
777
|
-
await this.api.deleteWebhook({
|
|
778
|
-
drop_pending_updates: dropPendingUpdates,
|
|
779
|
-
});
|
|
780
|
-
await this.updates.startPolling({
|
|
781
|
-
allowed_updates: allowedUpdates,
|
|
782
|
-
});
|
|
783
|
-
this.runImmutableHooks("onStart", {
|
|
784
|
-
plugins: this.dependencies,
|
|
785
|
-
// biome-ignore lint/style/noNonNullAssertion: bot.init() guarantees this.info
|
|
786
|
-
info: this.info,
|
|
787
|
-
updatesFrom: "long-polling",
|
|
788
|
-
});
|
|
789
|
-
return this.info;
|
|
790
|
-
}
|
|
791
|
-
if (this.updates.isStarted)
|
|
792
|
-
this.updates.stopPolling();
|
|
793
|
-
await this.api.setWebhook({
|
|
794
|
-
...webhook,
|
|
795
|
-
drop_pending_updates: dropPendingUpdates,
|
|
796
|
-
allowed_updates: allowedUpdates,
|
|
797
|
-
});
|
|
798
|
-
this.runImmutableHooks("onStart", {
|
|
799
|
-
plugins: this.dependencies,
|
|
800
|
-
// biome-ignore lint/style/noNonNullAssertion: bot.init() guarantees this.info
|
|
801
|
-
info: this.info,
|
|
802
|
-
updatesFrom: "webhook",
|
|
803
|
-
});
|
|
804
|
-
return this.info;
|
|
805
|
-
}
|
|
806
|
-
/**
|
|
807
|
-
* Stops receiving events via long-polling or webhook
|
|
808
|
-
* Currently does not implement graceful shutdown
|
|
809
|
-
* */
|
|
810
|
-
async stop() {
|
|
811
|
-
if (this.updates.isStarted)
|
|
812
|
-
this.updates.stopPolling();
|
|
813
|
-
else
|
|
814
|
-
await this.api.deleteWebhook();
|
|
815
|
-
await this.runImmutableHooks("onStop", {
|
|
816
|
-
plugins: this.dependencies,
|
|
817
|
-
// biome-ignore lint/style/noNonNullAssertion: bot.init() guarantees this.info
|
|
818
|
-
info: this.info,
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
};
|
|
822
|
-
return Bot = _classThis;
|
|
823
|
-
})();
|
|
824
|
-
exports.Bot = Bot;
|