tgplus 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 +52 -0
- package/README.md +1512 -0
- package/dist/adapters.d.ts +46 -0
- package/dist/adapters.js +83 -0
- package/dist/adapters.js.map +1 -0
- package/dist/bot.d.ts +50 -0
- package/dist/bot.js +180 -0
- package/dist/bot.js.map +1 -0
- package/dist/client.d.ts +1139 -0
- package/dist/client.js +529 -0
- package/dist/client.js.map +1 -0
- package/dist/composer.d.ts +88 -0
- package/dist/composer.js +233 -0
- package/dist/composer.js.map +1 -0
- package/dist/context.d.ts +72 -0
- package/dist/context.js +149 -0
- package/dist/context.js.map +1 -0
- package/dist/decorators.d.ts +33 -0
- package/dist/decorators.js +39 -0
- package/dist/decorators.js.map +1 -0
- package/dist/filters.d.ts +19 -0
- package/dist/filters.js +81 -0
- package/dist/filters.js.map +1 -0
- package/dist/i18n.d.ts +30 -0
- package/dist/i18n.js +41 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/keyboard.d.ts +62 -0
- package/dist/keyboard.js +96 -0
- package/dist/keyboard.js.map +1 -0
- package/dist/rateLimit.d.ts +19 -0
- package/dist/rateLimit.js +32 -0
- package/dist/rateLimit.js.map +1 -0
- package/dist/richMessage.d.ts +111 -0
- package/dist/richMessage.js +221 -0
- package/dist/richMessage.js.map +1 -0
- package/dist/scenes.d.ts +57 -0
- package/dist/scenes.js +105 -0
- package/dist/scenes.js.map +1 -0
- package/dist/session-redis.d.ts +27 -0
- package/dist/session-redis.js +36 -0
- package/dist/session-redis.js.map +1 -0
- package/dist/session-sqlite.d.ts +29 -0
- package/dist/session-sqlite.js +34 -0
- package/dist/session-sqlite.js.map +1 -0
- package/dist/session.d.ts +30 -0
- package/dist/session.js +35 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +2485 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Context } from "./context";
|
|
2
|
+
import { Predicate } from "./composer";
|
|
3
|
+
export declare function mention(): Predicate<Context>;
|
|
4
|
+
export declare function hashtag(): Predicate<Context>;
|
|
5
|
+
export declare function cashtag(): Predicate<Context>;
|
|
6
|
+
export declare function url(): Predicate<Context>;
|
|
7
|
+
export declare function textLink(): Predicate<Context>;
|
|
8
|
+
export declare function textMention(): Predicate<Context>;
|
|
9
|
+
export declare function phone(): Predicate<Context>;
|
|
10
|
+
export declare function email(): Predicate<Context>;
|
|
11
|
+
export declare function botCommand(): Predicate<Context>;
|
|
12
|
+
export declare function spoiler(): Predicate<Context>;
|
|
13
|
+
export declare function customEmoji(): Predicate<Context>;
|
|
14
|
+
/**
|
|
15
|
+
* Matches message_reaction updates — optionally only a specific emoji being
|
|
16
|
+
* added. `reaction()` alone matches any reaction change; `reaction('👍')`
|
|
17
|
+
* matches only when 👍 appears in the new reaction set.
|
|
18
|
+
*/
|
|
19
|
+
export declare function reaction(emoji?: string): Predicate<Context>;
|
package/dist/filters.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mention = mention;
|
|
4
|
+
exports.hashtag = hashtag;
|
|
5
|
+
exports.cashtag = cashtag;
|
|
6
|
+
exports.url = url;
|
|
7
|
+
exports.textLink = textLink;
|
|
8
|
+
exports.textMention = textMention;
|
|
9
|
+
exports.phone = phone;
|
|
10
|
+
exports.email = email;
|
|
11
|
+
exports.botCommand = botCommand;
|
|
12
|
+
exports.spoiler = spoiler;
|
|
13
|
+
exports.customEmoji = customEmoji;
|
|
14
|
+
exports.reaction = reaction;
|
|
15
|
+
/**
|
|
16
|
+
* Composable predicates for common message-entity and reaction patterns,
|
|
17
|
+
* matching telegraf's `telegraf/filters` module. Use with `bot.on(filter())`
|
|
18
|
+
* (on() accepts a predicate directly) or `bot.filter(filter(), ...)`.
|
|
19
|
+
*
|
|
20
|
+
* import { mention, hashtag } from "tgplus";
|
|
21
|
+
* bot.on(mention(), (ctx) => ctx.reply("Someone got mentioned!"));
|
|
22
|
+
*
|
|
23
|
+
* Each filter maps to exactly one real Bot API entity type — mention() only
|
|
24
|
+
* matches "@username" mentions, textMention() only matches the separate
|
|
25
|
+
* "user without a username" mention type, url() only matches plain URL
|
|
26
|
+
* text, textLink() only matches markdown-style [label](url) links. They're
|
|
27
|
+
* deliberately not merged, since Telegram treats them as distinct entities.
|
|
28
|
+
*/
|
|
29
|
+
function hasEntityType(ctx, type) {
|
|
30
|
+
const entities = ctx.message?.entities ?? ctx.message?.caption_entities ?? [];
|
|
31
|
+
return entities.some((e) => e.type === type);
|
|
32
|
+
}
|
|
33
|
+
function mention() {
|
|
34
|
+
return (ctx) => hasEntityType(ctx, "mention");
|
|
35
|
+
}
|
|
36
|
+
function hashtag() {
|
|
37
|
+
return (ctx) => hasEntityType(ctx, "hashtag");
|
|
38
|
+
}
|
|
39
|
+
function cashtag() {
|
|
40
|
+
return (ctx) => hasEntityType(ctx, "cashtag");
|
|
41
|
+
}
|
|
42
|
+
function url() {
|
|
43
|
+
return (ctx) => hasEntityType(ctx, "url");
|
|
44
|
+
}
|
|
45
|
+
function textLink() {
|
|
46
|
+
return (ctx) => hasEntityType(ctx, "text_link");
|
|
47
|
+
}
|
|
48
|
+
function textMention() {
|
|
49
|
+
return (ctx) => hasEntityType(ctx, "text_mention");
|
|
50
|
+
}
|
|
51
|
+
function phone() {
|
|
52
|
+
return (ctx) => hasEntityType(ctx, "phone_number");
|
|
53
|
+
}
|
|
54
|
+
function email() {
|
|
55
|
+
return (ctx) => hasEntityType(ctx, "email");
|
|
56
|
+
}
|
|
57
|
+
function botCommand() {
|
|
58
|
+
return (ctx) => hasEntityType(ctx, "bot_command");
|
|
59
|
+
}
|
|
60
|
+
function spoiler() {
|
|
61
|
+
return (ctx) => hasEntityType(ctx, "spoiler");
|
|
62
|
+
}
|
|
63
|
+
function customEmoji() {
|
|
64
|
+
return (ctx) => hasEntityType(ctx, "custom_emoji");
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Matches message_reaction updates — optionally only a specific emoji being
|
|
68
|
+
* added. `reaction()` alone matches any reaction change; `reaction('👍')`
|
|
69
|
+
* matches only when 👍 appears in the new reaction set.
|
|
70
|
+
*/
|
|
71
|
+
function reaction(emoji) {
|
|
72
|
+
return (ctx) => {
|
|
73
|
+
const r = ctx.update.message_reaction;
|
|
74
|
+
if (!r)
|
|
75
|
+
return false;
|
|
76
|
+
if (!emoji)
|
|
77
|
+
return true;
|
|
78
|
+
return r.new_reaction.some((rt) => rt.type === "emoji" && rt.emoji === emoji);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.js","sourceRoot":"","sources":["../src/filters.ts"],"names":[],"mappings":";;AAwBA,0BAEC;AACD,0BAEC;AACD,0BAEC;AACD,kBAEC;AACD,4BAEC;AACD,kCAEC;AACD,sBAEC;AACD,sBAEC;AACD,gCAEC;AACD,0BAEC;AACD,kCAEC;AAOD,4BAOC;AAlED;;;;;;;;;;;;;GAaG;AAEH,SAAS,aAAa,CAAC,GAAY,EAAE,IAA6B;IAChE,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,EAAE,QAAQ,IAAI,GAAG,CAAC,OAAO,EAAE,gBAAgB,IAAI,EAAE,CAAC;IAC9E,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,SAAgB,OAAO;IACrB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC;AACD,SAAgB,OAAO;IACrB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC;AACD,SAAgB,OAAO;IACrB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC;AACD,SAAgB,GAAG;IACjB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC;AACD,SAAgB,QAAQ;IACtB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AAClD,CAAC;AACD,SAAgB,WAAW;IACzB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AACrD,CAAC;AACD,SAAgB,KAAK;IACnB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AACrD,CAAC;AACD,SAAgB,KAAK;IACnB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AACD,SAAgB,UAAU;IACxB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;AACpD,CAAC;AACD,SAAgB,OAAO;IACrB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC;AACD,SAAgB,WAAW;IACzB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AACrD,CAAC;AAED;;;;GAIG;AACH,SAAgB,QAAQ,CAAC,KAAc;IACrC,OAAO,CAAC,GAAG,EAAE,EAAE;QACb,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC;QACtC,IAAI,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QACrB,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,OAAO,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,OAAO,IAAI,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;IAChF,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Context } from "./context";
|
|
2
|
+
import { Middleware } from "./composer";
|
|
3
|
+
export type Dictionary = Record<string, string | ((...args: any[]) => string)>;
|
|
4
|
+
export type Locales = Record<string, Dictionary>;
|
|
5
|
+
export interface I18nOptions {
|
|
6
|
+
locales: Locales;
|
|
7
|
+
defaultLocale: string;
|
|
8
|
+
/** Defaults to reading ctx.from.language_code (what Telegram clients send). */
|
|
9
|
+
getLocale?: (ctx: Context) => string | undefined;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Attaches `ctx.t(key, ...args)`, translating using the user's Telegram
|
|
13
|
+
* `language_code` with a fallback to `defaultLocale`. Interpolation is up to
|
|
14
|
+
* you — a dictionary value can be a plain string or a function for
|
|
15
|
+
* pluralization/placeholders.
|
|
16
|
+
*
|
|
17
|
+
* const i18n = createI18n({
|
|
18
|
+
* defaultLocale: 'en',
|
|
19
|
+
* locales: {
|
|
20
|
+
* en: { greeting: (name) => `Hello, ${name}!` },
|
|
21
|
+
* fr: { greeting: (name) => `Bonjour, ${name}!` },
|
|
22
|
+
* },
|
|
23
|
+
* });
|
|
24
|
+
* bot.use(i18n.middleware());
|
|
25
|
+
* bot.command('start', (ctx) => ctx.reply(ctx.t('greeting', ctx.from?.first_name)));
|
|
26
|
+
*/
|
|
27
|
+
export declare function createI18n(opts: I18nOptions): {
|
|
28
|
+
translate: (locale: string | undefined, key: string, ...args: unknown[]) => string;
|
|
29
|
+
middleware(): Middleware<Context>;
|
|
30
|
+
};
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createI18n = createI18n;
|
|
4
|
+
/**
|
|
5
|
+
* Attaches `ctx.t(key, ...args)`, translating using the user's Telegram
|
|
6
|
+
* `language_code` with a fallback to `defaultLocale`. Interpolation is up to
|
|
7
|
+
* you — a dictionary value can be a plain string or a function for
|
|
8
|
+
* pluralization/placeholders.
|
|
9
|
+
*
|
|
10
|
+
* const i18n = createI18n({
|
|
11
|
+
* defaultLocale: 'en',
|
|
12
|
+
* locales: {
|
|
13
|
+
* en: { greeting: (name) => `Hello, ${name}!` },
|
|
14
|
+
* fr: { greeting: (name) => `Bonjour, ${name}!` },
|
|
15
|
+
* },
|
|
16
|
+
* });
|
|
17
|
+
* bot.use(i18n.middleware());
|
|
18
|
+
* bot.command('start', (ctx) => ctx.reply(ctx.t('greeting', ctx.from?.first_name)));
|
|
19
|
+
*/
|
|
20
|
+
function createI18n(opts) {
|
|
21
|
+
const getLocale = opts.getLocale ?? ((ctx) => ctx.from?.language_code);
|
|
22
|
+
function translate(locale, key, ...args) {
|
|
23
|
+
const dict = (locale && opts.locales[locale]) || opts.locales[opts.defaultLocale] || {};
|
|
24
|
+
const entry = dict[key];
|
|
25
|
+
if (entry === undefined)
|
|
26
|
+
return key; // missing translation — fail loud-ish but not throw
|
|
27
|
+
return typeof entry === "function" ? entry(...args) : entry;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
translate,
|
|
31
|
+
middleware() {
|
|
32
|
+
return (ctx, next) => {
|
|
33
|
+
const locale = getLocale(ctx);
|
|
34
|
+
ctx.locale = locale;
|
|
35
|
+
ctx.t = (key, ...args) => translate(locale, key, ...args);
|
|
36
|
+
return next();
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=i18n.js.map
|
package/dist/i18n.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":";;AA6BA,gCAqBC;AArCD;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,UAAU,CAAC,IAAiB;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAEhF,SAAS,SAAS,CAAC,MAA0B,EAAE,GAAW,EAAE,GAAG,IAAe;QAC5E,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;QACxF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC,CAAC,oDAAoD;QACzF,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9D,CAAC;IAED,OAAO;QACL,SAAS;QACT,UAAU;YACR,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;gBACnB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;gBAC7B,GAA0D,CAAC,MAAM,GAAG,MAAM,CAAC;gBAC3E,GAAoE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;gBAC5H,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { Bot, BotOptions } from "./bot";
|
|
2
|
+
export { Context } from "./context";
|
|
3
|
+
export { Composer, Router, Middleware, Predicate } from "./composer";
|
|
4
|
+
export { Api, Transport, TelegramApiError, ClientOptions } from "./client";
|
|
5
|
+
export { Keyboard, InlineKeyboardBuilder, ReplyKeyboardBuilder } from "./keyboard";
|
|
6
|
+
export { RichMessage, RichMarkdownBuilder, RichHtmlBuilder, RichBlocksBuilder } from "./richMessage";
|
|
7
|
+
export { BotController, Command, Hears, Action, On } from "./decorators";
|
|
8
|
+
export { session, SessionStore, MemorySessionStore, SessionOptions } from "./session";
|
|
9
|
+
export { RedisSessionStore, RedisLikeClient, RedisSessionStoreOptions } from "./session-redis";
|
|
10
|
+
export { SqliteSessionStore, SqliteLikeDatabase, SqliteSessionStoreOptions } from "./session-sqlite";
|
|
11
|
+
export { WizardScene, Stage, WizardContext, WizardState, SceneApi, SceneStep } from "./scenes";
|
|
12
|
+
export { rateLimit, RateLimitOptions } from "./rateLimit";
|
|
13
|
+
export { createI18n, I18nOptions, Dictionary, Locales } from "./i18n";
|
|
14
|
+
export { vercelWebhookHandler, lambdaWebhookHandler, cloudflareWebhookHandler } from "./adapters";
|
|
15
|
+
export { mention, hashtag, cashtag, url, textLink, textMention, phone, email, botCommand, spoiler, customEmoji, reaction } from "./filters";
|
|
16
|
+
export * as Types from "./types";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Types = exports.reaction = exports.customEmoji = exports.spoiler = exports.botCommand = exports.email = exports.phone = exports.textMention = exports.textLink = exports.url = exports.cashtag = exports.hashtag = exports.mention = exports.cloudflareWebhookHandler = exports.lambdaWebhookHandler = exports.vercelWebhookHandler = exports.createI18n = exports.rateLimit = exports.Stage = exports.WizardScene = exports.SqliteSessionStore = exports.RedisSessionStore = exports.MemorySessionStore = exports.session = exports.On = exports.Action = exports.Hears = exports.Command = exports.BotController = exports.RichBlocksBuilder = exports.RichHtmlBuilder = exports.RichMarkdownBuilder = exports.RichMessage = exports.ReplyKeyboardBuilder = exports.InlineKeyboardBuilder = exports.Keyboard = exports.TelegramApiError = exports.Transport = exports.Api = exports.Router = exports.Composer = exports.Context = exports.Bot = void 0;
|
|
37
|
+
var bot_1 = require("./bot");
|
|
38
|
+
Object.defineProperty(exports, "Bot", { enumerable: true, get: function () { return bot_1.Bot; } });
|
|
39
|
+
var context_1 = require("./context");
|
|
40
|
+
Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return context_1.Context; } });
|
|
41
|
+
var composer_1 = require("./composer");
|
|
42
|
+
Object.defineProperty(exports, "Composer", { enumerable: true, get: function () { return composer_1.Composer; } });
|
|
43
|
+
Object.defineProperty(exports, "Router", { enumerable: true, get: function () { return composer_1.Router; } });
|
|
44
|
+
var client_1 = require("./client");
|
|
45
|
+
Object.defineProperty(exports, "Api", { enumerable: true, get: function () { return client_1.Api; } });
|
|
46
|
+
Object.defineProperty(exports, "Transport", { enumerable: true, get: function () { return client_1.Transport; } });
|
|
47
|
+
Object.defineProperty(exports, "TelegramApiError", { enumerable: true, get: function () { return client_1.TelegramApiError; } });
|
|
48
|
+
var keyboard_1 = require("./keyboard");
|
|
49
|
+
Object.defineProperty(exports, "Keyboard", { enumerable: true, get: function () { return keyboard_1.Keyboard; } });
|
|
50
|
+
Object.defineProperty(exports, "InlineKeyboardBuilder", { enumerable: true, get: function () { return keyboard_1.InlineKeyboardBuilder; } });
|
|
51
|
+
Object.defineProperty(exports, "ReplyKeyboardBuilder", { enumerable: true, get: function () { return keyboard_1.ReplyKeyboardBuilder; } });
|
|
52
|
+
var richMessage_1 = require("./richMessage");
|
|
53
|
+
Object.defineProperty(exports, "RichMessage", { enumerable: true, get: function () { return richMessage_1.RichMessage; } });
|
|
54
|
+
Object.defineProperty(exports, "RichMarkdownBuilder", { enumerable: true, get: function () { return richMessage_1.RichMarkdownBuilder; } });
|
|
55
|
+
Object.defineProperty(exports, "RichHtmlBuilder", { enumerable: true, get: function () { return richMessage_1.RichHtmlBuilder; } });
|
|
56
|
+
Object.defineProperty(exports, "RichBlocksBuilder", { enumerable: true, get: function () { return richMessage_1.RichBlocksBuilder; } });
|
|
57
|
+
var decorators_1 = require("./decorators");
|
|
58
|
+
Object.defineProperty(exports, "BotController", { enumerable: true, get: function () { return decorators_1.BotController; } });
|
|
59
|
+
Object.defineProperty(exports, "Command", { enumerable: true, get: function () { return decorators_1.Command; } });
|
|
60
|
+
Object.defineProperty(exports, "Hears", { enumerable: true, get: function () { return decorators_1.Hears; } });
|
|
61
|
+
Object.defineProperty(exports, "Action", { enumerable: true, get: function () { return decorators_1.Action; } });
|
|
62
|
+
Object.defineProperty(exports, "On", { enumerable: true, get: function () { return decorators_1.On; } });
|
|
63
|
+
var session_1 = require("./session");
|
|
64
|
+
Object.defineProperty(exports, "session", { enumerable: true, get: function () { return session_1.session; } });
|
|
65
|
+
Object.defineProperty(exports, "MemorySessionStore", { enumerable: true, get: function () { return session_1.MemorySessionStore; } });
|
|
66
|
+
var session_redis_1 = require("./session-redis");
|
|
67
|
+
Object.defineProperty(exports, "RedisSessionStore", { enumerable: true, get: function () { return session_redis_1.RedisSessionStore; } });
|
|
68
|
+
var session_sqlite_1 = require("./session-sqlite");
|
|
69
|
+
Object.defineProperty(exports, "SqliteSessionStore", { enumerable: true, get: function () { return session_sqlite_1.SqliteSessionStore; } });
|
|
70
|
+
var scenes_1 = require("./scenes");
|
|
71
|
+
Object.defineProperty(exports, "WizardScene", { enumerable: true, get: function () { return scenes_1.WizardScene; } });
|
|
72
|
+
Object.defineProperty(exports, "Stage", { enumerable: true, get: function () { return scenes_1.Stage; } });
|
|
73
|
+
var rateLimit_1 = require("./rateLimit");
|
|
74
|
+
Object.defineProperty(exports, "rateLimit", { enumerable: true, get: function () { return rateLimit_1.rateLimit; } });
|
|
75
|
+
var i18n_1 = require("./i18n");
|
|
76
|
+
Object.defineProperty(exports, "createI18n", { enumerable: true, get: function () { return i18n_1.createI18n; } });
|
|
77
|
+
var adapters_1 = require("./adapters");
|
|
78
|
+
Object.defineProperty(exports, "vercelWebhookHandler", { enumerable: true, get: function () { return adapters_1.vercelWebhookHandler; } });
|
|
79
|
+
Object.defineProperty(exports, "lambdaWebhookHandler", { enumerable: true, get: function () { return adapters_1.lambdaWebhookHandler; } });
|
|
80
|
+
Object.defineProperty(exports, "cloudflareWebhookHandler", { enumerable: true, get: function () { return adapters_1.cloudflareWebhookHandler; } });
|
|
81
|
+
var filters_1 = require("./filters");
|
|
82
|
+
Object.defineProperty(exports, "mention", { enumerable: true, get: function () { return filters_1.mention; } });
|
|
83
|
+
Object.defineProperty(exports, "hashtag", { enumerable: true, get: function () { return filters_1.hashtag; } });
|
|
84
|
+
Object.defineProperty(exports, "cashtag", { enumerable: true, get: function () { return filters_1.cashtag; } });
|
|
85
|
+
Object.defineProperty(exports, "url", { enumerable: true, get: function () { return filters_1.url; } });
|
|
86
|
+
Object.defineProperty(exports, "textLink", { enumerable: true, get: function () { return filters_1.textLink; } });
|
|
87
|
+
Object.defineProperty(exports, "textMention", { enumerable: true, get: function () { return filters_1.textMention; } });
|
|
88
|
+
Object.defineProperty(exports, "phone", { enumerable: true, get: function () { return filters_1.phone; } });
|
|
89
|
+
Object.defineProperty(exports, "email", { enumerable: true, get: function () { return filters_1.email; } });
|
|
90
|
+
Object.defineProperty(exports, "botCommand", { enumerable: true, get: function () { return filters_1.botCommand; } });
|
|
91
|
+
Object.defineProperty(exports, "spoiler", { enumerable: true, get: function () { return filters_1.spoiler; } });
|
|
92
|
+
Object.defineProperty(exports, "customEmoji", { enumerable: true, get: function () { return filters_1.customEmoji; } });
|
|
93
|
+
Object.defineProperty(exports, "reaction", { enumerable: true, get: function () { return filters_1.reaction; } });
|
|
94
|
+
exports.Types = __importStar(require("./types"));
|
|
95
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6BAAwC;AAA/B,0FAAA,GAAG,OAAA;AACZ,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAChB,uCAAqE;AAA5D,oGAAA,QAAQ,OAAA;AAAE,kGAAA,MAAM,OAAA;AACzB,mCAA2E;AAAlE,6FAAA,GAAG,OAAA;AAAE,mGAAA,SAAS,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AACzC,uCAAmF;AAA1E,oGAAA,QAAQ,OAAA;AAAE,iHAAA,qBAAqB,OAAA;AAAE,gHAAA,oBAAoB,OAAA;AAC9D,6CAAqG;AAA5F,0GAAA,WAAW,OAAA;AAAE,kHAAA,mBAAmB,OAAA;AAAE,8GAAA,eAAe,OAAA;AAAE,gHAAA,iBAAiB,OAAA;AAC7E,2CAAyE;AAAhE,2GAAA,aAAa,OAAA;AAAE,qGAAA,OAAO,OAAA;AAAE,mGAAA,KAAK,OAAA;AAAE,oGAAA,MAAM,OAAA;AAAE,gGAAA,EAAE,OAAA;AAClD,qCAAsF;AAA7E,kGAAA,OAAO,OAAA;AAAgB,6GAAA,kBAAkB,OAAA;AAClD,iDAA+F;AAAtF,kHAAA,iBAAiB,OAAA;AAC1B,mDAAqG;AAA5F,oHAAA,kBAAkB,OAAA;AAC3B,mCAA+F;AAAtF,qGAAA,WAAW,OAAA;AAAE,+FAAA,KAAK,OAAA;AAC3B,yCAA0D;AAAjD,sGAAA,SAAS,OAAA;AAClB,+BAAsE;AAA7D,kGAAA,UAAU,OAAA;AACnB,uCAAkG;AAAzF,gHAAA,oBAAoB,OAAA;AAAE,gHAAA,oBAAoB,OAAA;AAAE,oHAAA,wBAAwB,OAAA;AAC7E,qCAA4I;AAAnI,kGAAA,OAAO,OAAA;AAAE,kGAAA,OAAO,OAAA;AAAE,kGAAA,OAAO,OAAA;AAAE,8FAAA,GAAG,OAAA;AAAE,mGAAA,QAAQ,OAAA;AAAE,sGAAA,WAAW,OAAA;AAAE,gGAAA,KAAK,OAAA;AAAE,gGAAA,KAAK,OAAA;AAAE,qGAAA,UAAU,OAAA;AAAE,kGAAA,OAAO,OAAA;AAAE,sGAAA,WAAW,OAAA;AAAE,mGAAA,QAAQ,OAAA;AACxH,iDAAiC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as T from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Fluent builders for keyboards. Chosen to read almost like English:
|
|
4
|
+
*
|
|
5
|
+
* Keyboard.inline()
|
|
6
|
+
* .button('Yes', 'confirm:yes')
|
|
7
|
+
* .button('No', 'confirm:no')
|
|
8
|
+
* .row()
|
|
9
|
+
* .url('Docs', 'https://example.com')
|
|
10
|
+
* .build()
|
|
11
|
+
*/
|
|
12
|
+
export declare class InlineKeyboardBuilder {
|
|
13
|
+
private rows;
|
|
14
|
+
button(text: string, callback_data: string, extra?: {
|
|
15
|
+
style?: "primary" | "success" | "danger";
|
|
16
|
+
icon_custom_emoji_id?: string;
|
|
17
|
+
}): this;
|
|
18
|
+
url(text: string, url: string, extra?: {
|
|
19
|
+
style?: "primary" | "success" | "danger";
|
|
20
|
+
icon_custom_emoji_id?: string;
|
|
21
|
+
}): this;
|
|
22
|
+
/** Alias for url() — a plausible guessed name given how other libraries phrase this, so it's accepted rather than throwing "not a function". */
|
|
23
|
+
urlButton(text: string, url: string, extra?: {
|
|
24
|
+
style?: "primary" | "success" | "danger";
|
|
25
|
+
icon_custom_emoji_id?: string;
|
|
26
|
+
}): this;
|
|
27
|
+
webApp(text: string, url: string): this;
|
|
28
|
+
switchInline(text: string, query?: string): this;
|
|
29
|
+
pay(text: string): this;
|
|
30
|
+
/** Copies text to the user's clipboard when tapped (Bot API 7.11+). */
|
|
31
|
+
copyText(text: string, textToCopy: string, extra?: {
|
|
32
|
+
style?: "primary" | "success" | "danger";
|
|
33
|
+
icon_custom_emoji_id?: string;
|
|
34
|
+
}): this;
|
|
35
|
+
/** Start a new row of buttons. */
|
|
36
|
+
row(): this;
|
|
37
|
+
private current;
|
|
38
|
+
build(): T.InlineKeyboardMarkup;
|
|
39
|
+
}
|
|
40
|
+
export declare class ReplyKeyboardBuilder {
|
|
41
|
+
private rows;
|
|
42
|
+
text(label: string, extra?: {
|
|
43
|
+
style?: "primary" | "success" | "danger";
|
|
44
|
+
icon_custom_emoji_id?: string;
|
|
45
|
+
}): this;
|
|
46
|
+
requestContact(label: string): this;
|
|
47
|
+
requestLocation(label: string): this;
|
|
48
|
+
row(): this;
|
|
49
|
+
private current;
|
|
50
|
+
build(opts?: {
|
|
51
|
+
resize?: boolean;
|
|
52
|
+
oneTime?: boolean;
|
|
53
|
+
placeholder?: string;
|
|
54
|
+
}): T.ReplyKeyboardMarkup;
|
|
55
|
+
}
|
|
56
|
+
/** Entry points, so usage reads as `Keyboard.inline()...` / `Keyboard.reply()...` / `Keyboard.remove()`. */
|
|
57
|
+
export declare const Keyboard: {
|
|
58
|
+
inline: () => InlineKeyboardBuilder;
|
|
59
|
+
reply: () => ReplyKeyboardBuilder;
|
|
60
|
+
remove: (selective?: boolean) => T.ReplyKeyboardRemove;
|
|
61
|
+
forceReply: (placeholder?: string) => T.ForceReply;
|
|
62
|
+
};
|
package/dist/keyboard.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Keyboard = exports.ReplyKeyboardBuilder = exports.InlineKeyboardBuilder = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Fluent builders for keyboards. Chosen to read almost like English:
|
|
6
|
+
*
|
|
7
|
+
* Keyboard.inline()
|
|
8
|
+
* .button('Yes', 'confirm:yes')
|
|
9
|
+
* .button('No', 'confirm:no')
|
|
10
|
+
* .row()
|
|
11
|
+
* .url('Docs', 'https://example.com')
|
|
12
|
+
* .build()
|
|
13
|
+
*/
|
|
14
|
+
class InlineKeyboardBuilder {
|
|
15
|
+
rows = [[]];
|
|
16
|
+
button(text, callback_data, extra = {}) {
|
|
17
|
+
this.current().push({ text, callback_data, ...extra });
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
url(text, url, extra = {}) {
|
|
21
|
+
this.current().push({ text, url, ...extra });
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
/** Alias for url() — a plausible guessed name given how other libraries phrase this, so it's accepted rather than throwing "not a function". */
|
|
25
|
+
urlButton(text, url, extra = {}) {
|
|
26
|
+
return this.url(text, url, extra);
|
|
27
|
+
}
|
|
28
|
+
webApp(text, url) {
|
|
29
|
+
this.current().push({ text, web_app: { url } });
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
switchInline(text, query = "") {
|
|
33
|
+
this.current().push({ text, switch_inline_query: query });
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
pay(text) {
|
|
37
|
+
this.current().push({ text, pay: true });
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
/** Copies text to the user's clipboard when tapped (Bot API 7.11+). */
|
|
41
|
+
copyText(text, textToCopy, extra = {}) {
|
|
42
|
+
this.current().push({ text, copy_text: { text: textToCopy }, ...extra });
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
/** Start a new row of buttons. */
|
|
46
|
+
row() {
|
|
47
|
+
this.rows.push([]);
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
current() {
|
|
51
|
+
return this.rows[this.rows.length - 1];
|
|
52
|
+
}
|
|
53
|
+
build() {
|
|
54
|
+
return { inline_keyboard: this.rows.filter((r) => r.length) };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.InlineKeyboardBuilder = InlineKeyboardBuilder;
|
|
58
|
+
class ReplyKeyboardBuilder {
|
|
59
|
+
rows = [[]];
|
|
60
|
+
text(label, extra = {}) {
|
|
61
|
+
this.current().push({ text: label, ...extra });
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
requestContact(label) {
|
|
65
|
+
this.current().push({ text: label, request_contact: true });
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
requestLocation(label) {
|
|
69
|
+
this.current().push({ text: label, request_location: true });
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
row() {
|
|
73
|
+
this.rows.push([]);
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
current() {
|
|
77
|
+
return this.rows[this.rows.length - 1];
|
|
78
|
+
}
|
|
79
|
+
build(opts = {}) {
|
|
80
|
+
return {
|
|
81
|
+
keyboard: this.rows.filter((r) => r.length),
|
|
82
|
+
resize_keyboard: opts.resize ?? true,
|
|
83
|
+
one_time_keyboard: opts.oneTime,
|
|
84
|
+
input_field_placeholder: opts.placeholder,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.ReplyKeyboardBuilder = ReplyKeyboardBuilder;
|
|
89
|
+
/** Entry points, so usage reads as `Keyboard.inline()...` / `Keyboard.reply()...` / `Keyboard.remove()`. */
|
|
90
|
+
exports.Keyboard = {
|
|
91
|
+
inline: () => new InlineKeyboardBuilder(),
|
|
92
|
+
reply: () => new ReplyKeyboardBuilder(),
|
|
93
|
+
remove: (selective = false) => ({ remove_keyboard: true, selective }),
|
|
94
|
+
forceReply: (placeholder) => ({ force_reply: true, input_field_placeholder: placeholder }),
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=keyboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard.js","sourceRoot":"","sources":["../src/keyboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Context } from "./context";
|
|
2
|
+
import { Middleware } from "./composer";
|
|
3
|
+
export interface RateLimitOptions {
|
|
4
|
+
/** Time window in ms. Default 3000 (3s). */
|
|
5
|
+
windowMs?: number;
|
|
6
|
+
/** Max updates allowed per window per key. Default 1. */
|
|
7
|
+
limit?: number;
|
|
8
|
+
/** Defaults to limiting per chat. Use `ctx => String(ctx.from?.id)` to limit per user instead. */
|
|
9
|
+
keyFn?: (ctx: Context) => string | undefined;
|
|
10
|
+
/** Called instead of silently dropping the update when the limit is hit. Defaults to doing nothing. */
|
|
11
|
+
onLimitExceeded?: (ctx: Context) => unknown | Promise<unknown>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Simple sliding-window rate limiter. Mount it early with `bot.use(rateLimit())`
|
|
15
|
+
* so spammy updates never even reach your command/hears/action handlers.
|
|
16
|
+
*
|
|
17
|
+
* bot.use(rateLimit({ windowMs: 2000, limit: 1, onLimitExceeded: (ctx) => ctx.reply('Slow down!') }));
|
|
18
|
+
*/
|
|
19
|
+
export declare function rateLimit(opts?: RateLimitOptions): Middleware<Context>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rateLimit = rateLimit;
|
|
4
|
+
/**
|
|
5
|
+
* Simple sliding-window rate limiter. Mount it early with `bot.use(rateLimit())`
|
|
6
|
+
* so spammy updates never even reach your command/hears/action handlers.
|
|
7
|
+
*
|
|
8
|
+
* bot.use(rateLimit({ windowMs: 2000, limit: 1, onLimitExceeded: (ctx) => ctx.reply('Slow down!') }));
|
|
9
|
+
*/
|
|
10
|
+
function rateLimit(opts = {}) {
|
|
11
|
+
const windowMs = opts.windowMs ?? 3000;
|
|
12
|
+
const limit = opts.limit ?? 1;
|
|
13
|
+
const keyFn = opts.keyFn ?? ((ctx) => (ctx.chat ? String(ctx.chat.id) : undefined));
|
|
14
|
+
const hits = new Map();
|
|
15
|
+
return async (ctx, next) => {
|
|
16
|
+
const key = keyFn(ctx);
|
|
17
|
+
if (key === undefined)
|
|
18
|
+
return next();
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
const timestamps = (hits.get(key) ?? []).filter((t) => now - t < windowMs);
|
|
21
|
+
if (timestamps.length >= limit) {
|
|
22
|
+
hits.set(key, timestamps);
|
|
23
|
+
if (opts.onLimitExceeded)
|
|
24
|
+
await opts.onLimitExceeded(ctx);
|
|
25
|
+
return; // drop — don't call next()
|
|
26
|
+
}
|
|
27
|
+
timestamps.push(now);
|
|
28
|
+
hits.set(key, timestamps);
|
|
29
|
+
return next();
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=rateLimit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.js","sourceRoot":"","sources":["../src/rateLimit.ts"],"names":[],"mappings":";;AAoBA,8BAuBC;AA7BD;;;;;GAKG;AACH,SAAgB,SAAS,CAAC,OAAyB,EAAE;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC7F,MAAM,IAAI,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,IAAI,EAAE,CAAC;QAErC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;QAE3E,IAAI,UAAU,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;YAC/B,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;YAC1B,IAAI,IAAI,CAAC,eAAe;gBAAE,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAC1D,OAAO,CAAC,2BAA2B;QACrC,CAAC;QAED,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAC1B,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as T from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Two ways to build a Rich Message (Bot API 10.1, block API added 10.2):
|
|
4
|
+
*
|
|
5
|
+
* 1. `RichMessage.markdown()` / `.html()` — write "Rich Markdown"/"Rich HTML"
|
|
6
|
+
* text (GFM-flavored markdown: **bold**, ==marked==, ||spoiler||, `- [ ]`
|
|
7
|
+
* task items, GFM tables, etc. — see the official docs for the full
|
|
8
|
+
* syntax). Simplest for AI-generated or hand-written content. Inline
|
|
9
|
+
* photos here (`.photo()`) use Rich Markdown's own `` image
|
|
10
|
+
* syntax directly in the text — confirmed working against a real server.
|
|
11
|
+
* 2. `RichMessage.blocks()` — build the structured block tree directly
|
|
12
|
+
* (Bot API 10.2+), for when you want guaranteed structure (e.g. a table
|
|
13
|
+
* with real colspan/rowspan) rather than round-tripping through text.
|
|
14
|
+
* Media blocks (photo/video/audio/animation/voice_note) reference a
|
|
15
|
+
* separately-declared media item by id — confirmed via two live 400
|
|
16
|
+
* errors that Telegram rejects both a missing `id` on the media item and
|
|
17
|
+
* an inline file where it expects an `{ id }` reference. Use `.photo()`/
|
|
18
|
+
* `.video()`/etc. here (not the markdown builder's `.photo()`) and the id
|
|
19
|
+
* bookkeeping is handled for you.
|
|
20
|
+
*
|
|
21
|
+
* Both produce an `InputRichMessage` for `ctx.replyRich()` / `api.sendRichMessage()`.
|
|
22
|
+
*/
|
|
23
|
+
export declare class RichMarkdownBuilder {
|
|
24
|
+
private parts;
|
|
25
|
+
text(str: string): this;
|
|
26
|
+
heading(str: string, level?: 1 | 2 | 3 | 4 | 5 | 6): this;
|
|
27
|
+
blockquote(str: string): this;
|
|
28
|
+
checklist(items: (string | {
|
|
29
|
+
label: string;
|
|
30
|
+
done?: boolean;
|
|
31
|
+
})[]): this;
|
|
32
|
+
list(items: string[], ordered?: boolean): this;
|
|
33
|
+
table(headers: string[], rows: string[][]): this;
|
|
34
|
+
codeBlock(code: string, language?: string): this;
|
|
35
|
+
divider(): this;
|
|
36
|
+
/**
|
|
37
|
+
* Embeds a photo inline via Rich Markdown's own ``
|
|
38
|
+
* image syntax. This does NOT use InputRichMessage.media — that field is
|
|
39
|
+
* only for RichMessage.blocks()'s structured media blocks, and is a
|
|
40
|
+
* separate mechanism. This method's output is the confirmed-working path.
|
|
41
|
+
*/
|
|
42
|
+
photo(url: string, caption?: string): this;
|
|
43
|
+
build(): T.InputRichMessage;
|
|
44
|
+
}
|
|
45
|
+
export declare class RichHtmlBuilder {
|
|
46
|
+
private parts;
|
|
47
|
+
raw(html: string): this;
|
|
48
|
+
paragraph(html: string): this;
|
|
49
|
+
heading(html: string, level?: 1 | 2 | 3 | 4 | 5 | 6): this;
|
|
50
|
+
build(): T.InputRichMessage;
|
|
51
|
+
}
|
|
52
|
+
/** Structural block-based builder (Bot API 10.2+) — produces InputRichBlock[] directly. */
|
|
53
|
+
export declare class RichBlocksBuilder {
|
|
54
|
+
private blocks;
|
|
55
|
+
private mediaItems;
|
|
56
|
+
private mediaCounter;
|
|
57
|
+
/**
|
|
58
|
+
* Declares a media item, returning its id. Prefer the .photo()/.video()/
|
|
59
|
+
* .audio()/.animation()/.voiceNote() convenience methods below, which call
|
|
60
|
+
* this for you and add the referencing block in one step — use this
|
|
61
|
+
* directly only if you're building a raw block yourself via .raw().
|
|
62
|
+
*/
|
|
63
|
+
media(type: T.InputRichMessageMedia["type"], file: T.InputFile): string;
|
|
64
|
+
paragraph(text: T.RichText): this;
|
|
65
|
+
heading(text: T.RichText, size?: 1 | 2 | 3 | 4 | 5 | 6): this;
|
|
66
|
+
divider(): this;
|
|
67
|
+
table(cells: T.RichBlockTableCell[][], opts?: {
|
|
68
|
+
bordered?: boolean;
|
|
69
|
+
striped?: boolean;
|
|
70
|
+
caption?: T.RichText;
|
|
71
|
+
}): this;
|
|
72
|
+
list(items: T.RichBlockListItem[]): this;
|
|
73
|
+
details(summary: T.RichText, blocks: T.InputRichBlock[], open?: boolean): this;
|
|
74
|
+
/** Adds a photo block, declaring its media item for you. */
|
|
75
|
+
photo(file: T.InputFile, opts?: {
|
|
76
|
+
hasSpoiler?: boolean;
|
|
77
|
+
caption?: T.RichBlockCaption;
|
|
78
|
+
}): this;
|
|
79
|
+
video(file: T.InputFile, opts?: {
|
|
80
|
+
hasSpoiler?: boolean;
|
|
81
|
+
caption?: T.RichBlockCaption;
|
|
82
|
+
}): this;
|
|
83
|
+
audio(file: T.InputFile, opts?: {
|
|
84
|
+
caption?: T.RichBlockCaption;
|
|
85
|
+
}): this;
|
|
86
|
+
animation(file: T.InputFile, opts?: {
|
|
87
|
+
hasSpoiler?: boolean;
|
|
88
|
+
caption?: T.RichBlockCaption;
|
|
89
|
+
}): this;
|
|
90
|
+
voiceNote(file: T.InputFile, opts?: {
|
|
91
|
+
caption?: T.RichBlockCaption;
|
|
92
|
+
}): this;
|
|
93
|
+
/** Bot API 10.3+: adds a document (file) block. */
|
|
94
|
+
document(file: T.InputFile, opts?: {
|
|
95
|
+
caption?: T.RichBlockCaption;
|
|
96
|
+
}): this;
|
|
97
|
+
/** Bot API 10.3+: adds a row of buttons to the rich message. */
|
|
98
|
+
buttons(buttons: T.RichMessageButton[]): this;
|
|
99
|
+
/** Bot API 10.3+: adds an expandable/collapsible block quotation. */
|
|
100
|
+
expandableBlockquote(blocks: T.InputRichBlock[], opts?: {
|
|
101
|
+
credit?: T.RichText;
|
|
102
|
+
}): this;
|
|
103
|
+
/** Escape hatch for block types without a dedicated method. If it references media by id, declare that media via .media() first, or build() will throw before you ever hit Telegram's 400. */
|
|
104
|
+
raw(block: T.InputRichBlock): this;
|
|
105
|
+
build(): T.InputRichMessage;
|
|
106
|
+
}
|
|
107
|
+
export declare const RichMessage: {
|
|
108
|
+
markdown: () => RichMarkdownBuilder;
|
|
109
|
+
html: () => RichHtmlBuilder;
|
|
110
|
+
blocks: () => RichBlocksBuilder;
|
|
111
|
+
};
|