@effect-ak/tg-bot 1.1.0 → 1.2.1
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/dist/index.cjs +154 -6
- package/dist/index.d.ts +43 -7
- package/dist/index.js +152 -6
- package/package.json +5 -4
- package/readme.md +127 -120
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,8 @@ __export(index_exports, {
|
|
|
28
28
|
BotTgClientTag: () => BotTgClientTag,
|
|
29
29
|
BotUpdateHandlersTag: () => BotUpdateHandlersTag,
|
|
30
30
|
HandleUpdateError: () => HandleUpdateError,
|
|
31
|
+
createBotContext: () => createBotContext,
|
|
32
|
+
createWebhookHandler: () => createWebhookHandler,
|
|
31
33
|
defineBot: () => defineBot,
|
|
32
34
|
extractUpdate: () => extractUpdate,
|
|
33
35
|
handleEntireBatch: () => handleEntireBatch,
|
|
@@ -2656,6 +2658,26 @@ var BotResponse = class _BotResponse extends TaggedClass("BotResponse") {
|
|
|
2656
2658
|
static ignore = new _BotResponse({});
|
|
2657
2659
|
};
|
|
2658
2660
|
|
|
2661
|
+
// src/internal/bot-context.ts
|
|
2662
|
+
var extractCommand = (update) => {
|
|
2663
|
+
if (typeof update !== "object" || update === null) return void 0;
|
|
2664
|
+
const u = update;
|
|
2665
|
+
if (!u.entities || !u.text) return void 0;
|
|
2666
|
+
const entity = u.entities.find((e) => e.type === "bot_command");
|
|
2667
|
+
if (!entity) return void 0;
|
|
2668
|
+
return u.text.slice(entity.offset, entity.offset + entity.length);
|
|
2669
|
+
};
|
|
2670
|
+
var createBotContext = (update) => {
|
|
2671
|
+
const command = extractCommand(update);
|
|
2672
|
+
return {
|
|
2673
|
+
command,
|
|
2674
|
+
reply: (text, options) => BotResponse.make({ type: "message", text, ...options }),
|
|
2675
|
+
replyWithDocument: (document, options) => BotResponse.make({ type: "document", document, ...options }),
|
|
2676
|
+
replyWithPhoto: (photo, options) => BotResponse.make({ type: "photo", photo, ...options }),
|
|
2677
|
+
ignore: BotResponse.ignore
|
|
2678
|
+
};
|
|
2679
|
+
};
|
|
2680
|
+
|
|
2659
2681
|
// ../../node_modules/.pnpm/effect@3.12.0/node_modules/effect/dist/esm/Effectable.js
|
|
2660
2682
|
var EffectPrototype2 = EffectPrototype;
|
|
2661
2683
|
|
|
@@ -3547,6 +3569,36 @@ var BotPollSettingsTag = class extends Reference2()(
|
|
|
3547
3569
|
};
|
|
3548
3570
|
|
|
3549
3571
|
// src/internal/handle-update.ts
|
|
3572
|
+
var isGuardedHandler = (handler) => typeof handler === "object" && handler !== null && "handle" in handler;
|
|
3573
|
+
var executeSingleGuard = async (guard, update, ctx) => {
|
|
3574
|
+
const input = { update, ctx };
|
|
3575
|
+
if (guard.match) {
|
|
3576
|
+
const matched = await guard.match(input);
|
|
3577
|
+
if (!matched) return null;
|
|
3578
|
+
}
|
|
3579
|
+
return await guard.handle(input);
|
|
3580
|
+
};
|
|
3581
|
+
var executeGuards = async (guards, update, ctx) => {
|
|
3582
|
+
for (const guard of guards) {
|
|
3583
|
+
const result = await executeSingleGuard(guard, update, ctx);
|
|
3584
|
+
if (result !== null) return result;
|
|
3585
|
+
}
|
|
3586
|
+
return BotResponse.ignore;
|
|
3587
|
+
};
|
|
3588
|
+
var executeHandler = (handler, update, ctx) => {
|
|
3589
|
+
if (typeof handler === "function") {
|
|
3590
|
+
return handler(update);
|
|
3591
|
+
}
|
|
3592
|
+
if (Array.isArray(handler)) {
|
|
3593
|
+
return executeGuards(handler, update, ctx);
|
|
3594
|
+
}
|
|
3595
|
+
if (isGuardedHandler(handler)) {
|
|
3596
|
+
return executeSingleGuard(handler, update, ctx).then(
|
|
3597
|
+
(r) => r ?? BotResponse.ignore
|
|
3598
|
+
);
|
|
3599
|
+
}
|
|
3600
|
+
return BotResponse.ignore;
|
|
3601
|
+
};
|
|
3550
3602
|
var extractUpdate = (input) => {
|
|
3551
3603
|
for (const [field, value] of Object.entries(input)) {
|
|
3552
3604
|
if (field == "update_id") {
|
|
@@ -3650,8 +3702,8 @@ var handleOneUpdate = (updateObject, handlers) => gen(function* () {
|
|
|
3650
3702
|
})
|
|
3651
3703
|
);
|
|
3652
3704
|
}
|
|
3653
|
-
const
|
|
3654
|
-
if (!
|
|
3705
|
+
const handler = handlers[`on_${update.type}`];
|
|
3706
|
+
if (!handler) {
|
|
3655
3707
|
return yield* fail3(
|
|
3656
3708
|
new HandleUpdateError({
|
|
3657
3709
|
name: "HandlerNotDefined",
|
|
@@ -3666,9 +3718,10 @@ var handleOneUpdate = (updateObject, handlers) => gen(function* () {
|
|
|
3666
3718
|
message: `${update.text.slice(0, 5)}...`
|
|
3667
3719
|
});
|
|
3668
3720
|
}
|
|
3721
|
+
const ctx = createBotContext(update);
|
|
3669
3722
|
let handleUpdateError;
|
|
3670
3723
|
const handleResult = yield* try_({
|
|
3671
|
-
try: () =>
|
|
3724
|
+
try: () => executeHandler(handler, update, ctx),
|
|
3672
3725
|
catch: (error) => new HandleUpdateError({
|
|
3673
3726
|
name: "BotHandlerError",
|
|
3674
3727
|
update: updateObject,
|
|
@@ -3871,20 +3924,28 @@ var _runBotDaemon = (state) => gen(function* () {
|
|
|
3871
3924
|
|
|
3872
3925
|
// src/internal/launch.ts
|
|
3873
3926
|
var import_tg_bot_client2 = require("@effect-ak/tg-bot-client");
|
|
3927
|
+
var extractMode = (input) => {
|
|
3928
|
+
if (input.mode === "batch") {
|
|
3929
|
+
return { type: "batch", on_batch: input.on_batch };
|
|
3930
|
+
}
|
|
3931
|
+
const { bot_token, mode, poll, ...handlers } = input;
|
|
3932
|
+
return { type: "single", ...handlers };
|
|
3933
|
+
};
|
|
3874
3934
|
var launchBot = (input) => gen(function* () {
|
|
3875
3935
|
const service2 = yield* service(BotRunService);
|
|
3876
3936
|
const client = (0, import_tg_bot_client2.makeTgBotClient)({ bot_token: input.bot_token });
|
|
3877
3937
|
const contextWithClient = make4(BotTgClientTag, client);
|
|
3938
|
+
const mode = extractMode(input);
|
|
3878
3939
|
yield* service2.runBotInBackground.pipe(
|
|
3879
|
-
provideService(BotUpdateHandlersTag,
|
|
3940
|
+
provideService(BotUpdateHandlersTag, mode),
|
|
3880
3941
|
provideService(
|
|
3881
3942
|
BotPollSettingsTag,
|
|
3882
3943
|
BotPollSettings.make(input.poll ?? {})
|
|
3883
3944
|
),
|
|
3884
3945
|
provideContext(contextWithClient)
|
|
3885
3946
|
);
|
|
3886
|
-
const reload = (
|
|
3887
|
-
provideService(BotUpdateHandlersTag,
|
|
3947
|
+
const reload = (mode2) => service2.runBotInBackground.pipe(
|
|
3948
|
+
provideService(BotUpdateHandlersTag, mode2),
|
|
3888
3949
|
provideContext(contextWithClient),
|
|
3889
3950
|
runPromise
|
|
3890
3951
|
);
|
|
@@ -3901,6 +3962,91 @@ var defineBot = (input) => {
|
|
|
3901
3962
|
console.warn("No handlers are defined for bot");
|
|
3902
3963
|
return input;
|
|
3903
3964
|
};
|
|
3965
|
+
|
|
3966
|
+
// src/webhook.ts
|
|
3967
|
+
var import_tg_bot_client3 = require("@effect-ak/tg-bot-client");
|
|
3968
|
+
var isGuardedHandler2 = (handler) => typeof handler === "object" && handler !== null && "handle" in handler;
|
|
3969
|
+
var executeSingleGuard2 = async (guard, update, ctx) => {
|
|
3970
|
+
const input = { update, ctx };
|
|
3971
|
+
if (guard.match) {
|
|
3972
|
+
const matched = await guard.match(input);
|
|
3973
|
+
if (!matched) return null;
|
|
3974
|
+
}
|
|
3975
|
+
return await guard.handle(input);
|
|
3976
|
+
};
|
|
3977
|
+
var executeGuards2 = async (guards, update, ctx) => {
|
|
3978
|
+
for (const guard of guards) {
|
|
3979
|
+
const result = await executeSingleGuard2(guard, update, ctx);
|
|
3980
|
+
if (result !== null) return result;
|
|
3981
|
+
}
|
|
3982
|
+
return BotResponse.ignore;
|
|
3983
|
+
};
|
|
3984
|
+
var executeHandler2 = async (handler, update, ctx) => {
|
|
3985
|
+
if (typeof handler === "function") {
|
|
3986
|
+
return await handler(update);
|
|
3987
|
+
}
|
|
3988
|
+
if (Array.isArray(handler)) {
|
|
3989
|
+
return await executeGuards2(handler, update, ctx);
|
|
3990
|
+
}
|
|
3991
|
+
if (isGuardedHandler2(handler)) {
|
|
3992
|
+
const result = await executeSingleGuard2(handler, update, ctx);
|
|
3993
|
+
return result ?? BotResponse.ignore;
|
|
3994
|
+
}
|
|
3995
|
+
return BotResponse.ignore;
|
|
3996
|
+
};
|
|
3997
|
+
var extractUpdate2 = (input) => {
|
|
3998
|
+
for (const [field, value] of Object.entries(input)) {
|
|
3999
|
+
if (field === "update_id") continue;
|
|
4000
|
+
return { type: field, ...value };
|
|
4001
|
+
}
|
|
4002
|
+
return void 0;
|
|
4003
|
+
};
|
|
4004
|
+
var processUpdate = async (updateObject, handlers, client) => {
|
|
4005
|
+
const update = extractUpdate2(updateObject);
|
|
4006
|
+
if (!update) {
|
|
4007
|
+
console.warn("Unknown update format", updateObject);
|
|
4008
|
+
return;
|
|
4009
|
+
}
|
|
4010
|
+
const handlerKey = `on_${update.type}`;
|
|
4011
|
+
const handler = handlers[handlerKey];
|
|
4012
|
+
if (!handler) {
|
|
4013
|
+
return;
|
|
4014
|
+
}
|
|
4015
|
+
const ctx = createBotContext(update);
|
|
4016
|
+
try {
|
|
4017
|
+
const result = await executeHandler2(handler, update, ctx);
|
|
4018
|
+
if (result.response && "chat" in update) {
|
|
4019
|
+
const responsePayload = result.response;
|
|
4020
|
+
await client.execute(`send_${responsePayload.type}`, {
|
|
4021
|
+
...responsePayload,
|
|
4022
|
+
chat_id: update.chat.id
|
|
4023
|
+
});
|
|
4024
|
+
}
|
|
4025
|
+
} catch (error) {
|
|
4026
|
+
console.error("Error handling update", {
|
|
4027
|
+
updateId: updateObject.update_id,
|
|
4028
|
+
error: error instanceof Error ? error.message : error
|
|
4029
|
+
});
|
|
4030
|
+
}
|
|
4031
|
+
};
|
|
4032
|
+
var createWebhookHandler = (config) => {
|
|
4033
|
+
const client = (0, import_tg_bot_client3.makeTgBotClient)({ bot_token: config.bot_token });
|
|
4034
|
+
const handleUpdate = async (update) => {
|
|
4035
|
+
await processUpdate(update, config, client);
|
|
4036
|
+
};
|
|
4037
|
+
const handler = async (request) => {
|
|
4038
|
+
try {
|
|
4039
|
+
const update = await request.json();
|
|
4040
|
+
await handleUpdate(update);
|
|
4041
|
+
return new Response("ok", { status: 200 });
|
|
4042
|
+
} catch (error) {
|
|
4043
|
+
console.error("Webhook error", error);
|
|
4044
|
+
return new Response("error", { status: 500 });
|
|
4045
|
+
}
|
|
4046
|
+
};
|
|
4047
|
+
handler.handleUpdate = handleUpdate;
|
|
4048
|
+
return handler;
|
|
4049
|
+
};
|
|
3904
4050
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3905
4051
|
0 && (module.exports = {
|
|
3906
4052
|
BatchUpdateResult,
|
|
@@ -3911,6 +4057,8 @@ var defineBot = (input) => {
|
|
|
3911
4057
|
BotTgClientTag,
|
|
3912
4058
|
BotUpdateHandlersTag,
|
|
3913
4059
|
HandleUpdateError,
|
|
4060
|
+
createBotContext,
|
|
4061
|
+
createWebhookHandler,
|
|
3914
4062
|
defineBot,
|
|
3915
4063
|
extractUpdate,
|
|
3916
4064
|
handleEntireBatch,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as effect_Types from 'effect/Types';
|
|
2
2
|
import { Api, Update } from '@effect-ak/tg-bot-api';
|
|
3
|
-
import * as effect_Cause from 'effect/Cause';
|
|
4
|
-
import * as Micro from 'effect/Micro';
|
|
5
|
-
import * as Data from 'effect/Data';
|
|
6
3
|
import * as Context from 'effect/Context';
|
|
4
|
+
import * as Data from 'effect/Data';
|
|
7
5
|
import { TgBotClient } from '@effect-ak/tg-bot-client';
|
|
6
|
+
import * as effect_Cause from 'effect/Cause';
|
|
7
|
+
import * as Micro from 'effect/Micro';
|
|
8
8
|
|
|
9
9
|
type BotResult = {
|
|
10
10
|
[K in keyof Api]: K extends `send_${infer R}` ? {
|
|
@@ -41,9 +41,15 @@ declare const BotPollSettingsTag_base: Context.ReferenceClass<BotPollSettings, "
|
|
|
41
41
|
declare class BotPollSettingsTag extends BotPollSettingsTag_base {
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
type RunBotInput = RunBotInputSingle | RunBotInputBatch;
|
|
45
|
+
interface RunBotInputSingle extends BotUpdatesHandlers {
|
|
46
|
+
bot_token: string;
|
|
47
|
+
mode: "single";
|
|
48
|
+
poll?: Partial<PollSettings>;
|
|
49
|
+
}
|
|
50
|
+
interface RunBotInputBatch extends HandleBatchUpdateFunction {
|
|
45
51
|
bot_token: string;
|
|
46
|
-
mode:
|
|
52
|
+
mode: "batch";
|
|
47
53
|
poll?: Partial<PollSettings>;
|
|
48
54
|
}
|
|
49
55
|
type ExtractedUpdate<K extends AvailableUpdateTypes> = {
|
|
@@ -51,8 +57,27 @@ type ExtractedUpdate<K extends AvailableUpdateTypes> = {
|
|
|
51
57
|
} & Update[K];
|
|
52
58
|
type AvailableUpdateTypes = Exclude<keyof Update, "update_id">;
|
|
53
59
|
type HandleUpdateFunction<U> = (update: U) => BotResponse | PromiseLike<BotResponse>;
|
|
60
|
+
interface BotContext {
|
|
61
|
+
readonly command: string | undefined;
|
|
62
|
+
readonly reply: (text: string, options?: Omit<BotResponseParams<"message">, "text" | "type">) => BotResponse;
|
|
63
|
+
readonly replyWithDocument: (document: BotResponseParams<"document">["document"], options?: Omit<BotResponseParams<"document">, "document" | "type">) => BotResponse;
|
|
64
|
+
readonly replyWithPhoto: (photo: BotResponseParams<"photo">["photo"], options?: Omit<BotResponseParams<"photo">, "photo" | "type">) => BotResponse;
|
|
65
|
+
readonly ignore: BotResponse;
|
|
66
|
+
}
|
|
67
|
+
type BotResponseParams<T extends string> = Extract<Parameters<typeof BotResponse.make>[0], {
|
|
68
|
+
type: T;
|
|
69
|
+
}>;
|
|
70
|
+
interface HandlerInput<U> {
|
|
71
|
+
readonly update: U;
|
|
72
|
+
readonly ctx: BotContext;
|
|
73
|
+
}
|
|
74
|
+
interface GuardedHandler<U> {
|
|
75
|
+
readonly match?: (input: HandlerInput<U>) => boolean | PromiseLike<boolean>;
|
|
76
|
+
readonly handle: (input: HandlerInput<U>) => BotResponse | PromiseLike<BotResponse>;
|
|
77
|
+
}
|
|
78
|
+
type UpdateHandler<U> = HandleUpdateFunction<U> | GuardedHandler<U> | GuardedHandler<U>[];
|
|
54
79
|
type BotUpdatesHandlers = {
|
|
55
|
-
|
|
80
|
+
[K in AvailableUpdateTypes as `on_${K}`]?: UpdateHandler<NonNullable<Update[K]>>;
|
|
56
81
|
};
|
|
57
82
|
interface HandleBatchUpdateFunction {
|
|
58
83
|
readonly on_batch: (update: Update[]) => boolean | PromiseLike<boolean>;
|
|
@@ -65,6 +90,8 @@ interface BotBatchMode extends HandleBatchUpdateFunction {
|
|
|
65
90
|
}
|
|
66
91
|
type BotMode = BotSingleMode | BotBatchMode;
|
|
67
92
|
|
|
93
|
+
declare const createBotContext: (update: unknown) => BotContext;
|
|
94
|
+
|
|
68
95
|
declare const extractUpdate: <U extends AvailableUpdateTypes>(input: Update) => ExtractedUpdate<U> | undefined;
|
|
69
96
|
declare class BatchUpdateResult extends Data.Class<{
|
|
70
97
|
hasErrors: boolean;
|
|
@@ -110,4 +137,13 @@ declare const runTgChatBot: (input: RunBotInput) => Promise<{
|
|
|
110
137
|
}>;
|
|
111
138
|
declare const defineBot: (input: BotUpdatesHandlers) => BotUpdatesHandlers;
|
|
112
139
|
|
|
113
|
-
|
|
140
|
+
interface WebhookBotConfig extends BotUpdatesHandlers {
|
|
141
|
+
bot_token: string;
|
|
142
|
+
}
|
|
143
|
+
interface WebhookHandler {
|
|
144
|
+
(request: Request): Promise<Response>;
|
|
145
|
+
handleUpdate: (update: Update) => Promise<void>;
|
|
146
|
+
}
|
|
147
|
+
declare const createWebhookHandler: (config: WebhookBotConfig) => WebhookHandler;
|
|
148
|
+
|
|
149
|
+
export { type AvailableUpdateTypes, BatchUpdateResult, type BotBatchMode, type BotContext, type BotInstance, type BotMode, BotPollSettings, BotPollSettingsTag, BotResponse, BotRunService, type BotSingleMode, BotTgClientTag, BotUpdateHandlersTag, type BotUpdatesHandlers, type ExtractedUpdate, type GuardedHandler, type HandleBatchUpdateFunction, HandleUpdateError, type HandleUpdateFunction, type HandlerInput, type PollSettings, type RunBotInput, type RunBotInputBatch, type RunBotInputSingle, type UpdateHandler, type WebhookBotConfig, type WebhookHandler, createBotContext, createWebhookHandler, defineBot, extractUpdate, handleEntireBatch, handleOneByOne, handleOneUpdate, handleUpdates, launchBot, runTgChatBot };
|
package/dist/index.js
CHANGED
|
@@ -2615,6 +2615,26 @@ var BotResponse = class _BotResponse extends TaggedClass("BotResponse") {
|
|
|
2615
2615
|
static ignore = new _BotResponse({});
|
|
2616
2616
|
};
|
|
2617
2617
|
|
|
2618
|
+
// src/internal/bot-context.ts
|
|
2619
|
+
var extractCommand = (update) => {
|
|
2620
|
+
if (typeof update !== "object" || update === null) return void 0;
|
|
2621
|
+
const u = update;
|
|
2622
|
+
if (!u.entities || !u.text) return void 0;
|
|
2623
|
+
const entity = u.entities.find((e) => e.type === "bot_command");
|
|
2624
|
+
if (!entity) return void 0;
|
|
2625
|
+
return u.text.slice(entity.offset, entity.offset + entity.length);
|
|
2626
|
+
};
|
|
2627
|
+
var createBotContext = (update) => {
|
|
2628
|
+
const command = extractCommand(update);
|
|
2629
|
+
return {
|
|
2630
|
+
command,
|
|
2631
|
+
reply: (text, options) => BotResponse.make({ type: "message", text, ...options }),
|
|
2632
|
+
replyWithDocument: (document, options) => BotResponse.make({ type: "document", document, ...options }),
|
|
2633
|
+
replyWithPhoto: (photo, options) => BotResponse.make({ type: "photo", photo, ...options }),
|
|
2634
|
+
ignore: BotResponse.ignore
|
|
2635
|
+
};
|
|
2636
|
+
};
|
|
2637
|
+
|
|
2618
2638
|
// ../../node_modules/.pnpm/effect@3.12.0/node_modules/effect/dist/esm/Effectable.js
|
|
2619
2639
|
var EffectPrototype2 = EffectPrototype;
|
|
2620
2640
|
|
|
@@ -3506,6 +3526,36 @@ var BotPollSettingsTag = class extends Reference2()(
|
|
|
3506
3526
|
};
|
|
3507
3527
|
|
|
3508
3528
|
// src/internal/handle-update.ts
|
|
3529
|
+
var isGuardedHandler = (handler) => typeof handler === "object" && handler !== null && "handle" in handler;
|
|
3530
|
+
var executeSingleGuard = async (guard, update, ctx) => {
|
|
3531
|
+
const input = { update, ctx };
|
|
3532
|
+
if (guard.match) {
|
|
3533
|
+
const matched = await guard.match(input);
|
|
3534
|
+
if (!matched) return null;
|
|
3535
|
+
}
|
|
3536
|
+
return await guard.handle(input);
|
|
3537
|
+
};
|
|
3538
|
+
var executeGuards = async (guards, update, ctx) => {
|
|
3539
|
+
for (const guard of guards) {
|
|
3540
|
+
const result = await executeSingleGuard(guard, update, ctx);
|
|
3541
|
+
if (result !== null) return result;
|
|
3542
|
+
}
|
|
3543
|
+
return BotResponse.ignore;
|
|
3544
|
+
};
|
|
3545
|
+
var executeHandler = (handler, update, ctx) => {
|
|
3546
|
+
if (typeof handler === "function") {
|
|
3547
|
+
return handler(update);
|
|
3548
|
+
}
|
|
3549
|
+
if (Array.isArray(handler)) {
|
|
3550
|
+
return executeGuards(handler, update, ctx);
|
|
3551
|
+
}
|
|
3552
|
+
if (isGuardedHandler(handler)) {
|
|
3553
|
+
return executeSingleGuard(handler, update, ctx).then(
|
|
3554
|
+
(r) => r ?? BotResponse.ignore
|
|
3555
|
+
);
|
|
3556
|
+
}
|
|
3557
|
+
return BotResponse.ignore;
|
|
3558
|
+
};
|
|
3509
3559
|
var extractUpdate = (input) => {
|
|
3510
3560
|
for (const [field, value] of Object.entries(input)) {
|
|
3511
3561
|
if (field == "update_id") {
|
|
@@ -3609,8 +3659,8 @@ var handleOneUpdate = (updateObject, handlers) => gen(function* () {
|
|
|
3609
3659
|
})
|
|
3610
3660
|
);
|
|
3611
3661
|
}
|
|
3612
|
-
const
|
|
3613
|
-
if (!
|
|
3662
|
+
const handler = handlers[`on_${update.type}`];
|
|
3663
|
+
if (!handler) {
|
|
3614
3664
|
return yield* fail3(
|
|
3615
3665
|
new HandleUpdateError({
|
|
3616
3666
|
name: "HandlerNotDefined",
|
|
@@ -3625,9 +3675,10 @@ var handleOneUpdate = (updateObject, handlers) => gen(function* () {
|
|
|
3625
3675
|
message: `${update.text.slice(0, 5)}...`
|
|
3626
3676
|
});
|
|
3627
3677
|
}
|
|
3678
|
+
const ctx = createBotContext(update);
|
|
3628
3679
|
let handleUpdateError;
|
|
3629
3680
|
const handleResult = yield* try_({
|
|
3630
|
-
try: () =>
|
|
3681
|
+
try: () => executeHandler(handler, update, ctx),
|
|
3631
3682
|
catch: (error) => new HandleUpdateError({
|
|
3632
3683
|
name: "BotHandlerError",
|
|
3633
3684
|
update: updateObject,
|
|
@@ -3830,20 +3881,28 @@ var _runBotDaemon = (state) => gen(function* () {
|
|
|
3830
3881
|
|
|
3831
3882
|
// src/internal/launch.ts
|
|
3832
3883
|
import { makeTgBotClient } from "@effect-ak/tg-bot-client";
|
|
3884
|
+
var extractMode = (input) => {
|
|
3885
|
+
if (input.mode === "batch") {
|
|
3886
|
+
return { type: "batch", on_batch: input.on_batch };
|
|
3887
|
+
}
|
|
3888
|
+
const { bot_token, mode, poll, ...handlers } = input;
|
|
3889
|
+
return { type: "single", ...handlers };
|
|
3890
|
+
};
|
|
3833
3891
|
var launchBot = (input) => gen(function* () {
|
|
3834
3892
|
const service2 = yield* service(BotRunService);
|
|
3835
3893
|
const client = makeTgBotClient({ bot_token: input.bot_token });
|
|
3836
3894
|
const contextWithClient = make4(BotTgClientTag, client);
|
|
3895
|
+
const mode = extractMode(input);
|
|
3837
3896
|
yield* service2.runBotInBackground.pipe(
|
|
3838
|
-
provideService(BotUpdateHandlersTag,
|
|
3897
|
+
provideService(BotUpdateHandlersTag, mode),
|
|
3839
3898
|
provideService(
|
|
3840
3899
|
BotPollSettingsTag,
|
|
3841
3900
|
BotPollSettings.make(input.poll ?? {})
|
|
3842
3901
|
),
|
|
3843
3902
|
provideContext(contextWithClient)
|
|
3844
3903
|
);
|
|
3845
|
-
const reload = (
|
|
3846
|
-
provideService(BotUpdateHandlersTag,
|
|
3904
|
+
const reload = (mode2) => service2.runBotInBackground.pipe(
|
|
3905
|
+
provideService(BotUpdateHandlersTag, mode2),
|
|
3847
3906
|
provideContext(contextWithClient),
|
|
3848
3907
|
runPromise
|
|
3849
3908
|
);
|
|
@@ -3860,6 +3919,91 @@ var defineBot = (input) => {
|
|
|
3860
3919
|
console.warn("No handlers are defined for bot");
|
|
3861
3920
|
return input;
|
|
3862
3921
|
};
|
|
3922
|
+
|
|
3923
|
+
// src/webhook.ts
|
|
3924
|
+
import { makeTgBotClient as makeTgBotClient2 } from "@effect-ak/tg-bot-client";
|
|
3925
|
+
var isGuardedHandler2 = (handler) => typeof handler === "object" && handler !== null && "handle" in handler;
|
|
3926
|
+
var executeSingleGuard2 = async (guard, update, ctx) => {
|
|
3927
|
+
const input = { update, ctx };
|
|
3928
|
+
if (guard.match) {
|
|
3929
|
+
const matched = await guard.match(input);
|
|
3930
|
+
if (!matched) return null;
|
|
3931
|
+
}
|
|
3932
|
+
return await guard.handle(input);
|
|
3933
|
+
};
|
|
3934
|
+
var executeGuards2 = async (guards, update, ctx) => {
|
|
3935
|
+
for (const guard of guards) {
|
|
3936
|
+
const result = await executeSingleGuard2(guard, update, ctx);
|
|
3937
|
+
if (result !== null) return result;
|
|
3938
|
+
}
|
|
3939
|
+
return BotResponse.ignore;
|
|
3940
|
+
};
|
|
3941
|
+
var executeHandler2 = async (handler, update, ctx) => {
|
|
3942
|
+
if (typeof handler === "function") {
|
|
3943
|
+
return await handler(update);
|
|
3944
|
+
}
|
|
3945
|
+
if (Array.isArray(handler)) {
|
|
3946
|
+
return await executeGuards2(handler, update, ctx);
|
|
3947
|
+
}
|
|
3948
|
+
if (isGuardedHandler2(handler)) {
|
|
3949
|
+
const result = await executeSingleGuard2(handler, update, ctx);
|
|
3950
|
+
return result ?? BotResponse.ignore;
|
|
3951
|
+
}
|
|
3952
|
+
return BotResponse.ignore;
|
|
3953
|
+
};
|
|
3954
|
+
var extractUpdate2 = (input) => {
|
|
3955
|
+
for (const [field, value] of Object.entries(input)) {
|
|
3956
|
+
if (field === "update_id") continue;
|
|
3957
|
+
return { type: field, ...value };
|
|
3958
|
+
}
|
|
3959
|
+
return void 0;
|
|
3960
|
+
};
|
|
3961
|
+
var processUpdate = async (updateObject, handlers, client) => {
|
|
3962
|
+
const update = extractUpdate2(updateObject);
|
|
3963
|
+
if (!update) {
|
|
3964
|
+
console.warn("Unknown update format", updateObject);
|
|
3965
|
+
return;
|
|
3966
|
+
}
|
|
3967
|
+
const handlerKey = `on_${update.type}`;
|
|
3968
|
+
const handler = handlers[handlerKey];
|
|
3969
|
+
if (!handler) {
|
|
3970
|
+
return;
|
|
3971
|
+
}
|
|
3972
|
+
const ctx = createBotContext(update);
|
|
3973
|
+
try {
|
|
3974
|
+
const result = await executeHandler2(handler, update, ctx);
|
|
3975
|
+
if (result.response && "chat" in update) {
|
|
3976
|
+
const responsePayload = result.response;
|
|
3977
|
+
await client.execute(`send_${responsePayload.type}`, {
|
|
3978
|
+
...responsePayload,
|
|
3979
|
+
chat_id: update.chat.id
|
|
3980
|
+
});
|
|
3981
|
+
}
|
|
3982
|
+
} catch (error) {
|
|
3983
|
+
console.error("Error handling update", {
|
|
3984
|
+
updateId: updateObject.update_id,
|
|
3985
|
+
error: error instanceof Error ? error.message : error
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3988
|
+
};
|
|
3989
|
+
var createWebhookHandler = (config) => {
|
|
3990
|
+
const client = makeTgBotClient2({ bot_token: config.bot_token });
|
|
3991
|
+
const handleUpdate = async (update) => {
|
|
3992
|
+
await processUpdate(update, config, client);
|
|
3993
|
+
};
|
|
3994
|
+
const handler = async (request) => {
|
|
3995
|
+
try {
|
|
3996
|
+
const update = await request.json();
|
|
3997
|
+
await handleUpdate(update);
|
|
3998
|
+
return new Response("ok", { status: 200 });
|
|
3999
|
+
} catch (error) {
|
|
4000
|
+
console.error("Webhook error", error);
|
|
4001
|
+
return new Response("error", { status: 500 });
|
|
4002
|
+
}
|
|
4003
|
+
};
|
|
4004
|
+
handler.handleUpdate = handleUpdate;
|
|
4005
|
+
return handler;
|
|
4006
|
+
};
|
|
3863
4007
|
export {
|
|
3864
4008
|
BatchUpdateResult,
|
|
3865
4009
|
BotPollSettings,
|
|
@@ -3869,6 +4013,8 @@ export {
|
|
|
3869
4013
|
BotTgClientTag,
|
|
3870
4014
|
BotUpdateHandlersTag,
|
|
3871
4015
|
HandleUpdateError,
|
|
4016
|
+
createBotContext,
|
|
4017
|
+
createWebhookHandler,
|
|
3872
4018
|
defineBot,
|
|
3873
4019
|
extractUpdate,
|
|
3874
4020
|
handleEntireBatch,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-ak/tg-bot",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Telegram Bot runner",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,13 +34,14 @@
|
|
|
34
34
|
"dist/*.d.ts"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@effect-ak/tg-bot-client": "^1.1
|
|
38
|
-
"@effect-ak/tg-bot-api": "0.
|
|
37
|
+
"@effect-ak/tg-bot-client": "^1.3.1",
|
|
38
|
+
"@effect-ak/tg-bot-api": "^1.0.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"effect": "^3.12.7"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
|
-
"build": "tsup"
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"typecheck": "tsc"
|
|
45
46
|
}
|
|
46
47
|
}
|
package/readme.md
CHANGED
|
@@ -60,21 +60,17 @@ yarn add @effect-ak/tg-bot effect
|
|
|
60
60
|
## Quick Start
|
|
61
61
|
|
|
62
62
|
```typescript
|
|
63
|
-
import { runTgChatBot
|
|
63
|
+
import { runTgChatBot } from "@effect-ak/tg-bot"
|
|
64
64
|
|
|
65
65
|
runTgChatBot({
|
|
66
66
|
bot_token: "YOUR_BOT_TOKEN",
|
|
67
|
-
mode:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return BotResponse.make({
|
|
73
|
-
type: "message",
|
|
74
|
-
text: `You said: ${message.text}`
|
|
75
|
-
})
|
|
67
|
+
mode: "single",
|
|
68
|
+
on_message: [
|
|
69
|
+
{
|
|
70
|
+
match: ({ update }) => !!update.text,
|
|
71
|
+
handle: ({ update, ctx }) => ctx.reply(`You said: ${update.text}`)
|
|
76
72
|
}
|
|
77
|
-
|
|
73
|
+
]
|
|
78
74
|
})
|
|
79
75
|
```
|
|
80
76
|
|
|
@@ -84,6 +80,31 @@ runTgChatBot({
|
|
|
84
80
|
|
|
85
81
|
In single mode, the bot processes each update individually with a dedicated handler for each update type.
|
|
86
82
|
|
|
83
|
+
**Handler Format (v2 with guards):**
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
on_message: [
|
|
87
|
+
{
|
|
88
|
+
match: ({ update, ctx }) => ctx.command === "/start", // optional filter
|
|
89
|
+
handle: ({ update, ctx }) => ctx.reply("Welcome!") // handler
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
match: ({ update }) => !!update.text,
|
|
93
|
+
handle: ({ ctx }) => ctx.reply("Got your message!")
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
handle: ({ ctx }) => ctx.ignore // fallback (no match = always runs)
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Context helpers:**
|
|
102
|
+
- `ctx.reply(text, options?)` - Send a message
|
|
103
|
+
- `ctx.replyWithDocument(document, options?)` - Send a document
|
|
104
|
+
- `ctx.replyWithPhoto(photo, options?)` - Send a photo
|
|
105
|
+
- `ctx.command` - Parsed command (e.g., "/start", "/help")
|
|
106
|
+
- `ctx.ignore` - Skip response
|
|
107
|
+
|
|
87
108
|
**Available Handlers:**
|
|
88
109
|
- `on_message` - New incoming message
|
|
89
110
|
- `on_edited_message` - Message was edited
|
|
@@ -100,6 +121,15 @@ In single mode, the bot processes each update individually with a dedicated hand
|
|
|
100
121
|
- `on_chat_member` - Chat member status changed
|
|
101
122
|
- `on_chat_join_request` - Request to join chat
|
|
102
123
|
|
|
124
|
+
**Legacy format (v1 - still supported):**
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
on_message: (message) => {
|
|
128
|
+
if (!message.text) return BotResponse.ignore
|
|
129
|
+
return BotResponse.make({ type: "message", text: "Hello!" })
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
103
133
|
### Batch Mode
|
|
104
134
|
|
|
105
135
|
In batch mode, the bot receives all updates as an array and processes them together.
|
|
@@ -107,13 +137,11 @@ In batch mode, the bot receives all updates as an array and processes them toget
|
|
|
107
137
|
```typescript
|
|
108
138
|
runTgChatBot({
|
|
109
139
|
bot_token: "YOUR_BOT_TOKEN",
|
|
110
|
-
mode:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return true // Continue polling
|
|
116
|
-
}
|
|
140
|
+
mode: "batch",
|
|
141
|
+
on_batch: async (updates) => {
|
|
142
|
+
console.log(`Processing ${updates.length} updates`)
|
|
143
|
+
// Process updates...
|
|
144
|
+
return true // Continue polling
|
|
117
145
|
}
|
|
118
146
|
})
|
|
119
147
|
```
|
|
@@ -155,66 +183,45 @@ All Telegram `send_*` methods are supported: `message`, `photo`, `document`, `vi
|
|
|
155
183
|
### Echo Bot
|
|
156
184
|
|
|
157
185
|
```typescript
|
|
158
|
-
import { runTgChatBot,
|
|
186
|
+
import { runTgChatBot, defineBot } from "@effect-ak/tg-bot"
|
|
159
187
|
|
|
160
188
|
const ECHO_BOT = defineBot({
|
|
161
|
-
on_message:
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
reply_parameters: {
|
|
168
|
-
message_id: message.message_id
|
|
169
|
-
}
|
|
170
|
-
})
|
|
171
|
-
}
|
|
189
|
+
on_message: [
|
|
190
|
+
{
|
|
191
|
+
match: ({ update }) => !!update.text,
|
|
192
|
+
handle: ({ update, ctx }) => ctx.reply(update.text!)
|
|
193
|
+
}
|
|
194
|
+
]
|
|
172
195
|
})
|
|
173
196
|
|
|
174
197
|
runTgChatBot({
|
|
175
198
|
bot_token: "YOUR_BOT_TOKEN",
|
|
176
|
-
mode:
|
|
177
|
-
|
|
178
|
-
...ECHO_BOT
|
|
179
|
-
}
|
|
199
|
+
mode: "single",
|
|
200
|
+
...ECHO_BOT
|
|
180
201
|
})
|
|
181
202
|
```
|
|
182
203
|
|
|
183
204
|
### Command Handler
|
|
184
205
|
|
|
185
206
|
```typescript
|
|
186
|
-
import { runTgChatBot
|
|
207
|
+
import { runTgChatBot } from "@effect-ak/tg-bot"
|
|
187
208
|
import { MESSAGE_EFFECTS } from "@effect-ak/tg-bot-client"
|
|
188
209
|
|
|
189
210
|
runTgChatBot({
|
|
190
211
|
bot_token: "YOUR_BOT_TOKEN",
|
|
191
|
-
mode:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
type: "message",
|
|
203
|
-
text: "Welcome! Send me any message.",
|
|
204
|
-
message_effect_id: MESSAGE_EFFECTS["🎉"]
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
case "/help":
|
|
208
|
-
return BotResponse.make({
|
|
209
|
-
type: "message",
|
|
210
|
-
text: "Available commands:\n/start - Start bot\n/help - Show help"
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
default:
|
|
214
|
-
return BotResponse.ignore
|
|
215
|
-
}
|
|
212
|
+
mode: "single",
|
|
213
|
+
on_message: [
|
|
214
|
+
{
|
|
215
|
+
match: ({ ctx }) => ctx.command === "/start",
|
|
216
|
+
handle: ({ ctx }) => ctx.reply("Welcome! Send me any message.", {
|
|
217
|
+
message_effect_id: MESSAGE_EFFECTS["🎉"]
|
|
218
|
+
})
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
match: ({ ctx }) => ctx.command === "/help",
|
|
222
|
+
handle: ({ ctx }) => ctx.reply("Available commands:\n/start - Start bot\n/help - Show help")
|
|
216
223
|
}
|
|
217
|
-
|
|
224
|
+
]
|
|
218
225
|
})
|
|
219
226
|
```
|
|
220
227
|
|
|
@@ -228,24 +235,22 @@ const client = makeTgBotClient({ bot_token: "YOUR_BOT_TOKEN" })
|
|
|
228
235
|
|
|
229
236
|
runTgChatBot({
|
|
230
237
|
bot_token: "YOUR_BOT_TOKEN",
|
|
238
|
+
mode: "batch",
|
|
231
239
|
poll: {
|
|
232
240
|
batch_size: 100,
|
|
233
241
|
poll_timeout: 60
|
|
234
242
|
},
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
text: `Processed ${messages.length} messages`
|
|
245
|
-
})
|
|
243
|
+
on_batch: async (updates) => {
|
|
244
|
+
const messages = updates
|
|
245
|
+
.map(u => u.message)
|
|
246
|
+
.filter(m => m != null)
|
|
247
|
+
|
|
248
|
+
await client.execute("send_message", {
|
|
249
|
+
chat_id: "ADMIN_CHAT_ID",
|
|
250
|
+
text: `Processed ${messages.length} messages`
|
|
251
|
+
})
|
|
246
252
|
|
|
247
|
-
|
|
248
|
-
}
|
|
253
|
+
return true // Continue polling
|
|
249
254
|
}
|
|
250
255
|
})
|
|
251
256
|
```
|
|
@@ -256,32 +261,24 @@ Advanced usage with Effect for composable async operations:
|
|
|
256
261
|
|
|
257
262
|
```typescript
|
|
258
263
|
import { Effect, Micro, pipe } from "effect"
|
|
259
|
-
import {
|
|
264
|
+
import { launchBot } from "@effect-ak/tg-bot"
|
|
260
265
|
|
|
261
266
|
Effect.gen(function* () {
|
|
262
267
|
const bot = yield* launchBot({
|
|
263
268
|
bot_token: "YOUR_BOT_TOKEN",
|
|
269
|
+
mode: "single",
|
|
264
270
|
poll: {
|
|
265
271
|
log_level: "debug"
|
|
266
272
|
},
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
Effect.sleep("2 seconds"),
|
|
275
|
-
Effect.andThen(() =>
|
|
276
|
-
BotResponse.make({
|
|
277
|
-
type: "message",
|
|
278
|
-
text: "Delayed response!"
|
|
279
|
-
})
|
|
280
|
-
),
|
|
281
|
-
Effect.runPromise
|
|
282
|
-
)
|
|
273
|
+
on_message: [
|
|
274
|
+
{
|
|
275
|
+
match: ({ update }) => !!update.text,
|
|
276
|
+
handle: async ({ ctx }) => {
|
|
277
|
+
await Effect.sleep("2 seconds").pipe(Effect.runPromise)
|
|
278
|
+
return ctx.reply("Delayed response!")
|
|
279
|
+
}
|
|
283
280
|
}
|
|
284
|
-
|
|
281
|
+
]
|
|
285
282
|
})
|
|
286
283
|
|
|
287
284
|
// Access bot fiber for control
|
|
@@ -296,30 +293,31 @@ Effect.gen(function* () {
|
|
|
296
293
|
### Hot Reload
|
|
297
294
|
|
|
298
295
|
```typescript
|
|
299
|
-
import {
|
|
300
|
-
import { launchBot, BotResponse } from "@effect-ak/tg-bot"
|
|
296
|
+
import { runTgChatBot } from "@effect-ak/tg-bot"
|
|
301
297
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
text: "Version 1"
|
|
310
|
-
})
|
|
298
|
+
const bot = await runTgChatBot({
|
|
299
|
+
bot_token: "YOUR_BOT_TOKEN",
|
|
300
|
+
mode: "single",
|
|
301
|
+
on_message: [
|
|
302
|
+
{
|
|
303
|
+
match: ({ update }) => !!update.text,
|
|
304
|
+
handle: ({ ctx }) => ctx.reply("Version 1")
|
|
311
305
|
}
|
|
312
|
-
|
|
306
|
+
]
|
|
307
|
+
})
|
|
313
308
|
|
|
314
|
-
|
|
315
|
-
|
|
309
|
+
// Later, reload with new handlers
|
|
310
|
+
setTimeout(() => {
|
|
311
|
+
bot.reload({
|
|
316
312
|
type: "single",
|
|
317
|
-
on_message:
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
313
|
+
on_message: [
|
|
314
|
+
{
|
|
315
|
+
match: ({ update }) => !!update.text,
|
|
316
|
+
handle: ({ ctx }) => ctx.reply("Version 2 - Hot reloaded!")
|
|
317
|
+
}
|
|
318
|
+
]
|
|
321
319
|
})
|
|
322
|
-
})
|
|
320
|
+
}, 5000)
|
|
323
321
|
```
|
|
324
322
|
|
|
325
323
|
## Configuration
|
|
@@ -331,6 +329,7 @@ Configure how the bot polls for updates:
|
|
|
331
329
|
```typescript
|
|
332
330
|
runTgChatBot({
|
|
333
331
|
bot_token: "YOUR_BOT_TOKEN",
|
|
332
|
+
mode: "single", // or "batch"
|
|
334
333
|
poll: {
|
|
335
334
|
log_level: "debug", // "info" | "debug"
|
|
336
335
|
on_error: "continue", // "stop" | "continue"
|
|
@@ -338,7 +337,7 @@ runTgChatBot({
|
|
|
338
337
|
poll_timeout: 30, // 2-120 seconds
|
|
339
338
|
max_empty_responses: 5 // Stop after N empty responses
|
|
340
339
|
},
|
|
341
|
-
|
|
340
|
+
on_message: [/* ... */] // handlers at top level
|
|
342
341
|
})
|
|
343
342
|
```
|
|
344
343
|
|
|
@@ -366,10 +365,12 @@ Starts the bot with long polling.
|
|
|
366
365
|
|
|
367
366
|
**Parameters:**
|
|
368
367
|
- `bot_token` (string, required): Bot token from @BotFather
|
|
369
|
-
- `mode` (
|
|
368
|
+
- `mode` (`"single"` | `"batch"`, required): Processing mode
|
|
370
369
|
- `poll` (object, optional): Polling configuration
|
|
370
|
+
- `on_message`, `on_callback_query`, etc. (optional): Update handlers (for single mode)
|
|
371
|
+
- `on_batch` (required for batch mode): Batch handler function
|
|
371
372
|
|
|
372
|
-
**Returns:** `Promise<
|
|
373
|
+
**Returns:** `Promise<BotInstance>`
|
|
373
374
|
|
|
374
375
|
### `launchBot(input)`
|
|
375
376
|
|
|
@@ -450,13 +451,19 @@ If a handler throws an error, the bot:
|
|
|
450
451
|
3. Continues processing other updates (if `on_error: "continue"`)
|
|
451
452
|
|
|
452
453
|
```typescript
|
|
453
|
-
on_message:
|
|
454
|
-
|
|
455
|
-
|
|
454
|
+
on_message: [
|
|
455
|
+
{
|
|
456
|
+
match: ({ ctx }) => ctx.command === "/error",
|
|
457
|
+
handle: () => {
|
|
458
|
+
throw new Error("Something went wrong!")
|
|
459
|
+
// Bot will catch this and send error message to user
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
match: ({ update }) => !!update.text,
|
|
464
|
+
handle: ({ ctx }) => ctx.reply("OK")
|
|
456
465
|
}
|
|
457
|
-
|
|
458
|
-
return BotResponse.make({ type: "message", text: "OK" })
|
|
459
|
-
}
|
|
466
|
+
]
|
|
460
467
|
```
|
|
461
468
|
|
|
462
469
|
### Batch Handler Errors
|