Documentation
¶
Overview ¶
Package laniakea provides a modular, extensible framework for building scalable Telegram bots.
Core concepts:
- Bot manages Telegram API access, update processing, logging, rate limiting, and dependency injection.
- Plugins group commands, payloads, and non-command update handlers behind shared middleware.
- MessageContext provides access to the current update and reply/edit/delete helpers.
- InlineKeyboard builds callback-driven keyboards and structured payloads.
- DraftProvider accumulates multi-step replies before sending them.
- L10n stores key-based translations with fallback behavior.
- Runners execute startup or background tasks alongside the polling loop.
Example usage:
bot, err := laniakea.NewBot[*mydb.AppData](laniakea.LoadOptsFromEnv())
if err != nil {
return err
}
bot.SetAppData(myDB).
AddUpdateType(tgapi.UpdateTypeMessage).
AddPrefixes("/", "!").
AddPlugins(&startPlugin, &helpPlugin).
AddMiddleware(authMiddleware, logMiddleware).
AddRunner(cleanupRunner).
SetL10n(l10n.New())
return bot.Run()
Configure bots, plugins, and localization before starting Run, RunWithContext, or RunWebhookWithContext. Runtime accessors are safe for concurrent use unless stated otherwise.
Index ¶
- Constants
- Variables
- func AsInternalError(err error) error
- func AsUserError(err error) error
- func IsInternalError(err error) bool
- func IsUserError(err error) bool
- func LoadPrefixesFromEnv() []string
- func Ptr[T any](v T) *T
- func SaveBotOptsFile(codec BotOptsFileCodec, filename string, opts *BotOpts) error
- func SplitMessageText(text string) []string
- func Val[T any](p *T, def T) T
- type AnswerMessage
- func (m *AnswerMessage) Delete()
- func (m *AnswerMessage) Edit(text string) *AnswerMessage
- func (m *AnswerMessage) EditCaption(text string) *AnswerMessage
- func (m *AnswerMessage) EditCaptionKeyboard(text string, kb *InlineKeyboard) *AnswerMessage
- func (m *AnswerMessage) EditCaptionKeyboardMarkdown(text string, kb *InlineKeyboard) *AnswerMessage
- func (m *AnswerMessage) EditCaptionMarkdown(text string) *AnswerMessage
- func (m *AnswerMessage) EditMarkdown(text string) *AnswerMessage
- func (m *AnswerMessage) EditRich(blocks ...tgapi.InputRichBlock) *AnswerMessage
- func (m *AnswerMessage) EditRichKeyboard(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage
- type AppData
- type AppDataLogger
- type Bot
- func (bot *Bot[T]) AddAppDataLoggerWriter(writer AppDataLogger[T]) *Bot[T]
- func (bot *Bot[T]) AddMiddleware(middleware ...Middleware[T]) *Bot[T]
- func (bot *Bot[T]) AddPlugins(plugin ...*Plugin[T]) *Bot[T]
- func (bot *Bot[T]) AddPrefixes(prefixes ...string) *Bot[T]
- func (bot *Bot[T]) AddRunner(runner Runner[T]) *Bot[T]
- func (bot *Bot[T]) AddUpdateType(t ...tgapi.UpdateType) *Bot[T]
- func (bot *Bot[T]) AutoGenerateCommands() error
- func (bot *Bot[T]) AutoGenerateCommandsForScope(scope *tgapi.BotCommandScope) error
- func (bot *Bot[T]) AutoGenerateCommandsForScopeWithContext(ctx context.Context, scope *tgapi.BotCommandScope) error
- func (bot *Bot[T]) AutoGenerateCommandsWithContext(ctx context.Context) error
- func (bot *Bot[T]) Close() error
- func (bot *Bot[T]) CloseRemote(ctx context.Context) error
- func (bot *Bot[T]) CloseWebhook() error
- func (bot *Bot[T]) ExecRunners(ctx context.Context)
- func (bot *Bot[T]) GetAPI() *tgapi.API
- func (bot *Bot[T]) GetAppData() T
- func (bot *Bot[T]) GetDraftProvider() *DraftProvider
- func (bot *Bot[T]) GetLogger() *sneklog.Logger
- func (bot *Bot[T]) GetLoggerLevel() sneklog.LogLevel
- func (bot *Bot[T]) GetObserver() Observer
- func (bot *Bot[T]) GetPayloadType() BotPayloadType
- func (bot *Bot[T]) GetRequestLogger() *sneklog.Logger
- func (bot *Bot[T]) GetSessionStore() SessionStore
- func (bot *Bot[T]) GetUpdateOffset() int
- func (bot *Bot[T]) GetUpdateTypes() []tgapi.UpdateType
- func (bot *Bot[T]) GetUploader() *tgapi.Uploader
- func (bot *Bot[T]) GetWebhookLogger() *sneklog.Logger
- func (bot *Bot[T]) L10n(lang, key string) string
- func (bot *Bot[T]) Run() error
- func (bot *Bot[T]) RunWebhook(opts *BotWebhookOpts, tlsFiles ...string) error
- func (bot *Bot[T]) RunWebhookWithContext(ctx context.Context, opts *BotWebhookOpts, tlsFiles ...string) error
- func (bot *Bot[T]) RunWithContext(ctx context.Context) error
- func (bot *Bot[T]) SetAppData(ctx T) *Bot[T]
- func (bot *Bot[T]) SetDebug(debug bool) *Bot[T]
- func (bot *Bot[T]) SetDraftProvider(p *DraftProvider) *Bot[T]
- func (bot *Bot[T]) SetErrorTemplate(s string) *Bot[T]
- func (bot *Bot[T]) SetL10n(l *L10n) *Bot[T]
- func (bot *Bot[T]) SetLogger(l *sneklog.Logger) *Bot[T]
- func (bot *Bot[T]) SetObserver(observer Observer) *Bot[T]
- func (bot *Bot[T]) SetPayloadType(t BotPayloadType) *Bot[T]
- func (bot *Bot[T]) SetRequestLogger(l *sneklog.Logger) *Bot[T]
- func (bot *Bot[T]) SetSceneScopePriority(priority []SceneScope) *Bot[T]
- func (bot *Bot[T]) SetSessionStore(store SessionStore) *Bot[T]
- func (bot *Bot[T]) SetStrictPayloadType(strict bool) *Bot[T]
- func (bot *Bot[T]) SetUpdateOffset(offset int)
- func (bot *Bot[T]) SetUpdateTypes(t ...tgapi.UpdateType) *Bot[T]
- func (bot *Bot[T]) SetWebhookLogger(l *sneklog.Logger) *Bot[T]
- func (bot *Bot[T]) Updates(ctx context.Context) ([]tgapi.Update, error)
- func (bot *Bot[T]) UpdatesIter(ctx context.Context) iter.Seq2[tgapi.Update, error]
- func (bot *Bot[T]) UsePolicy(name string, policy Policy[T]) *Bot[T]
- type BotOpts
- func (opts *BotOpts) SetAPIURL(url string) *BotOpts
- func (opts *BotOpts) SetDebug(debug bool) *BotOpts
- func (opts *BotOpts) SetDropRateLimitOverflow(drop bool) *BotOpts
- func (opts *BotOpts) SetErrorTemplate(tpl string) *BotOpts
- func (opts *BotOpts) SetLogFormat(format utils.LogFormat) *BotOpts
- func (opts *BotOpts) SetLogFormatter(formatter *sneklog.Formatter) *BotOpts
- func (opts *BotOpts) SetLoggerBasePath(path string) *BotOpts
- func (opts *BotOpts) SetMaxWorkers(workers int) *BotOpts
- func (opts *BotOpts) SetPollTimeout(seconds int) *BotOpts
- func (opts *BotOpts) SetPrefixes(prefixes ...string) *BotOpts
- func (opts *BotOpts) SetProxyURL(u *url.URL) *BotOpts
- func (opts *BotOpts) SetRateLimit(limit int) *BotOpts
- func (opts *BotOpts) SetStrictPayloadType(strict bool) *BotOpts
- func (opts *BotOpts) SetToken(token string) *BotOpts
- func (opts *BotOpts) SetUpdateTypes(types ...tgapi.UpdateType) *BotOpts
- func (opts *BotOpts) SetUseRequestLogger(use bool) *BotOpts
- func (opts *BotOpts) SetUseTestServer(use bool) *BotOpts
- func (opts *BotOpts) SetWriteToFile(write bool) *BotOpts
- type BotOptsFileCodec
- type BotOptsFileJSON
- type BotOptsFileJSONCodec
- func (codec BotOptsFileJSONCodec) EscapeEnv(s string) string
- func (codec BotOptsFileJSONCodec) FromBytes(data []byte) (*BotOpts, error)
- func (codec BotOptsFileJSONCodec) Load(filename string) (*BotOpts, error)
- func (codec BotOptsFileJSONCodec) Save(filename string, opts *BotOpts) error
- func (codec BotOptsFileJSONCodec) ToBytes(opts *BotOpts) ([]byte, error)
- type BotOptsFileJSONProxy
- type BotPayloadType
- type BotWebhookOpts
- func (opts *BotWebhookOpts) MustLoadCertificate(filename string) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetAllowedUpdates(updates ...tgapi.UpdateType) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetCertificate(certificate []byte) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetDropPendingUpdates(drop bool) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetIPAddress(ip string) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetLocalPort(port int) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetMaxConnections(max int8) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetPath(path string) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetSecretToken(secretToken string) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetURL(url string) *BotWebhookOpts
- func (opts *BotWebhookOpts) SetUseStatusPath(use bool) *BotWebhookOpts
- type CallbackData
- type Command
- type CommandArg
- type CommandExecutor
- type CommandGroup
- type CommandScopeUpdateError
- type CommandValueType
- type DictEntry
- type Draft
- type DraftProvider
- type ErrorEvent
- type Event
- type HandlerEventKind
- type HandlerFinishedEvent
- type HandlerStartedEvent
- type InlineKeyboard
- func NewInlineKeyboard(payloadType BotPayloadType, maxRow int) *InlineKeyboard
- func NewInlineKeyboardBase64(maxRow int) *InlineKeyboard
- func NewInlineKeyboardCompact(maxRow int) *InlineKeyboard
- func NewInlineKeyboardCompactBase64(maxRow int) *InlineKeyboard
- func NewInlineKeyboardJSON(maxRow int) *InlineKeyboard
- func (in *InlineKeyboard) AddButton(b InlineKeyboardButtonBuilder) *InlineKeyboard
- func (in *InlineKeyboard) AddCallbackButton(text, cmd string, args ...any) *InlineKeyboard
- func (in *InlineKeyboard) AddCallbackButtonStyle(text string, style tgapi.KeyboardButtonStyle, cmd string, args ...any) *InlineKeyboard
- func (in *InlineKeyboard) AddLine() *InlineKeyboard
- func (in *InlineKeyboard) AddURLButton(text, url string) *InlineKeyboard
- func (in *InlineKeyboard) AddURLButtonStyle(text string, style tgapi.KeyboardButtonStyle, url string) *InlineKeyboard
- func (in *InlineKeyboard) Get() (*tgapi.ReplyMarkup, error)
- func (in *InlineKeyboard) GetMaxRow() int
- func (in *InlineKeyboard) GetPayloadType() BotPayloadType
- func (in *InlineKeyboard) SetMaxRow(maxRow int) *InlineKeyboard
- func (in *InlineKeyboard) SetPayloadType(t BotPayloadType) *InlineKeyboard
- func (in *InlineKeyboard) SetUnlimitedRows() *InlineKeyboard
- type InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) Build() (tgapi.InlineKeyboardButton, error)
- func (b InlineKeyboardButtonBuilder) SetCallbackData(cmd string, args ...any) InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) SetCallbackDataBase64(cmd string, args ...any) InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) SetCallbackDataCompact(cmd string, args ...any) InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) SetCallbackDataCompactBase64(cmd string, args ...any) InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) SetCallbackDataJSON(cmd string, args ...any) InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) SetDisabled() InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) SetIconCustomEmojiID(id string) InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) SetPayloadType(t BotPayloadType) InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) SetStyle(style tgapi.KeyboardButtonStyle) InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) SetURL(url string) InlineKeyboardButtonBuilder
- func (b InlineKeyboardButtonBuilder) Validate() error
- type L10n
- type LinearDraftIDGenerator
- type MemorySessionStore
- type MessageContext
- func (ctx *MessageContext) Answer(text string) *AnswerMessage
- func (ctx *MessageContext) AnswerCallback()
- func (ctx *MessageContext) AnswerCallbackAlert(text string)
- func (ctx *MessageContext) AnswerCallbackText(text string)
- func (ctx *MessageContext) AnswerCallbackURL(u string)
- func (ctx *MessageContext) AnswerLong(text string) []*AnswerMessage
- func (ctx *MessageContext) AnswerLongf(template string, args ...any) []*AnswerMessage
- func (ctx *MessageContext) AnswerMarkdown(text string) *AnswerMessage
- func (ctx *MessageContext) AnswerPhoto(photoID, text string) *AnswerMessage
- func (ctx *MessageContext) AnswerPhotoKeyboard(photoID, text string, kb *InlineKeyboard) *AnswerMessage
- func (ctx *MessageContext) AnswerPhotoKeyboardMarkdown(photoID, text string, kb *InlineKeyboard) *AnswerMessage
- func (ctx *MessageContext) AnswerPhotoMarkdown(photoID, text string) *AnswerMessage
- func (ctx *MessageContext) AnswerPhotof(photoID, template string, args ...any) *AnswerMessage
- func (ctx *MessageContext) AnswerPhotofMarkdown(photoID, template string, args ...any) *AnswerMessage
- func (ctx *MessageContext) Answerf(template string, args ...any) *AnswerMessage
- func (ctx *MessageContext) AnswerfMarkdown(template string, args ...any) *AnswerMessage
- func (ctx *MessageContext) BindArgs(dst any) error
- func (ctx *MessageContext) CallbackDelete()
- func (ctx *MessageContext) Context() context.Context
- func (ctx *MessageContext) EditCallback(text string, keyboard *InlineKeyboard) *AnswerMessage
- func (ctx *MessageContext) EditCallbackMarkdown(text string, keyboard *InlineKeyboard) *AnswerMessage
- func (ctx *MessageContext) EditCallbackRich(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage
- func (ctx *MessageContext) EditCallbackf(format string, keyboard *InlineKeyboard, args ...any) *AnswerMessage
- func (ctx *MessageContext) EditCallbackfMarkdown(format string, keyboard *InlineKeyboard, args ...any) *AnswerMessage
- func (ctx *MessageContext) EnterScene(name string) error
- func (ctx *MessageContext) EnterSceneStep(name, step string) error
- func (ctx *MessageContext) Error(err error)
- func (ctx *MessageContext) ExitScene() error
- func (ctx *MessageContext) HasPhoto() bool
- func (ctx *MessageContext) IsCallback() bool
- func (ctx *MessageContext) Keyboard(text string, kb *InlineKeyboard) *AnswerMessage
- func (ctx *MessageContext) KeyboardLong(text string, kb *InlineKeyboard) []*AnswerMessage
- func (ctx *MessageContext) KeyboardMarkdown(text string, keyboard *InlineKeyboard) *AnswerMessage
- func (ctx *MessageContext) NewDraft() *Draft
- func (ctx *MessageContext) NewDraftMarkdown() *Draft
- func (ctx *MessageContext) NewInlineKeyboard(maxRow int) *InlineKeyboard
- func (ctx *MessageContext) NewInlineKeyboardButton(text string) InlineKeyboardButtonBuilder
- func (ctx *MessageContext) RichAnswer(blocks ...tgapi.InputRichBlock) *AnswerMessage
- func (ctx *MessageContext) RichAnswerKeyboard(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage
- func (ctx *MessageContext) SendAction(action tgapi.ChatActionType)
- func (ctx *MessageContext) Translate(key string) string
- func (ctx *MessageContext) UpsertKeyboard(text string, keyboard *InlineKeyboard) *AnswerMessage
- func (ctx *MessageContext) UpsertKeyboardMarkdown(text string, keyboard *InlineKeyboard) *AnswerMessage
- func (ctx *MessageContext) UpsertKeyboardRich(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage
- type Middleware
- type MiddlewareExecutor
- type MultiObserver
- func (m MultiObserver) OnError(ctx context.Context, event ErrorEvent)
- func (m MultiObserver) OnHandlerFinished(ctx context.Context, event HandlerFinishedEvent)
- func (m MultiObserver) OnHandlerStarted(ctx context.Context, event HandlerStartedEvent)
- func (m MultiObserver) OnPolicyChecked(ctx context.Context, event PolicyCheckedEvent)
- func (m MultiObserver) OnPollingRetry(ctx context.Context, event PollingRetryEvent)
- func (m MultiObserver) OnRunnerFinished(ctx context.Context, event RunnerFinishedEvent)
- func (m MultiObserver) OnSceneTransition(ctx context.Context, event SceneTransitionEvent)
- func (m MultiObserver) OnUpdateHandled(ctx context.Context, event UpdateHandledEvent)
- func (m MultiObserver) OnUpdateReceived(ctx context.Context, event UpdateReceivedEvent)
- type NoData
- type Observer
- type Plugin
- func (p *Plugin[T]) AddCommand(command *Command[T]) *Plugin[T]
- func (p *Plugin[T]) AddCommandGroup(group *CommandGroup[T]) *Plugin[T]
- func (p *Plugin[T]) AddMiddleware(middleware Middleware[T]) *Plugin[T]
- func (p *Plugin[T]) AddPayload(command *Command[T]) *Plugin[T]
- func (p *Plugin[T]) AddScene(scene *Scene[T]) *Plugin[T]
- func (p *Plugin[T]) AddUpdateHandler(t tgapi.UpdateType, handler CommandExecutor[T]) *Plugin[T]
- func (p *Plugin[T]) Close() error
- func (p *Plugin[T]) Command(command string, exec CommandExecutor[T], args ...CommandArg) *Command[T]
- func (p *Plugin[T]) CommandGroup(prefix string, groupFunc func(group *CommandGroup[T])) *Plugin[T]
- func (p *Plugin[T]) Payload(command string, exec CommandExecutor[T], args ...CommandArg) *Command[T]
- func (p *Plugin[T]) RemoveLogger() *Plugin[T]
- func (p *Plugin[T]) Scene(name string) *Scene[T]
- func (p *Plugin[T]) SetLogger(l *sneklog.Logger) *Plugin[T]
- func (p *Plugin[T]) SetMessageFallback(handler CommandExecutor[T]) *Plugin[T]
- func (p *Plugin[T]) SetOnClose(f func() error) *Plugin[T]
- func (p *Plugin[T]) SkipCommandAutoGen() *Plugin[T]
- func (p *Plugin[T]) UsePolicy(name string, policy Policy[T]) *Plugin[T]
- type Policy
- func AllPolicies[T AppData](policies ...Policy[T]) Policy[T]
- func AnyPolicy[T AppData](policies ...Policy[T]) Policy[T]
- func NotPolicy[T AppData](policy Policy[T]) Policy[T]
- func RequireBotAdmin[T AppData]() Policy[T]
- func RequireCallbackFromUser[T AppData]() Policy[T]
- func RequireChatAdmin[T AppData]() Policy[T]
- func RequireChatCreator[T AppData]() Policy[T]
- func RequireGroupChat[T AppData]() Policy[T]
- func RequirePrivateChat[T AppData]() Policy[T]
- func RequireSupergroupChat[T AppData]() Policy[T]
- type PolicyCheckedEvent
- type PollingRetryEvent
- type RandomDraftIDGenerator
- type Runner
- type RunnerFinishedEvent
- type RunnerFn
- type Scene
- func (s *Scene[T]) OnCommand(cmd string, handler SceneHandler[T]) *Scene[T]
- func (s *Scene[T]) OnMessage(handler SceneHandler[T]) *Scene[T]
- func (s *Scene[T]) OnPayload(cmd string, handler SceneHandler[T]) *Scene[T]
- func (s *Scene[T]) OnStep(step string, handler SceneHandler[T]) *Scene[T]
- func (s *Scene[T]) SetEntry(step string) *Scene[T]
- func (s *Scene[T]) SetScope(scope SceneScope) *Scene[T]
- type SceneAction
- type SceneContext
- type SceneHandler
- type SceneResult
- type SceneScope
- type SceneSession
- type SceneTransitionEvent
- type SessionStore
- type UpdateHandledEvent
- type UpdateReceivedEvent
Constants ¶
const ( // ButtonStyleDanger marks a destructive inline keyboard action. ButtonStyleDanger tgapi.KeyboardButtonStyle = "danger" // ButtonStyleSuccess marks a confirmatory inline keyboard action. ButtonStyleSuccess tgapi.KeyboardButtonStyle = "success" // ButtonStylePrimary marks a primary inline keyboard action. ButtonStylePrimary tgapi.KeyboardButtonStyle = "primary" )
const ( // VersionString re-exports the module version string. VersionString = utils.VersionString // VersionMajor re-exports the module major version. VersionMajor = utils.VersionMajor // VersionMinor re-exports the module minor version. VersionMinor = utils.VersionMinor // VersionPatch re-exports the module patch version. VersionPatch = utils.VersionPatch // VersionBeta re-exports the module prerelease counter. VersionBeta = utils.VersionBeta )
const ConfigVersion = 1
ConfigVersion is the current version of the built-in JSON BotOpts file format.
Variables ¶
var ( // ErrNoPrefixes reports that the bot was started without any command prefixes. ErrNoPrefixes = errors.New("no prefixes defined") // ErrNoPlugins reports that the bot was started without any registered plugins. ErrNoPlugins = errors.New("no plugins defined") // ErrBotAlreadyRun reports that Run, RunWithContext, or RunWebhookWithContext was called more than once. ErrBotAlreadyRun = errors.New("bot can only be run once") // ErrTokenRequired reports that BotOpts.Token was empty. ErrTokenRequired = errors.New("token required") // ErrOptsIsNil reports that NewBot was called with a nil BotOpts pointer. ErrOptsIsNil = errors.New("opts is nil") )
var ( // ErrInvalidBotCommand reports a command name that Telegram would reject. ErrInvalidBotCommand = errors.New("invalid bot command") // ErrInvalidBotCommandDescription reports an empty or overlong generated description. ErrInvalidBotCommandDescription = errors.New("invalid bot command description") // ErrDuplicateBotCommand reports the same command generated by multiple plugins. ErrDuplicateBotCommand = errors.New("duplicate bot command") // ErrPartialCommandScopeUpdate reports that an earlier command scope was // updated before a later scope failed. ErrPartialCommandScopeUpdate = errors.New("partial command scope update") )
var ( // CommandRegexInt matches one or more digits. CommandRegexInt = regexp.MustCompile(`^\d+$`) // CommandRegexString matches any non-empty string. CommandRegexString = regexp.MustCompile(`^.+$`) // CommandRegexBool matches true or false. CommandRegexBool = regexp.MustCompile(`^(true|false)$`) )
var ( // ErrEmptyMessage reports that a required message text is empty. ErrEmptyMessage = errors.New("empty message") // ErrMessageTooLong reports that a message exceeds Telegram's text limit. ErrMessageTooLong = errors.New("message too long") // ErrCaptionTooLong reports that a caption exceeds Telegram's caption limit. ErrCaptionTooLong = errors.New("caption too long") // ErrMessageSplitImpossible reports that automatic message splitting cannot preserve semantics. ErrMessageSplitImpossible = errors.New("message split is impossible") // ErrPayloadTypeMismatch reports that callback payload encoding does not match bot policy. ErrPayloadTypeMismatch = errors.New("payload type mismatch") // ErrDraftChatIDZero reports that a draft has no target chat ID. ErrDraftChatIDZero = errors.New("zero draft chat ID") // ErrMessageNil reports that a required message value is nil. ErrMessageNil = errors.New("message is nil") // ErrMessageContextNil reports that an operation requires ctx.Msg but none is set. ErrMessageContextNil = errors.New("message context is nil") // ErrEditTargetMissing reports that an edit operation has no message target. ErrEditTargetMissing = errors.New("edit target is missing") // ErrCallbackMessageMissing reports that a callback operation has no callback message target. ErrCallbackMessageMissing = errors.New("callback message is missing") // ErrDraftProviderNil reports that draft creation was requested without a draft provider. ErrDraftProviderNil = errors.New("draft provider is nil") // ErrAPIIsNil reports that an operation requires an API client but none is set. ErrAPIIsNil = errors.New("api is nil") // ErrMessageIDZero reports that an operation requires a non-zero message ID. ErrMessageIDZero = errors.New("message ID is zero") // ErrCodecIsNil reports that a config operation received a nil codec. ErrCodecIsNil = errors.New("codec is nil") )
var ( // ErrBindArgsTargetNotPointer reports that BindArgs received a nil or non-pointer destination. ErrBindArgsTargetNotPointer = errors.New("bind args: dst must be a non-nil pointer") // ErrBindArgsTargetNotStruct reports that BindArgs received a pointer to a non-struct value. ErrBindArgsTargetNotStruct = errors.New("bind args: dst must point to a struct") // ErrBindArgsUnsupportedFieldType reports that BindArgs encountered an unsupported field kind. ErrBindArgsUnsupportedFieldType = errors.New("bind args: unsupported field type") // ErrBindArgsConversion reports that BindArgs could not convert a string argument into a field type. ErrBindArgsConversion = errors.New("bind args: conversion failed") // ErrCantFindSession reports that no scene session matches the current context. ErrCantFindSession = errors.New("can't find session for this context") // ErrSceneNotFound reports that the requested scene is not registered. ErrSceneNotFound = errors.New("scene not found") // ErrSceneStepNotFound reports that the requested scene step is not registered. ErrSceneStepNotFound = errors.New("scene step not found") // ErrNotInScene reports that the current context has no active scene session. ErrNotInScene = errors.New("not in scene") // ErrSceneEntryNotSet reports that a scene has no configured entry step. ErrSceneEntryNotSet = errors.New("scene entry step not set") // ErrSceneRuntimeNil reports that scene APIs were used without an attached runtime. ErrSceneRuntimeNil = errors.New("scene runtime is nil") // ErrInvalidSceneAction reports a SceneResult with an unknown action. ErrInvalidSceneAction = errors.New("invalid scene action") // ErrHandlerExecutorNil reports an attempted registration or execution of a nil handler. ErrHandlerExecutorNil = errors.New("handler executor is nil") // ErrHandlerPanic reports a panic recovered from a user handler. ErrHandlerPanic = errors.New("handler panicked") // ErrObserverShutdownTimeout reports that observer callbacks did not stop before shutdown timed out. ErrObserverShutdownTimeout = errors.New("observer shutdown timed out") // ErrInlineKeyboardButtonAction reports a button without exactly one action. ErrInlineKeyboardButtonAction = errors.New("inline keyboard button must have exactly one action") // ErrCallbackDataLength reports callback data outside Telegram's 1-64 byte range. ErrCallbackDataLength = errors.New("callback data must be between 1 and 64 bytes") // ErrInlineKeyboardRowTooLong reports a row exceeding the configured maximum. ErrInlineKeyboardRowTooLong = errors.New("inline keyboard row exceeds maximum size") // ErrInlineKeyboardMaxRow reports a non-positive row limit without explicit unlimited mode. ErrInlineKeyboardMaxRow = errors.New("inline keyboard maximum row size must be positive") )
var ( // ErrNilBotWebhookOpts reports that a nil BotWebhookOpts was passed. ErrNilBotWebhookOpts = errors.New("nil BotWebhookOpts") // ErrNoBotWebhookOptsURL reports that BotWebhookOpts.URL is empty. ErrNoBotWebhookOptsURL = errors.New("empty BotWebhookOpts.URL") // ErrBotWebhookOptsMaxConnectionsRange reports that BotWebhookOpts.MaxConnections is out of range. ErrBotWebhookOptsMaxConnectionsRange = errors.New("BotWebhookOpts.MaxConnections must be between 1 and 100") // ErrBotWebhookOptsSecretTokenInvalid reports that SecretToken violates Telegram's format. ErrBotWebhookOptsSecretTokenInvalid = errors.New("BotWebhookOpts.SecretToken must be 1-256 characters from A-Z, a-z, 0-9, _ and -") // ErrBotUploaderWhenCertificate reports that a certificate was set without an uploader. ErrBotUploaderWhenCertificate = errors.New("bot uploader nil, but certificate set") // ErrStatusPathSecretRequired reports that UseStatusPath requires SecretToken to be set. ErrStatusPathSecretRequired = errors.New("SecretToken required when UseStatusPath is enabled") // ErrSetWebhookFailed reports that Telegram rejected the setWebhook request. ErrSetWebhookFailed = errors.New("failed to set webhook") // ErrBotAPINil reports that an operation requires an API client but none is set. ErrBotAPINil = errors.New("bot api is nil") // ErrBotWebhookOptsEmptyPath reports that BotWebhookOpts.Path is empty. ErrBotWebhookOptsEmptyPath = errors.New("empty BotWebhookOpts.Path") // ErrBotWebhookOptsPathNoSlash reports that BotWebhookOpts.Path does not start with '/'. ErrBotWebhookOptsPathNoSlash = errors.New("BotWebhookOpts.Path must start with '/'") // ErrBotWebhookOptsPathHasQueryOrFragment reports that BotWebhookOpts.Path contains a query or fragment. ErrBotWebhookOptsPathHasQueryOrFragment = errors.New("BotWebhookOpts.Path must not contain query or fragment") // ErrBotWebhookOptsPathCollidesStatus reports that BotWebhookOpts.Path collides with the reserved /status endpoint. ErrBotWebhookOptsPathCollidesStatus = errors.New("BotWebhookOpts.Path must not be '/status' when status path is enabled") // ErrBotWebhookTLSFilesIncomplete reports that only one of the two TLS files was provided. ErrBotWebhookTLSFilesIncomplete = errors.New("you must specify both private and public keys") // ErrBotWebhookTLSFilesTooMany reports that more than two TLS files were provided. ErrBotWebhookTLSFilesTooMany = errors.New("too many files; you must specify only private and public keys") )
var ( // ErrProxySchemeEmpty reports that a configured proxy has no URL scheme. ErrProxySchemeEmpty = errors.New("proxy scheme is empty") // ErrProxySchemeUnsupported reports that a configured proxy uses an unsupported URL scheme. ErrProxySchemeUnsupported = errors.New("proxy scheme is unsupported") // ErrProxyHostEmpty reports that a configured proxy has no host. ErrProxyHostEmpty = errors.New("proxy host is empty") // ErrProxyPortOutOfRange reports that a proxy port is outside 1..65535. ErrProxyPortOutOfRange = errors.New("proxy port must be in range 1-65535") )
var ErrCmdArgCountMismatch = errors.New("command arg count mismatch")
ErrCmdArgCountMismatch is returned when the number of provided arguments is less than the number of required arguments.
var ErrCmdArgRegexpMismatch = errors.New("command arg regexp mismatch")
ErrCmdArgRegexpMismatch is returned when an argument fails regex validation.
var ErrConfigVersionMismatch = fmt.Errorf("config version mismatch: expected %d", ConfigVersion)
ErrConfigVersionMismatch reports that a config file declares a newer version than this library knows how to decode.
var ErrInvalidPayload = errors.New("invalid payload")
ErrInvalidPayload reports that a callback payload could not be decoded under the expected encoding (e.g. the compact format separator is missing).
var ErrInvalidPayloadType = errors.New("invalid payload type")
ErrInvalidPayloadType is returned when callback payload encoding type is unknown.
var ErrMiddlewareExecutorNil = errors.New("middleware executor is nil")
ErrMiddlewareExecutorNil reports an attempt to execute middleware without a callback.
var ErrTooManyCommands = errors.New("too many commands. max 100")
ErrTooManyCommands is returned when the total number of registered commands exceeds Telegram's limit of 100 bot commands per bot.
Telegram Bot API enforces this limit strictly. If exceeded, SetMyCommands will fail with a 400 error. This error helps catch the issue early during bot initialization.
Functions ¶
func AsInternalError ¶
AsInternalError marks err as internal-only so it will be logged but not sent to the user through the centralized handler error flow.
func AsUserError ¶
AsUserError marks err as safe to show to the user through the centralized handler error flow.
func IsInternalError ¶
IsInternalError reports whether err was explicitly marked as internal-only.
func IsUserError ¶
IsUserError reports whether err was explicitly marked as user-visible.
func LoadPrefixesFromEnv ¶
func LoadPrefixesFromEnv() []string
LoadPrefixesFromEnv returns the PREFIXES environment variable split by semicolon. Defaults to ["/"] if not set.
func SaveBotOptsFile ¶
func SaveBotOptsFile(codec BotOptsFileCodec, filename string, opts *BotOpts) error
SaveBotOptsFile encodes BotOpts with codec and writes the result to filename.
func SplitMessageText ¶
SplitMessageText splits plain text into Telegram-safe message chunks.
The function preserves the original text exactly: concatenating all returned chunks reconstructs text byte-for-byte. It prefers splitting at newlines or spaces within the Telegram message limit and falls back to hard rune-based splits when no separator is available.
Types ¶
type AnswerMessage ¶
type AnswerMessage struct {
// MessageID identifies the sent Telegram message.
MessageID int
// Text contains the text or caption sent with the message.
// For rich messages, it contains rendered HTML for v1 compatibility.
Text string
// RichHTML contains the rendered HTML of a rich message.
RichHTML string // Since: Bot API 10.2
// IsMedia reports whether the answer contains media.
IsMedia bool
// contains filtered or unexported fields
}
AnswerMessage represents a message sent or edited via MessageContext. It holds metadata to allow further editing or deletion.
func (*AnswerMessage) Delete ¶
func (m *AnswerMessage) Delete()
Delete removes the message associated with this AnswerMessage.
func (*AnswerMessage) Edit ¶
func (m *AnswerMessage) Edit(text string) *AnswerMessage
Edit replaces the text of the message without changing the keyboard or parse mode. Uses ParseNone (plain text).
func (*AnswerMessage) EditCaption ¶
func (m *AnswerMessage) EditCaption(text string) *AnswerMessage
EditCaption edits the caption of a media message using plain text.
func (*AnswerMessage) EditCaptionKeyboard ¶
func (m *AnswerMessage) EditCaptionKeyboard(text string, kb *InlineKeyboard) *AnswerMessage
EditCaptionKeyboard edits the caption of a media message with a new inline keyboard (plain text).
func (*AnswerMessage) EditCaptionKeyboardMarkdown ¶
func (m *AnswerMessage) EditCaptionKeyboardMarkdown(text string, kb *InlineKeyboard) *AnswerMessage
EditCaptionKeyboardMarkdown edits the caption of a media message with a new inline keyboard using MarkdownV2.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*AnswerMessage) EditCaptionMarkdown ¶
func (m *AnswerMessage) EditCaptionMarkdown(text string) *AnswerMessage
EditCaptionMarkdown edits the caption of a media message using MarkdownV2.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*AnswerMessage) EditMarkdown ¶
func (m *AnswerMessage) EditMarkdown(text string) *AnswerMessage
EditMarkdown replaces the text of the message using MarkdownV2 formatting.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here. Unescaped input may cause Telegram API errors or broken formatting.
func (*AnswerMessage) EditRich ¶
func (m *AnswerMessage) EditRich(blocks ...tgapi.InputRichBlock) *AnswerMessage
EditRich builds rich blocks and replaces the message content without changing its inline keyboard. It doesn't upload local files referenced with attach://.
Since: Bot API 10.2
func (*AnswerMessage) EditRichKeyboard ¶
func (m *AnswerMessage) EditRichKeyboard(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage
EditRichKeyboard builds rich blocks and replaces the message content and inline keyboard. It doesn't upload local files referenced with attach://.
Since: Bot API 10.2
type AppData ¶
type AppData any
AppData is the generic shared application data type injected into bots, plugins, and handlers.
Use it for long-lived shared dependencies such as database handles, service containers, API clients, or immutable configuration snapshots.
Example:
type MyDB struct { ... }
myDB := &MyDB{}
bot, err := NewBot[*MyDB](opts)
if err != nil {
return err
}
bot.SetAppData(myDB)
Use NoData if no shared application data is needed.
type AppDataLogger ¶
type AppDataLogger[T AppData] func(data T) sneklog.LoggerWriter
AppDataLogger builds a sneklog.LoggerWriter from injected application data.
Use it when shared application data exposes a log sink or adapter that should receive framework logs.
type Bot ¶
type Bot[T AppData] struct { // contains filtered or unexported fields }
Bot is the core Telegram bot instance.
Manages:
- API communication via tgapi
- Update processing pipeline (middleware → plugins)
- Background runners
- Logging and rate limiting
- Localization and draft message support
Runtime accessors are safe for concurrent use. Configure the bot before Run, RunWithContext, or RunWebhookWithContext. A Bot is single-use: after Run, RunWithContext, or RunWebhookWithContext returns, create a new Bot for the next session.
func NewBot ¶
NewBot creates and initializes a new Bot instance using the provided BotOpts.
Automatically:
- Creates API and Uploader clients
- Initializes structured logging (JSON stdout + optional file)
- Fetches bot username via GetMe()
- Sets up DraftProvider with random IDs
- Adds API and Uploader loggers to extraLoggers
func NewBotWithAPI ¶
NewBotWithAPI creates a Bot using a preconfigured API client. The Bot takes ownership of api and closes it from Bot.Close. API transport, retry, and rate-limit fields in opts do not reconfigure the supplied client.
func (*Bot[T]) AddAppDataLoggerWriter ¶
func (bot *Bot[T]) AddAppDataLoggerWriter(writer AppDataLogger[T]) *Bot[T]
AddAppDataLoggerWriter adds an app-data-backed logger writer to all loggers.
The writer will receive logs from:
- Main bot logger
- Request logger (if enabled)
- API and Uploader loggers
- Already registered plugin loggers
Call this after AddPlugins if plugin loggers should also receive the writer. Plugins registered later do not automatically inherit previously added writers; call AddAppDataLoggerWriter again after adding them.
Example:
bot.AddAppDataLoggerWriter(func(data *MyAppData) sneklog.LoggerWriter {
return data.QueryLogger()
})
func (*Bot[T]) AddMiddleware ¶
func (bot *Bot[T]) AddMiddleware(middleware ...Middleware[T]) *Bot[T]
AddMiddleware registers one or more middleware handlers.
Middleware are executed in order of increasing .order value before plugins. If two middleware have the same order, they are sorted lexicographically by name.
Middleware can:
- Modify or reject updates before they reach plugins
- Inject context (e.g., user auth state, rate limit status)
- Log, validate, or transform incoming data
Example:
bot.AddMiddleware(authMiddleware, rateLimitMiddleware)
Middleware with an empty name are skipped with a warning.
func (*Bot[T]) AddPlugins ¶
AddPlugins registers one or more plugins. Plugins are executed in registration order unless filtered by middleware.
Registration is a commit point for plugin configuration. The Bot stores plugin metadata internally, so plugins must be fully configured before they are passed here. Post-registration mutation through the original *Plugin is not a supported API, even if some changes appear to work due to shared maps.
func (*Bot[T]) AddPrefixes ¶
AddPrefixes adds one or more command prefixes (e.g., "/", "!"). The bot must have at least one prefix before any runtime entry point starts.
func (*Bot[T]) AddRunner ¶
AddRunner registers a background runner to execute concurrently with the bot.
Runners are goroutines that run independently of update processing. Common use cases:
- Periodic cleanup (e.g., expiring drafts, clearing temp files)
- Metrics collection or health checks
- Scheduled tasks (e.g., daily announcements)
Runners start from the bot runtime entry points, immediately after RunWithContext or RunWebhookWithContext begins.
Example:
bot.AddRunner(cleanupRunner)
Runners with an empty name are skipped with a warning.
func (*Bot[T]) AddUpdateType ¶
func (bot *Bot[T]) AddUpdateType(t ...tgapi.UpdateType) *Bot[T]
AddUpdateType adds one or more update types to the list. Does not overwrite existing types.
func (*Bot[T]) AutoGenerateCommands ¶
AutoGenerateCommands replaces plugin-defined commands in the private-chat, group-chat, and all-chat-administrators scopes.
Returns ErrTooManyCommands if the total number of commands exceeds 100. Returns any API error from Telegram (e.g., network issues, invalid scope).
Important: This method assumes the bot has been properly initialized and the API client is authenticated and ready.
Usage:
err := bot.AutoGenerateCommands()
if err != nil {
log.Fatal(err)
}
func (*Bot[T]) AutoGenerateCommandsForScope ¶
func (bot *Bot[T]) AutoGenerateCommandsForScope(scope *tgapi.BotCommandScope) error
AutoGenerateCommandsForScope registers all plugin-defined commands with Telegram's Bot API for the specified command scope. A nil scope selects Telegram's default scope.
The scope parameter defines where the commands should be available (e.g., private chats, group chats, chat administrators). See tgapi.BotCommandScope and its predefined types.
Returns ErrTooManyCommands if the total number of commands exceeds 100. Returns any API error from Telegram (e.g., network issues, invalid scope).
Usage:
privateScope := &tgapi.BotCommandScope{Type: tgapi.BotCommandScopePrivateType}
if err := bot.AutoGenerateCommandsForScope(privateScope); err != nil {
log.Fatal(err)
}
func (*Bot[T]) AutoGenerateCommandsForScopeWithContext ¶
func (bot *Bot[T]) AutoGenerateCommandsForScopeWithContext(ctx context.Context, scope *tgapi.BotCommandScope) error
AutoGenerateCommandsForScopeWithContext is the context-aware variant of AutoGenerateCommandsForScope.
func (*Bot[T]) AutoGenerateCommandsWithContext ¶
AutoGenerateCommandsWithContext is the context-aware variant of AutoGenerateCommands.
func (*Bot[T]) Close ¶
Close gracefully shuts down bot-owned resources.
Close shuts down, in order:
- The asynchronous observer dispatcher, after draining queued events
- Registered plugins via Plugin.Close
- Webhook logger (if initialized)
- Uploader logger resources
- API client internals, after pending API and upload requests complete
- RequestLogger (if enabled)
- Main logger
RunWithContext and RunWebhookWithContext do not call Close automatically. The caller is responsible for invoking Close after runtime returns to release these resources.
Close returns a joined error containing all shutdown failures, if any.
func (*Bot[T]) CloseRemote ¶
CloseRemote sends Telegram Bot API "close" request for the current bot instance using ctx for cancellation and deadlines.
This is separate from Bot.Close(), which only releases local resources.
func (*Bot[T]) CloseWebhook ¶
CloseWebhook removes the current Telegram webhook registration.
It is separate from Close, which only releases local resources. Call it before switching a deployment from webhook delivery to polling.
func (*Bot[T]) ExecRunners ¶
ExecRunners executes all runners registered on the Bot with context-based lifecycle management.
Execution semantics by configuration:
- every=0, async=true: Runs once in a goroutine; runtime shutdown waits for it.
- every=0, async=false: Runs once synchronously; warns if slower than 2 seconds.
- every>0, async=true: Runs in a loop with the configured interval until ctx.Done().
- every>0, async=false: Skipped with a warning (invalid configuration).
Background runners listen for ctx.Done() and gracefully shut down when the context is canceled.
This method is typically called once during bot startup from RunWithContext or RunWebhookWithContext.
func (*Bot[T]) GetAppData ¶
func (bot *Bot[T]) GetAppData() T
GetAppData returns the injected application data. If SetAppData was not called, it returns the zero value of T.
func (*Bot[T]) GetDraftProvider ¶
func (bot *Bot[T]) GetDraftProvider() *DraftProvider
GetDraftProvider returns the draft provider currently used by the bot.
func (*Bot[T]) GetLoggerLevel ¶
GetLoggerLevel returns the effective log level derived from the bot's debug flag.
func (*Bot[T]) GetObserver ¶
GetObserver returns the bot's event observer, or nil if no observer is set.
func (*Bot[T]) GetPayloadType ¶
func (bot *Bot[T]) GetPayloadType() BotPayloadType
GetPayloadType returns the bot's default callback payload encoding type.
func (*Bot[T]) GetRequestLogger ¶
GetRequestLogger returns the request-level logger, if configured.
func (*Bot[T]) GetSessionStore ¶
func (bot *Bot[T]) GetSessionStore() SessionStore
GetSessionStore returns the session store used for scene management.
func (*Bot[T]) GetUpdateOffset ¶
GetUpdateOffset returns the current update offset (thread-safe).
func (*Bot[T]) GetUpdateTypes ¶
func (bot *Bot[T]) GetUpdateTypes() []tgapi.UpdateType
GetUpdateTypes returns the list of update types the bot is configured to receive.
func (*Bot[T]) GetUploader ¶
GetUploader returns the underlying file uploader client.
func (*Bot[T]) GetWebhookLogger ¶
GetWebhookLogger returns the webhook logger, if configured.
func (*Bot[T]) L10n ¶
L10n translates a key in the given language. Returns key if translation not found.
func (*Bot[T]) Run ¶
Run starts the bot using a background context.
Equivalent to RunWithContext(context.Background()). Use this for simple bots where graceful shutdown is not required.
For production use, prefer RunWithContext to handle SIGINT/SIGTERM gracefully.
func (*Bot[T]) RunWebhook ¶
func (bot *Bot[T]) RunWebhook(opts *BotWebhookOpts, tlsFiles ...string) error
RunWebhook starts the webhook runtime with a background context.
It is shorthand for RunWebhookWithContext(context.Background(), opts, tlsFiles...).
func (*Bot[T]) RunWebhookWithContext ¶
func (bot *Bot[T]) RunWebhookWithContext(ctx context.Context, opts *BotWebhookOpts, tlsFiles ...string) error
RunWebhookWithContext registers the webhook and serves incoming updates until ctx is canceled.
The bot uses the same update queue, worker pool, runner startup, and single-use lifecycle guarantees as RunWithContext. When opts.AllowedUpdates is empty, the bot-level update types configured through SetUpdateTypes/AddUpdateType are used. When UseStatusPath is enabled, SecretToken must be non-empty so the operational endpoint is not left public.
When two TLS files are provided, the method serves HTTPS using the existing key-then-cert argument order.
func (*Bot[T]) RunWithContext ¶
RunWithContext starts the bot with a given context for graceful shutdown.
This is the main entry point for bot execution. It:
- Validates required configuration (prefixes, plugins)
- Starts all registered runners as background goroutines
- Begins polling for updates via Telegram's GetUpdates API
- Processes updates concurrently using a worker pool with size configurable via BotOpts.MaxWorkers
The context controls graceful shutdown. When canceled, the bot:
- Stops polling for new updates
- Finishes processing currently queued updates
- Waits for registered runners to exit
If you are switching an existing deployment from webhook delivery to polling, delete the current webhook first with CloseWebhook or tgapi.DeleteWebhook. Telegram keeps webhook delivery active until the webhook is removed.
RunWithContext does not close API, uploader, or logger resources on return. The caller must invoke Close after RunWithContext finishes.
A Bot is single-use. After RunWithContext returns, later calls return ErrBotAlreadyRun.
func (*Bot[T]) SetAppData ¶
SetAppData injects shared application data into the bot.
The data is accessible to commands, payload handlers, middleware, scenes, and runners through the generic type parameter T.
For shared dependencies such as *sql.DB, prefer using a pointer type as T. Value-typed application data is supported, but the bot warns once because handlers receive T by value.
func (*Bot[T]) SetDraftProvider ¶
func (bot *Bot[T]) SetDraftProvider(p *DraftProvider) *Bot[T]
SetDraftProvider replaces the default DraftProvider with a custom one. Useful for using LinearDraftIDGenerator to persist draft IDs across restarts.
func (*Bot[T]) SetErrorTemplate ¶
SetErrorTemplate sets the format string for error messages sent to users. Use "%s" to insert the error message. Example: "❌ Error: %s" → "❌ Error: Command not found".
func (*Bot[T]) SetL10n ¶
SetL10n sets the localization (i18n) provider for the bot.
The L10n instance must be pre-populated with translations. Translations are accessed via Bot.L10n(lang, key).
Replaces any previously set L10n instance.
func (*Bot[T]) SetObserver ¶
SetObserver sets an event observer for instrumentation.
func (*Bot[T]) SetPayloadType ¶
func (bot *Bot[T]) SetPayloadType(t BotPayloadType) *Bot[T]
SetPayloadType sets the default payload encoding type used for callback data. JSON stores payload as a string: `{"cmd":"command","args":[...]}`. Base64 stores the same JSON encoded as a Base64URL string. InlineKeyboard.SetPayloadType may override this value for an individual keyboard.
func (*Bot[T]) SetRequestLogger ¶
SetRequestLogger replaces the request-level logger before runtime starts.
func (*Bot[T]) SetSceneScopePriority ¶
func (bot *Bot[T]) SetSceneScopePriority(priority []SceneScope) *Bot[T]
SetSceneScopePriority sets the lookup order for resolving active scene sessions.
func (*Bot[T]) SetSessionStore ¶
func (bot *Bot[T]) SetSessionStore(store SessionStore) *Bot[T]
SetSessionStore replaces the session store used for scene management.
func (*Bot[T]) SetStrictPayloadType ¶
SetStrictPayloadType enables or disables strict callback payload decoding. When enabled, callback payloads must match the bot's default payload type.
func (*Bot[T]) SetUpdateOffset ¶
SetUpdateOffset sets the update offset for next GetUpdates call (thread-safe).
func (*Bot[T]) SetUpdateTypes ¶
func (bot *Bot[T]) SetUpdateTypes(t ...tgapi.UpdateType) *Bot[T]
SetUpdateTypes sets the list of update types the bot will request from Telegram. Overwrites any previously set types.
func (*Bot[T]) SetWebhookLogger ¶
SetWebhookLogger replaces the webhook logger before runtime starts.
func (*Bot[T]) Updates ¶
Updates fetches new updates from Telegram API using long polling. It respects the bot's current update offset and automatically advances it after successful retrieval. The method supports selective update types through AllowedUpdates and includes optional request logging.
Parameters:
- ctx: request context used to cancel the in-flight long polling request
Returns:
- []tgapi.Update: slice of received updates (empty if none available)
- error: any error encountered during the API call
Behavior:
- Uses the bot's current update offset (via GetUpdateOffset)
- Requests updates with the timeout configured via PollTimeout
- Filters updates by types specified in bot.GetUpdateTypes()
- Logs raw update JSON if RequestLogger is configured
- Automatically updates the offset to the last received update ID + 1
- Returns all received updates (empty slice if none)
Note: This is a blocking call that waits up to the configured PollTimeout for new updates, unless ctx is canceled earlier. For non-blocking behavior, consider using webhooks instead.
Example:
updates, err := bot.Updates(ctx)
if err != nil {
log.Fatal(err)
}
for _, update := range updates {
// process update
}
func (*Bot[T]) UpdatesIter ¶
UpdatesIter fetches updates once and yields each update in order.
If fetching updates fails, the iterator yields the error once with a zero update and then stops.
type BotOpts ¶
type BotOpts struct {
// Token is the Telegram bot token (required).
Token string
// UpdateTypes is a list of update types to listen for.
// Example: "["message", "edited_message", "callback_query"]"
// Defaults to empty (Telegram will return all types).
UpdateTypes []tgapi.UpdateType
// Debug enables debug-level logging.
Debug bool
// ErrorTemplate is the format string used to wrap error messages sent to users.
// Use "%s" to insert the actual error. Example: "❌ Error: %s"
ErrorTemplate string
// Prefixes is a list of command prefixes (e.g., ["/", "!"]).
// Defaults to ["/"] if not set via environment.
Prefixes []string
// LoggerBasePath is the directory where log files are written.
// Defaults to "./".
LoggerBasePath string
// UseRequestLogger enables detailed logging of all Telegram API requests.
UseRequestLogger bool
// WriteToFile enables writing logs to files (main.log and requests.log).
WriteToFile bool
// UseTestServer uses Telegram's test server (https://api.test.telegram.org).
UseTestServer bool
// APIURL overrides the default Telegram API endpoint (useful for proxies or self-hosted).
APIURL string
// RateLimit is the maximum number of API requests per second.
// Telegram allows up to 30 req/s for most bots. Defaults to 30.
RateLimit int
// DropRateLimitOverflow rejects outgoing Telegram API requests immediately when
// rate-limit capacity is unavailable instead of waiting for capacity.
DropRateLimitOverflow bool
// StrictPayloadType disables callback payload fallback decoding.
// When enabled, the bot accepts only the configured default payload type.
StrictPayloadType bool
// MaxWorkers is the maximum number of update handlers that may run concurrently.
MaxWorkers int
// PollTimeout is the long-polling timeout in seconds for getUpdates.
// Defaults to 30. Telegram allows 0..50; values outside that range are accepted
// by the bot but rejected by Telegram at runtime.
PollTimeout int
// FileConfigVersion stores the version declared by the config file used to
// load these options.
//
// It is zero when the options were not loaded from a versioned file.
FileConfigVersion int
// LogFormat selects text or JSON output for bot-managed loggers.
LogFormat utils.LogFormat
// LogFormatter customizes bot-managed logger writers when supported.
LogFormatter *sneklog.Formatter
// ProxyURL routes Telegram API requests through an HTTP, HTTPS, SOCKS5, or SOCKS5H proxy.
// When nil, the HTTP client uses proxy settings from the environment.
ProxyURL *url.URL
}
BotOpts holds configuration options for initializing a Bot.
Values are loaded from environment variables via LoadOptsFromEnv(). Use &BotOpts{} to create a value and set fields manually.
func LoadBotOptsFile ¶
func LoadBotOptsFile(codec BotOptsFileCodec, filename string) (*BotOpts, error)
LoadBotOptsFile reads a config file, expands env placeholders, and decodes BotOpts.
func LoadOptsFromEnv ¶
func LoadOptsFromEnv() *BotOpts
LoadOptsFromEnv loads BotOpts from environment variables.
Environment variables:
- TG_TOKEN: Bot token (required)
- UPDATE_TYPES: semicolon-separated update types (e.g., "message;callback_query")
- DEBUG: "true" to enable debug logging
- ERROR_TEMPLATE: format string for error messages (e.g., "❌ %s")
- PREFIXES: semicolon-separated prefixes (e.g., "/;!bot")
- LOGGER_BASE_PATH: directory for log files (default: "./")
- USE_REQ_LOG: "true" to enable request logging
- WRITE_TO_FILE: "true" to write logs to files
- USE_TEST_SERVER: "true" to use Telegram test server
- API_URL: custom API endpoint
- RATE_LIMIT: max requests per second (default: 30)
- DROP_RL_OVERFLOW: "true" to reject rate-limited API requests instead of waiting
- STRICT_PAYLOAD_TYPE: "true" to reject callback payloads encoded in a different format
- MAX_WORKERS: maximum number of concurrent update handlers (default: 32)
- POLL_TIMEOUT: long-polling timeout in seconds for getUpdates (default: 30)
- LOG_FORMAT: logger output format, "text" or "json" (default: "text")
Returns a populated BotOpts. NewBot validates required fields and returns ErrTokenRequired when TG_TOKEN is missing.
func (*BotOpts) SetAPIURL ¶
SetAPIURL overrides the default Telegram API endpoint (useful for proxies or self-hosted). If not set, defaults to "https://api.telegram.org".
func (*BotOpts) SetDropRateLimitOverflow ¶
SetDropRateLimitOverflow configures outgoing Telegram API requests to fail immediately when rate-limit capacity is unavailable. Default is false.
func (*BotOpts) SetErrorTemplate ¶
SetErrorTemplate sets the format string for error messages sent to users. Use "%s" to insert the actual error. Example: "❌ Error: %s" If not set, defaults to "%s".
func (*BotOpts) SetLogFormat ¶
SetLogFormat sets the output format used by bot-managed loggers.
func (*BotOpts) SetLogFormatter ¶
SetLogFormatter sets the formatter used by bot-managed logger writers.
func (*BotOpts) SetLoggerBasePath ¶
SetLoggerBasePath sets the directory where log files are written. Defaults to "./".
func (*BotOpts) SetMaxWorkers ¶
SetMaxWorkers sets the maximum number of concurrent update handlers. Must be called before NewBot, as the value is captured during bot creation.
The optimal value depends on your bot's workload:
- For I/O-bound handlers (e.g., database queries, external API calls), you may need more workers, but be mindful of downstream service limits.
- For CPU-bound handlers, keep workers close to the number of CPU cores.
Recommended starting points (adjust based on profiling and monitoring):
- Small to medium bots with fast handlers: 16–32
- Medium to large bots with fast handlers: 32–64
- Large bots with heavy I/O: 64–128 (ensure your infrastructure can handle it)
The default is 32. Monitor queue length and processing latency to fine-tune.
func (*BotOpts) SetPollTimeout ¶
SetPollTimeout sets the long-polling timeout in seconds for getUpdates. Defaults to 30. Telegram accepts 0..50.
func (*BotOpts) SetPrefixes ¶
SetPrefixes sets the command prefixes (e.g., "/", "!"). If not set via environment, defaults to ["/"].
func (*BotOpts) SetProxyURL ¶
SetProxyURL sets the HTTP, HTTPS, SOCKS5, or SOCKS5H proxy used for Telegram API requests. A nil URL restores proxy discovery from the environment.
func (*BotOpts) SetRateLimit ¶
SetRateLimit sets the maximum number of API requests per second. Telegram allows up to 30 req/s for most bots. Defaults to 30.
func (*BotOpts) SetStrictPayloadType ¶
SetStrictPayloadType enables or disables strict callback payload decoding. When enabled, the bot accepts only the configured default payload type.
func (*BotOpts) SetUpdateTypes ¶
func (opts *BotOpts) SetUpdateTypes(types ...tgapi.UpdateType) *BotOpts
SetUpdateTypes sets the list of update types to listen for. If empty (default), Telegram will return all update types. Example: opts.SetUpdateTypes("message", "callback_query").
func (*BotOpts) SetUseRequestLogger ¶
SetUseRequestLogger enables detailed logging of all Telegram API requests. Default is false.
func (*BotOpts) SetUseTestServer ¶
SetUseTestServer enables using Telegram's test server (https://api.telegram.org/bot<token>/test). Default is false.
func (*BotOpts) SetWriteToFile ¶
SetWriteToFile enables writing logs to files (main.log and requests.log). Default is false.
type BotOptsFileCodec ¶
type BotOptsFileCodec interface {
FromBytes([]byte) (*BotOpts, error)
ToBytes(*BotOpts) ([]byte, error)
Load(filename string) (*BotOpts, error)
Save(filename string, opts *BotOpts) error
}
BotOptsFileCodec decodes and encodes BotOpts file formats.
type BotOptsFileJSON ¶
type BotOptsFileJSON struct {
// Version identifies the JSON configuration format version.
Version int `json:"version"`
// Token is the Telegram bot token.
Token string `json:"token"`
// UpdateTypes limits the update kinds requested from Telegram.
UpdateTypes []tgapi.UpdateType `json:"update_types"`
// Debug enables debug logging.
Debug bool `json:"debug"`
// ErrorTemplate formats user-facing handler errors.
ErrorTemplate string `json:"error_template"`
// Prefixes contains accepted command prefixes.
Prefixes []string `json:"prefixes"`
// Logger contains file logging options.
Logger botOptsFileJSONLogger `json:"logger"`
// API contains Telegram client and rate-limit options.
API botOptsFileJSONAPI `json:"api"`
// StrictPayloadType requires callback payloads to use the configured encoding.
StrictPayloadType bool `json:"strict_payload_type"`
// MaxWorkers limits concurrent update handlers.
MaxWorkers int `json:"max_workers"`
// Proxy configures the Telegram API proxy.
Proxy BotOptsFileJSONProxy `json:"proxy"`
}
BotOptsFileJSON is the JSON file representation of BotOpts.
type BotOptsFileJSONCodec ¶
type BotOptsFileJSONCodec struct{}
BotOptsFileJSONCodec encodes and decodes BotOpts using BotOptsFileJSON.
func (BotOptsFileJSONCodec) EscapeEnv ¶
func (codec BotOptsFileJSONCodec) EscapeEnv(s string) string
EscapeEnv escapes an environment value for use inside a JSON string.
func (BotOptsFileJSONCodec) FromBytes ¶
func (codec BotOptsFileJSONCodec) FromBytes(data []byte) (*BotOpts, error)
FromBytes decodes BotOpts from JSON file bytes.
func (BotOptsFileJSONCodec) Load ¶
func (codec BotOptsFileJSONCodec) Load(filename string) (*BotOpts, error)
Load reads BotOpts from a JSON config file.
type BotOptsFileJSONProxy ¶
type BotOptsFileJSONProxy struct {
// Scheme is one of http, https, socks5, or socks5h.
Scheme string `json:"scheme"`
// Host is the proxy hostname or IP address without a port.
Host string `json:"host"`
// Port is the proxy TCP port in the range 1..65535.
Port int `json:"port"`
// User is the optional proxy authentication username.
User string `json:"user"`
// Password is the optional proxy authentication password.
Password string `json:"password"`
}
BotOptsFileJSONProxy is the JSON representation of a Telegram API proxy.
type BotPayloadType ¶
type BotPayloadType string
BotPayloadType defines the serialization format for callback data payloads.
const ( // BotPayloadBase64 encodes callback data as a Base64 string. BotPayloadBase64 BotPayloadType = "base64" // BotPayloadJSON encodes callback data as a JSON string. BotPayloadJSON BotPayloadType = "json" // BotPayloadCompact encodes callback data as a compact delimited string. BotPayloadCompact BotPayloadType = "compact" // BotPayloadCompactBase64 encodes compact callback data as a Base64 string. BotPayloadCompactBase64 BotPayloadType = "compact-base64" )
type BotWebhookOpts ¶
type BotWebhookOpts struct {
// Path is the local HTTP route that receives Telegram updates.
Path string
// LocalPort is the TCP port used by the webhook server.
LocalPort int
// UseStatusPath enables the authenticated /status endpoint.
UseStatusPath bool
// URL is the public base URL Telegram uses for delivery.
URL string
// Certificate contains a self-signed public certificate to upload.
Certificate []byte
// IPAddress fixes the destination IP used by Telegram.
IPAddress string
// MaxConnections limits simultaneous Telegram webhook connections to 1–100.
MaxConnections int8
// AllowedUpdates limits the update kinds delivered to the webhook.
AllowedUpdates []tgapi.UpdateType
// DropPendingUpdates requests deletion of queued updates during registration.
DropPendingUpdates bool
// SecretToken authenticates Telegram requests and the optional status endpoint.
SecretToken string
}
BotWebhookOpts configures Telegram webhook registration and the local HTTP server.
func NewBotWebhookOpts ¶
func NewBotWebhookOpts() *BotWebhookOpts
NewBotWebhookOpts returns webhook options with the default path, local port, and max connections.
func (*BotWebhookOpts) MustLoadCertificate ¶
func (opts *BotWebhookOpts) MustLoadCertificate(filename string) *BotWebhookOpts
MustLoadCertificate loads a webhook certificate from disk and panics on failure.
func (*BotWebhookOpts) SetAllowedUpdates ¶
func (opts *BotWebhookOpts) SetAllowedUpdates(updates ...tgapi.UpdateType) *BotWebhookOpts
SetAllowedUpdates sets the Telegram update types that should be delivered to the webhook.
func (*BotWebhookOpts) SetCertificate ¶
func (opts *BotWebhookOpts) SetCertificate(certificate []byte) *BotWebhookOpts
SetCertificate sets the self-signed webhook certificate bytes to upload.
func (*BotWebhookOpts) SetDropPendingUpdates ¶
func (opts *BotWebhookOpts) SetDropPendingUpdates(drop bool) *BotWebhookOpts
SetDropPendingUpdates configures whether Telegram should drop pending updates while setting the webhook.
func (*BotWebhookOpts) SetIPAddress ¶
func (opts *BotWebhookOpts) SetIPAddress(ip string) *BotWebhookOpts
SetIPAddress sets the fixed IP address Telegram should use for webhook delivery.
func (*BotWebhookOpts) SetLocalPort ¶
func (opts *BotWebhookOpts) SetLocalPort(port int) *BotWebhookOpts
SetLocalPort sets the local HTTP port used by the webhook server.
func (*BotWebhookOpts) SetMaxConnections ¶
func (opts *BotWebhookOpts) SetMaxConnections(max int8) *BotWebhookOpts
SetMaxConnections sets Telegram's maximum number of simultaneous webhook connections.
func (*BotWebhookOpts) SetPath ¶
func (opts *BotWebhookOpts) SetPath(path string) *BotWebhookOpts
SetPath sets the local HTTP path that receives Telegram webhook requests.
func (*BotWebhookOpts) SetSecretToken ¶
func (opts *BotWebhookOpts) SetSecretToken(secretToken string) *BotWebhookOpts
SetSecretToken sets the secret token expected in Telegram webhook requests. The same token is also required to access /status when that endpoint is enabled.
func (*BotWebhookOpts) SetURL ¶
func (opts *BotWebhookOpts) SetURL(url string) *BotWebhookOpts
SetURL sets the public base URL Telegram should call for incoming updates.
func (*BotWebhookOpts) SetUseStatusPath ¶
func (opts *BotWebhookOpts) SetUseStatusPath(use bool) *BotWebhookOpts
SetUseStatusPath enables or disables the optional /status endpoint. A non-empty SecretToken is required when this endpoint is enabled.
type CallbackData ¶
type CallbackData struct {
// Command is the command name used for payload routing.
Command string `json:"cmd"`
// Args contains the string arguments passed to the payload handler.
Args []string `json:"args"`
}
CallbackData represents the structured payload sent when an inline button with callback data is pressed.
This structure is serialized to JSON and sent to the bot as a string. The bot should parse this back to determine the command and arguments.
Example:
{"cmd":"delete_user","args":["123","confirm"]}
func NewCallbackData ¶
func NewCallbackData(command string, args ...any) CallbackData
NewCallbackData creates a new CallbackData instance with the given command and args.
All args are converted to strings using fmt.Sprint. This is safe for primitives (int, string, bool, float64) but may not serialize complex structs meaningfully.
Use this to build callback payloads for bot command routing.
func (CallbackData) Encode ¶
func (d CallbackData) Encode(t BotPayloadType) (string, error)
Encode serializes the CallbackData according to the specified payload type. Supported types: BotPayloadJSON, BotPayloadBase64, BotPayloadCompact, and BotPayloadCompactBase64. For unknown types, returns an empty string.
func (CallbackData) ToBase64 ¶
func (d CallbackData) ToBase64() string
ToBase64 serializes the CallbackData to a JSON string and then encodes it as Base64. Returns an empty string if serialization or encoding fails.
func (CallbackData) ToCompact ¶
func (d CallbackData) ToCompact() string
ToCompact serializes the CallbackData to a compact delimited string. Returns an empty string if serialization fails.
The compact format coalesces "no args" with "single empty arg" — both produce "cmd|" and decode back to nil args. Use ToJSON or ToBase64 when that distinction must be preserved.
func (CallbackData) ToCompactBase64 ¶
func (d CallbackData) ToCompactBase64() string
ToCompactBase64 serializes the CallbackData to compact text and then encodes it as Base64. Returns an empty string if serialization or encoding fails.
func (CallbackData) ToJSON ¶
func (d CallbackData) ToJSON() string
ToJSON serializes the CallbackData to a JSON string. Returns an empty string if serialization fails.
type Command ¶
type Command[T AppData] struct { // contains filtered or unexported fields }
Command represents a bot command with arguments, description, and executor. Can be registered in a Plugin and optionally skipped from auto-generation.
func NewCommand ¶
func NewCommand[T any](command string, exec CommandExecutor[T], args ...CommandArg) *Command[T]
NewCommand creates a new Command with the given identifier, executor, and arguments.
The identifier is used as the routing key for both /-prefixed commands and callback payloads — the difference is registration: pass the result to Plugin.AddCommand/Plugin.Command for message routing, or to Plugin.AddPayload/Plugin.Payload for callback_data routing.
For /-commands the identifier must not include the leading slash (e.g. "start", not "/start") and should match [_a-z0-9]{1,32} to satisfy Telegram's BotCommand validation. Payload identifiers may use any bytes that fit Telegram's callback_data limit, though the configured payload encoding may impose its own restrictions.
func (*Command[T]) SetDescription ¶
SetDescription sets the human-readable description of the command.
func (*Command[T]) SetEphemeral ¶
SetEphemeral controls whether Telegram treats the command as ephemeral.
Since: Bot API 10.2
func (*Command[T]) SkipCommandAutoGen ¶
SkipCommandAutoGen marks this command to be excluded from auto-generated help menus.
func (*Command[T]) Use ¶
func (c *Command[T]) Use(m Middleware[T]) *Command[T]
Use adds a middleware to the command's execution chain. Middlewares are executed in the order they are added.
type CommandArg ¶
type CommandArg struct {
// contains filtered or unexported fields
}
CommandArg defines a single argument for a command, including type, regex, and whether it is required.
func NewCommandArg ¶
func NewCommandArg(text string) CommandArg
NewCommandArg creates an optional argument without value validation.
func (CommandArg) SetRequired ¶
func (c CommandArg) SetRequired() CommandArg
SetRequired marks this argument as required. Returns the receiver for method chaining.
func (CommandArg) SetValueType ¶
func (c CommandArg) SetValueType(t CommandValueType) CommandArg
SetValueType sets expected value type and switches built-in validation regexp.
type CommandExecutor ¶
type CommandExecutor[T AppData] func(ctx *MessageContext, dbContext T) error
CommandExecutor is the function type that executes a command. It receives the message context and injected application data. Returning a non-nil error routes it through the bot's error handler.
type CommandGroup ¶
type CommandGroup[T any] struct { // contains filtered or unexported fields }
CommandGroup builds a set of commands with a shared name prefix and middleware.
func NewCommandGroup ¶
func NewCommandGroup[T any](prefix string) *CommandGroup[T]
NewCommandGroup creates a command group that prefixes every added command.
func (*CommandGroup[T]) AddCommand ¶
func (g *CommandGroup[T]) AddCommand(cmd *Command[T]) *CommandGroup[T]
AddCommand adds a prefixed copy of cmd to the group.
func (*CommandGroup[T]) Build ¶
func (g *CommandGroup[T]) Build() []*Command[T]
Build returns command copies with group middleware prepended.
func (*CommandGroup[T]) Use ¶
func (g *CommandGroup[T]) Use(m Middleware[T]) *CommandGroup[T]
Use adds middleware that runs before each command's own middleware.
type CommandScopeUpdateError ¶
type CommandScopeUpdateError struct {
// UpdatedScopes contains scopes changed before the failure.
UpdatedScopes []tgapi.BotCommandScopeType
// FailedScope identifies the scope whose update failed.
FailedScope tgapi.BotCommandScopeType
// Err is the Telegram API error for FailedScope.
Err error
}
CommandScopeUpdateError describes a failed multi-scope command update. UpdatedScopes lists scopes successfully changed before FailedScope failed.
func (*CommandScopeUpdateError) Error ¶
func (e *CommandScopeUpdateError) Error() string
Error returns a human-readable partial-update description.
func (*CommandScopeUpdateError) Unwrap ¶
func (e *CommandScopeUpdateError) Unwrap() []error
Unwrap exposes both the partial-update sentinel and the underlying API error.
type CommandValueType ¶
type CommandValueType string
CommandValueType defines the expected type of command argument.
const ( // CommandValueString expects any non-empty string. CommandValueString CommandValueType = "string" // CommandValueInt expects a decimal integer (digits only). CommandValueInt CommandValueType = "int" // CommandValueBool expects an exact "true" or "false". CommandValueBool CommandValueType = "bool" // CommandValueAny accepts any input without validation. CommandValueAny CommandValueType = "any" )
type Draft ¶
type Draft struct {
// ID uniquely identifies the draft within its provider.
ID uint64
// Message contains the current draft text.
Message string
// contains filtered or unexported fields
}
Draft represents a single message draft that can be edited and flushed.
Drafts are safe to use from a single goroutine. Multiple goroutines must synchronize access manually.
Drafts are automatically removed from the provider's map when Flush() succeeds.
func (*Draft) Clear ¶
func (d *Draft) Clear()
Clear resets the draft's message content to empty string.
Does not affect server-side draft — use Flush() for that.
func (*Draft) Delete ¶
func (d *Draft) Delete()
Delete removes the draft from its provider and clears its content.
You may call it manually if you want to cancel a draft without sending it.
func (*Draft) Flush ¶
Flush sends the draft as a final message and clears it locally.
If successful:
- The message is sent to Telegram.
- The draft's content is cleared.
- The draft is removed from the provider's map.
If an error occurs:
- The message is NOT sent.
- The draft remains in the provider and retains its content.
- You can call Flush() again to retry.
If the draft is empty, Flush() returns nil without calling the API.
func (*Draft) GetMessage ¶
GetMessage returns the current content of the draft.
Useful for inspection, logging, or validation before flushing.
func (*Draft) Push ¶
Push appends text to the draft and attempts to update the server-side draft.
Returns an error if the Telegram API rejects the update (e.g., due to network issues). The draft's Message field is always updated, even if the API call fails.
Use this method to build the message incrementally.
func (*Draft) SetChat ¶
SetChat overrides the draft's target chat and message thread.
This is useful for sending a draft to a different chat than the provider's default.
func (*Draft) SetEntities ¶
func (d *Draft) SetEntities(entities []tgapi.MessageEntity) *Draft
SetEntities replaces the draft's message entities.
The entities slice is copied.
type DraftProvider ¶
type DraftProvider struct {
// contains filtered or unexported fields
}
DraftProvider manages a collection of Drafts and a shared draft ID generator.
DraftProvider is safe for concurrent use.
func NewLinearDraftProvider ¶
func NewLinearDraftProvider(api *tgapi.API, startValue uint64) *DraftProvider
NewLinearDraftProvider creates a new DraftProvider using linear (incrementing) draft IDs.
startValue is the initial value for the counter. Use 0 for fresh start, or a known value to resume from persisted state.
This is useful when you need to store draft IDs externally (e.g., in a database) and want to reconstruct drafts after restart.
func NewRandomDraftProvider ¶
func NewRandomDraftProvider(api *tgapi.API) *DraftProvider
NewRandomDraftProvider creates a DraftProvider using non-cryptographic random IDs. Zero values and collisions with active drafts are retried.
func (*DraftProvider) FlushAll ¶
func (p *DraftProvider) FlushAll() error
FlushAll sends all pending drafts as final messages and clears them.
If one or more drafts fail to send, FlushAll still attempts all drafts and returns the first encountered error.
After successful flush, each draft is removed from the provider and cleared.
type ErrorEvent ¶
type ErrorEvent struct {
// UpdateID identifies the Telegram update when available.
UpdateID int
// UpdateType identifies the normalized update kind when available.
UpdateType tgapi.UpdateType
// Plugin names the component that reported the error.
Plugin string
// HandlerKind classifies the failing handler or runtime component.
HandlerKind HandlerEventKind
// HandlerName identifies the failing handler within its kind.
HandlerName string
// FromID identifies the originating user when available.
FromID int64
// ChatID identifies the originating chat when available.
ChatID int64
// Err is the reported error.
Err error
// UserFacing reports whether Err is safe to show to the user.
UserFacing bool
}
ErrorEvent describes an error routed through framework error handling.
type Event ¶
type Event interface {
// contains filtered or unexported methods
}
Event is the marker interface implemented by all observer runtime events.
type HandlerEventKind ¶
type HandlerEventKind string
HandlerEventKind identifies the kind of handler observed by runtime events.
const ( // HandlerCommandKind identifies a command handler. HandlerCommandKind HandlerEventKind = "command" // HandlerMessageKind identifies a message fallback handler. HandlerMessageKind HandlerEventKind = "message" // HandlerMiddlewareKind identifies middleware execution. HandlerMiddlewareKind HandlerEventKind = "middleware" // HandlerPayloadKind identifies a callback payload handler. HandlerPayloadKind HandlerEventKind = "payload" // HandlerUpdateKind identifies a generic update handler. HandlerUpdateKind HandlerEventKind = "update" // HandlerRunnerKind identifies a background runner execution. HandlerRunnerKind HandlerEventKind = "runner" // HandlerPollingKind identifies polling and getUpdates runtime work. HandlerPollingKind HandlerEventKind = "polling" // HandlerSceneKind identifies a scene runtime handler wrapper. HandlerSceneKind HandlerEventKind = "scene" // HandlerSceneStepKind identifies a scene step handler. HandlerSceneStepKind HandlerEventKind = "scene_step" // HandlerSceneCommandKind identifies a scene-local command handler. HandlerSceneCommandKind HandlerEventKind = "scene_command" // HandlerScenePayloadKind identifies a scene-local callback payload handler. HandlerScenePayloadKind HandlerEventKind = "scene_payload" // HandlerSceneMessageKind identifies a scene message fallback handler. HandlerSceneMessageKind HandlerEventKind = "scene_message" )
type HandlerFinishedEvent ¶
type HandlerFinishedEvent struct {
// UpdateID identifies the Telegram update.
UpdateID int
// UpdateType identifies the normalized update kind.
UpdateType tgapi.UpdateType
// Plugin names the plugin that owns the handler.
Plugin string
// HandlerKind classifies the handler.
HandlerKind HandlerEventKind
// HandlerName identifies the handler within its plugin and kind.
HandlerName string
// FromID identifies the originating user when available.
FromID int64
// ChatID identifies the originating chat when available.
ChatID int64
// Duration is the handler execution time.
Duration time.Duration
// Err is the error returned or recovered from the handler.
Err error
// UserFacing reports whether Err is safe to show to the user.
UserFacing bool
}
HandlerFinishedEvent describes a handler that has completed.
type HandlerStartedEvent ¶
type HandlerStartedEvent struct {
// UpdateID identifies the Telegram update.
UpdateID int
// UpdateType identifies the normalized update kind.
UpdateType tgapi.UpdateType
// Plugin names the plugin that owns the handler.
Plugin string
// HandlerKind classifies the handler.
HandlerKind HandlerEventKind
// HandlerName identifies the handler within its plugin and kind.
HandlerName string
// FromID identifies the originating user when available.
FromID int64
// ChatID identifies the originating chat when available.
ChatID int64
}
HandlerStartedEvent describes a handler about to execute.
type InlineKeyboard ¶
type InlineKeyboard struct {
// CurrentLine is the row currently being built.
CurrentLine extypes.Slice[tgapi.InlineKeyboardButton]
// Lines contains completed keyboard rows.
Lines [][]tgapi.InlineKeyboardButton
// contains filtered or unexported fields
}
InlineKeyboard is a stateful builder for constructing Telegram inline keyboard layouts.
Buttons are added row-by-row. When a row reaches maxRow, it is automatically flushed. Call AddLine() to manually end a row, or Get() to finalize and retrieve the markup.
The keyboard is not thread-safe. Build it in a single goroutine.
func NewInlineKeyboard ¶
func NewInlineKeyboard(payloadType BotPayloadType, maxRow int) *InlineKeyboard
NewInlineKeyboard creates a keyboard builder with the specified payload encoding and a positive maximum number of buttons per row.
Use NewInlineKeyboardJSON or NewInlineKeyboardBase64 for the common cases.
func NewInlineKeyboardBase64 ¶
func NewInlineKeyboardBase64(maxRow int) *InlineKeyboard
NewInlineKeyboardBase64 creates a keyboard builder with a positive maximum number of buttons per row, using Base64 encoding for button payloads.
Example: NewInlineKeyboardBase64(3) creates a keyboard with at most 3 buttons per line.
func NewInlineKeyboardCompact ¶
func NewInlineKeyboardCompact(maxRow int) *InlineKeyboard
NewInlineKeyboardCompact creates a keyboard builder using compact callback payloads.
func NewInlineKeyboardCompactBase64 ¶
func NewInlineKeyboardCompactBase64(maxRow int) *InlineKeyboard
NewInlineKeyboardCompactBase64 creates a keyboard builder using Base64-encoded compact payloads.
func NewInlineKeyboardJSON ¶
func NewInlineKeyboardJSON(maxRow int) *InlineKeyboard
NewInlineKeyboardJSON creates a keyboard builder with a positive maximum number of buttons per row.
Example: NewInlineKeyboardJSON(3) creates a keyboard with at most 3 buttons per line.
func (*InlineKeyboard) AddButton ¶
func (in *InlineKeyboard) AddButton(b InlineKeyboardButtonBuilder) *InlineKeyboard
AddButton adds a button pre-configured via InlineKeyboardButtonBuilder. This is the most flexible way to create buttons with custom emoji, style, URL, and callback.
func (*InlineKeyboard) AddCallbackButton ¶
func (in *InlineKeyboard) AddCallbackButton(text, cmd string, args ...any) *InlineKeyboard
AddCallbackButton adds a button that sends a structured callback payload to the bot. The command and args are serialized according to the current payloadType.
func (*InlineKeyboard) AddCallbackButtonStyle ¶
func (in *InlineKeyboard) AddCallbackButtonStyle(text string, style tgapi.KeyboardButtonStyle, cmd string, args ...any) *InlineKeyboard
AddCallbackButtonStyle adds a styled callback button. Style affects visual appearance; callback data is sent to bot on press.
func (*InlineKeyboard) AddLine ¶
func (in *InlineKeyboard) AddLine() *InlineKeyboard
AddLine manually ends the current row and starts a new one. If the current row is empty, nothing happens.
func (*InlineKeyboard) AddURLButton ¶
func (in *InlineKeyboard) AddURLButton(text, url string) *InlineKeyboard
AddURLButton adds a button that opens a URL when pressed. No callback data is attached.
func (*InlineKeyboard) AddURLButtonStyle ¶
func (in *InlineKeyboard) AddURLButtonStyle(text string, style tgapi.KeyboardButtonStyle, url string) *InlineKeyboard
AddURLButtonStyle adds a button with a visual style that opens a URL. Style must be one of: ButtonStyleDanger, ButtonStyleSuccess, ButtonStylePrimary.
func (*InlineKeyboard) Get ¶
func (in *InlineKeyboard) Get() (*tgapi.ReplyMarkup, error)
Get finalizes the keyboard and returns a tgapi.ReplyMarkup. Automatically flushes the current line if not empty.
Returns a pointer to a ReplyMarkup suitable for use with tgapi.SendMessage.
func (*InlineKeyboard) GetMaxRow ¶
func (in *InlineKeyboard) GetMaxRow() int
GetMaxRow returns the maximum number of buttons per row, or zero in explicit unlimited mode.
func (*InlineKeyboard) GetPayloadType ¶
func (in *InlineKeyboard) GetPayloadType() BotPayloadType
GetPayloadType returns the keyboard-local callback payload encoding type.
func (*InlineKeyboard) SetMaxRow ¶
func (in *InlineKeyboard) SetMaxRow(maxRow int) *InlineKeyboard
SetMaxRow sets the positive number of buttons appended to a row before the keyboard automatically starts a new line. Get returns ErrInlineKeyboardMaxRow when maxRow is not positive.
func (*InlineKeyboard) SetPayloadType ¶
func (in *InlineKeyboard) SetPayloadType(t BotPayloadType) *InlineKeyboard
SetPayloadType sets the keyboard-local serialization format for callback data added via AddCallbackButton and AddCallbackButtonStyle methods. It overrides the bot's default payload type for this keyboard only.
func (*InlineKeyboard) SetUnlimitedRows ¶
func (in *InlineKeyboard) SetUnlimitedRows() *InlineKeyboard
SetUnlimitedRows disables automatic row wrapping explicitly.
type InlineKeyboardButtonBuilder ¶
type InlineKeyboardButtonBuilder struct {
// contains filtered or unexported fields
}
InlineKeyboardButtonBuilder is a fluent builder for creating a single inline keyboard button.
Use NewInlineKeyboardButton() to start, then chain methods to configure:
- SetIconCustomEmojiID() — adds a custom emoji icon
- SetStyle() — sets visual style (danger/success/primary)
- SetURL() — makes button open a URL
- SetCallbackDataJSON() — attaches structured command + args for bot handling
Call Build to validate and produce the final tgapi.InlineKeyboardButton. Builder methods are immutable — each returns a copy.
func NewInlineKeyboardButton ¶
func NewInlineKeyboardButton(text string) InlineKeyboardButtonBuilder
NewInlineKeyboardButton creates a new button builder with the given display text. The button will have no URL, no style, and no callback data by default.
func (InlineKeyboardButtonBuilder) Build ¶
func (b InlineKeyboardButtonBuilder) Build() (tgapi.InlineKeyboardButton, error)
Build validates and returns the configured inline keyboard button.
func (InlineKeyboardButtonBuilder) SetCallbackData ¶
func (b InlineKeyboardButtonBuilder) SetCallbackData(cmd string, args ...any) InlineKeyboardButtonBuilder
SetCallbackData sets a structured callback payload using the configured payload type. The default payload type is JSON.
func (InlineKeyboardButtonBuilder) SetCallbackDataBase64 ¶
func (b InlineKeyboardButtonBuilder) SetCallbackDataBase64(cmd string, args ...any) InlineKeyboardButtonBuilder
SetCallbackDataBase64 sets a Base64-encoded structured callback payload. Base64 does not bypass Telegram's 64-byte callback-data limit.
func (InlineKeyboardButtonBuilder) SetCallbackDataCompact ¶
func (b InlineKeyboardButtonBuilder) SetCallbackDataCompact(cmd string, args ...any) InlineKeyboardButtonBuilder
SetCallbackDataCompact sets a structured callback payload encoded as compact text.
func (InlineKeyboardButtonBuilder) SetCallbackDataCompactBase64 ¶
func (b InlineKeyboardButtonBuilder) SetCallbackDataCompactBase64(cmd string, args ...any) InlineKeyboardButtonBuilder
SetCallbackDataCompactBase64 sets a compact callback payload encoded as Base64.
func (InlineKeyboardButtonBuilder) SetCallbackDataJSON ¶
func (b InlineKeyboardButtonBuilder) SetCallbackDataJSON(cmd string, args ...any) InlineKeyboardButtonBuilder
SetCallbackDataJSON sets a structured callback payload that will be sent to the bot when the button is pressed. The command and arguments are serialized as JSON.
Args are converted to strings using fmt.Sprint. Non-string types (e.g., int, bool) are safely serialized, but complex structs may not serialize usefully.
Example: SetCallbackDataJSON("delete_user", 123, "confirm") → {"cmd":"delete_user","args":["123","confirm"]}.
func (InlineKeyboardButtonBuilder) SetDisabled ¶
func (b InlineKeyboardButtonBuilder) SetDisabled() InlineKeyboardButtonBuilder
SetDisabled makes the button inert and clears URL and callback actions.
Since: Bot API 10.3
func (InlineKeyboardButtonBuilder) SetIconCustomEmojiID ¶
func (b InlineKeyboardButtonBuilder) SetIconCustomEmojiID(id string) InlineKeyboardButtonBuilder
SetIconCustomEmojiID sets a custom emoji ID to display as the button's icon. This is a Telegram Bot API feature for custom emoji icons.
func (InlineKeyboardButtonBuilder) SetPayloadType ¶
func (b InlineKeyboardButtonBuilder) SetPayloadType(t BotPayloadType) InlineKeyboardButtonBuilder
SetPayloadType sets the encoding used by SetCallbackData.
func (InlineKeyboardButtonBuilder) SetStyle ¶
func (b InlineKeyboardButtonBuilder) SetStyle(style tgapi.KeyboardButtonStyle) InlineKeyboardButtonBuilder
SetStyle sets the visual style of the button. Valid values: ButtonStyleDanger, ButtonStyleSuccess, ButtonStylePrimary. If not set, the button uses the default style.
func (InlineKeyboardButtonBuilder) SetURL ¶
func (b InlineKeyboardButtonBuilder) SetURL(url string) InlineKeyboardButtonBuilder
SetURL sets a URL that will be opened when the button is pressed. It clears callback data because Telegram requires exactly one button action.
func (InlineKeyboardButtonBuilder) Validate ¶
func (b InlineKeyboardButtonBuilder) Validate() error
Validate checks that the button has exactly one action and valid callback data.
type L10n ¶
type L10n struct {
// contains filtered or unexported fields
}
L10n stores translations with a configurable fallback language and is safe for concurrent use.
func (*L10n) AddDictEntry ¶
AddDictEntry stores translations for key.
func (*L10n) GetFallbackLanguage ¶
GetFallbackLanguage returns the currently configured fallback language code.
type LinearDraftIDGenerator ¶
type LinearDraftIDGenerator struct {
// contains filtered or unexported fields
}
LinearDraftIDGenerator generates draft IDs using a monotonically increasing counter. Useful for debugging, persistence, or when drafts must be ordered.
func (*LinearDraftIDGenerator) Next ¶
func (g *LinearDraftIDGenerator) Next() uint64
Next returns the next linear ID, atomically incremented.
type MemorySessionStore ¶
type MemorySessionStore struct {
// contains filtered or unexported fields
}
MemorySessionStore stores scene sessions in memory.
func NewMemorySessionStore ¶
func NewMemorySessionStore() *MemorySessionStore
NewMemorySessionStore creates an empty in-memory session store.
func (*MemorySessionStore) Delete ¶
func (s *MemorySessionStore) Delete(key string) error
Delete removes the session stored under key.
func (*MemorySessionStore) Get ¶
func (s *MemorySessionStore) Get(key string) (SceneSession, error)
Get returns the session stored under key, or the zero session when absent.
func (*MemorySessionStore) Set ¶
func (s *MemorySessionStore) Set(key string, session SceneSession) error
Set stores session under key.
type MessageContext ¶
type MessageContext struct {
// API is the Telegram API client used by context helpers.
API *tgapi.API
// Update is the Telegram update being handled.
Update tgapi.Update
// Msg is the normalized Telegram message for message-backed update kinds.
// It is nil for updates that do not include a message object.
Msg *tgapi.Message
// From is the normalized Telegram user for update kinds that expose one.
// It stays nil for sender-chat-only updates and update kinds without a user.
From *tgapi.User
// Chat is the normalized Telegram chat for update kinds that expose one.
// It is nil for updates that do not include a chat identity.
Chat *tgapi.Chat
// Logger is the logger assigned by the matched plugin for the current handler call.
// It may fall back to the bot logger when the plugin has no dedicated logger.
Logger *sneklog.Logger
// InlineMsgID is the inline message identifier for callback queries that target
// an inline message instead of a chat message.
InlineMsgID string
// CallbackMsgID is the message ID targeted by the current callback query when
// the callback comes from a chat message.
CallbackMsgID int
// CallbackQueryID is the Telegram callback query ID for payload handlers and
// callback-backed scene handlers.
CallbackQueryID string
// FromID is the normalized sender ID when the current update exposes a user.
// It is zero when the update has no user identity.
FromID int64
// ChatID is the normalized chat ID when the current update exposes a chat.
// It is zero when the update has no chat identity.
ChatID int64
// Prefix is the matched command prefix for command routing and scene-local
// command routing. It is empty outside those flows.
Prefix string
// Text is the parsed command tail for command routing, the parsed scene-command
// tail for scene-local command routing, or the trimmed message text seen by a
// scene step/message handler. It is empty when the current routing path does
// not derive text input.
Text string
// Args contains parsed command or payload arguments for the current routing
// path. It is nil or empty when no argument vector is derived.
Args []string
// contains filtered or unexported fields
}
MessageContext holds the normalized per-update context passed to command, payload, scene, middleware, and generic update handlers.
MessageContext is populated from the current Telegram update before handler routing. Not every field is guaranteed for every update kind. In particular:
- Update is always present.
- Msg is populated only for update kinds that carry a Telegram message object.
- From and FromID are populated only when the update exposes a user identity.
- Chat and ChatID are populated only when the update exposes a chat identity.
- Text, Args, and Prefix are populated only by command or scene command routing.
- CallbackQueryID, CallbackMsgID, and InlineMsgID are populated only for callback query handling when the corresponding callback targets exist.
Helper methods on MessageContext may require a message-backed context. For example, reply helpers need Msg, while inline callback edit helpers can work through InlineMsgID when there is no chat message.
func (*MessageContext) Answer ¶
func (ctx *MessageContext) Answer(text string) *AnswerMessage
Answer sends a plain text message (ParseNone).
func (*MessageContext) AnswerCallback ¶
func (ctx *MessageContext) AnswerCallback()
AnswerCallback answers the callback query with no text or alert.
func (*MessageContext) AnswerCallbackAlert ¶
func (ctx *MessageContext) AnswerCallbackAlert(text string)
AnswerCallbackAlert answers the callback query with a user-visible alert.
func (*MessageContext) AnswerCallbackText ¶
func (ctx *MessageContext) AnswerCallbackText(text string)
AnswerCallbackText answers the callback query with a text notification.
func (*MessageContext) AnswerCallbackURL ¶
func (ctx *MessageContext) AnswerCallbackURL(u string)
AnswerCallbackURL answers the callback query with a URL redirect.
func (*MessageContext) AnswerLong ¶
func (ctx *MessageContext) AnswerLong(text string) []*AnswerMessage
AnswerLong sends one or more plain-text messages if text exceeds Telegram's limit.
The text is split into Telegram-safe chunks. Returned messages preserve send order. If a chunk fails to send, already-sent messages are returned.
func (*MessageContext) AnswerLongf ¶
func (ctx *MessageContext) AnswerLongf(template string, args ...any) []*AnswerMessage
AnswerLongf formats a string using fmt.Sprintf and sends it as one or more plain-text messages.
func (*MessageContext) AnswerMarkdown ¶
func (ctx *MessageContext) AnswerMarkdown(text string) *AnswerMessage
AnswerMarkdown sends a message using MarkdownV2 formatting.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*MessageContext) AnswerPhoto ¶
func (ctx *MessageContext) AnswerPhoto(photoID, text string) *AnswerMessage
AnswerPhoto sends a photo with plain text caption.
func (*MessageContext) AnswerPhotoKeyboard ¶
func (ctx *MessageContext) AnswerPhotoKeyboard(photoID, text string, kb *InlineKeyboard) *AnswerMessage
AnswerPhotoKeyboard sends a photo with caption and inline keyboard (plain text).
func (*MessageContext) AnswerPhotoKeyboardMarkdown ¶
func (ctx *MessageContext) AnswerPhotoKeyboardMarkdown(photoID, text string, kb *InlineKeyboard) *AnswerMessage
AnswerPhotoKeyboardMarkdown sends a photo with caption and inline keyboard using MarkdownV2.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*MessageContext) AnswerPhotoMarkdown ¶
func (ctx *MessageContext) AnswerPhotoMarkdown(photoID, text string) *AnswerMessage
AnswerPhotoMarkdown sends a photo with MarkdownV2 caption.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*MessageContext) AnswerPhotof ¶
func (ctx *MessageContext) AnswerPhotof(photoID, template string, args ...any) *AnswerMessage
AnswerPhotof formats a string and sends it as a photo caption (plain text).
func (*MessageContext) AnswerPhotofMarkdown ¶
func (ctx *MessageContext) AnswerPhotofMarkdown(photoID, template string, args ...any) *AnswerMessage
AnswerPhotofMarkdown formats a string and sends it as a photo caption using MarkdownV2.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*MessageContext) Answerf ¶
func (ctx *MessageContext) Answerf(template string, args ...any) *AnswerMessage
Answerf formats a string using fmt.Sprintf and sends it as a plain text message.
func (*MessageContext) AnswerfMarkdown ¶
func (ctx *MessageContext) AnswerfMarkdown(template string, args ...any) *AnswerMessage
AnswerfMarkdown formats a string using fmt.Sprintf and sends it using MarkdownV2.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*MessageContext) BindArgs ¶
func (ctx *MessageContext) BindArgs(dst any) error
BindArgs binds positional command arguments from ctx.Args into dst.
Exported struct fields are filled in declaration order. When fewer arguments are provided than fields, the remaining fields keep their zero values. If the final bindable field is a string, it receives the remaining arguments joined with spaces.
func (*MessageContext) CallbackDelete ¶
func (ctx *MessageContext) CallbackDelete()
CallbackDelete deletes the message that triggered the callback query.
func (*MessageContext) Context ¶
func (ctx *MessageContext) Context() context.Context
Context returns the request-scoped context associated with the current update.
func (*MessageContext) EditCallback ¶
func (ctx *MessageContext) EditCallback(text string, keyboard *InlineKeyboard) *AnswerMessage
EditCallback edits the callback message using plain text (ParseNone).
func (*MessageContext) EditCallbackMarkdown ¶
func (ctx *MessageContext) EditCallbackMarkdown(text string, keyboard *InlineKeyboard) *AnswerMessage
EditCallbackMarkdown edits the callback message using MarkdownV2.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*MessageContext) EditCallbackRich ¶
func (ctx *MessageContext) EditCallbackRich(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage
EditCallbackRich builds rich blocks and replaces the callback message content and inline keyboard. It doesn't upload local files referenced with attach://.
Since: Bot API 10.2
func (*MessageContext) EditCallbackf ¶
func (ctx *MessageContext) EditCallbackf(format string, keyboard *InlineKeyboard, args ...any) *AnswerMessage
EditCallbackf formats a string using fmt.Sprintf and edits the callback message with plain text.
func (*MessageContext) EditCallbackfMarkdown ¶
func (ctx *MessageContext) EditCallbackfMarkdown(format string, keyboard *InlineKeyboard, args ...any) *AnswerMessage
EditCallbackfMarkdown formats a string using fmt.Sprintf and edits the callback message with MarkdownV2.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*MessageContext) EnterScene ¶
func (ctx *MessageContext) EnterScene(name string) error
EnterScene enters the named scene at its configured entry step.
func (*MessageContext) EnterSceneStep ¶
func (ctx *MessageContext) EnterSceneStep(name, step string) error
EnterSceneStep enters the named scene at a specific step.
func (*MessageContext) Error ¶
func (ctx *MessageContext) Error(err error)
Error routes err through the centralized handler error path.
The error is logged via ctx.Logger. When IsUserError(err) is true, the formatted error template is delivered to the user — through an answer to the active callback query when one exists, otherwise as a chat reply. Internal errors are logged but not surfaced to the user.
func (*MessageContext) ExitScene ¶
func (ctx *MessageContext) ExitScene() error
ExitScene leaves the currently active scene for this context.
func (*MessageContext) HasPhoto ¶
func (ctx *MessageContext) HasPhoto() bool
HasPhoto reports whether the current message contains a photo payload.
func (*MessageContext) IsCallback ¶
func (ctx *MessageContext) IsCallback() bool
IsCallback reports whether the context belongs to a callback query.
func (*MessageContext) Keyboard ¶
func (ctx *MessageContext) Keyboard(text string, kb *InlineKeyboard) *AnswerMessage
Keyboard sends a message with an inline keyboard (plain text).
func (*MessageContext) KeyboardLong ¶
func (ctx *MessageContext) KeyboardLong(text string, kb *InlineKeyboard) []*AnswerMessage
KeyboardLong sends long plain text split across multiple messages.
The inline keyboard is attached only to the final chunk.
func (*MessageContext) KeyboardMarkdown ¶
func (ctx *MessageContext) KeyboardMarkdown(text string, keyboard *InlineKeyboard) *AnswerMessage
KeyboardMarkdown sends a message with an inline keyboard using MarkdownV2.
⚠️ WARNING: User input must be escaped with tgfmt.EscapeMarkdownV2() before passing here.
func (*MessageContext) NewDraft ¶
func (ctx *MessageContext) NewDraft() *Draft
NewDraft creates a new message draft associated with the current chat. Draft sends are rate-limited by the API client.
func (*MessageContext) NewDraftMarkdown ¶
func (ctx *MessageContext) NewDraftMarkdown() *Draft
NewDraftMarkdown creates a new message draft associated with the current chat, with Markdown V2 parse mode enabled. Draft sends are rate-limited by the API client.
func (*MessageContext) NewInlineKeyboard ¶
func (ctx *MessageContext) NewInlineKeyboard(maxRow int) *InlineKeyboard
NewInlineKeyboard creates a new keyboard builder with the context's payload encoding type and the specified maximum number of buttons per row.
func (*MessageContext) NewInlineKeyboardButton ¶
func (ctx *MessageContext) NewInlineKeyboardButton(text string) InlineKeyboardButtonBuilder
NewInlineKeyboardButton creates a button builder using the context payload encoding.
func (*MessageContext) RichAnswer ¶
func (ctx *MessageContext) RichAnswer(blocks ...tgapi.InputRichBlock) *AnswerMessage
RichAnswer builds and sends input rich-message blocks.
Since: Bot API 10.2
func (*MessageContext) RichAnswerKeyboard ¶
func (ctx *MessageContext) RichAnswerKeyboard(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage
RichAnswerKeyboard builds and sends input rich-message blocks with an inline keyboard.
Since: Bot API 10.2
func (*MessageContext) SendAction ¶
func (ctx *MessageContext) SendAction(action tgapi.ChatActionType)
SendAction sends a chat action (typing, uploading_photo, etc.) to indicate bot activity.
func (*MessageContext) Translate ¶
func (ctx *MessageContext) Translate(key string) string
Translate looks up a key in the current user's language. Falls back to the bot's default language if user's language is unknown or unsupported.
func (*MessageContext) UpsertKeyboard ¶
func (ctx *MessageContext) UpsertKeyboard(text string, keyboard *InlineKeyboard) *AnswerMessage
UpsertKeyboard edits a callback message or sends a new plain-text message with a keyboard.
func (*MessageContext) UpsertKeyboardMarkdown ¶
func (ctx *MessageContext) UpsertKeyboardMarkdown(text string, keyboard *InlineKeyboard) *AnswerMessage
UpsertKeyboardMarkdown edits a callback message or sends a new MarkdownV2 message with a keyboard.
func (*MessageContext) UpsertKeyboardRich ¶
func (ctx *MessageContext) UpsertKeyboardRich(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage
UpsertKeyboardRich builds rich blocks and either edits the callback message or sends a new message. Photo callback messages are replaced because their text content can't be edited directly. It doesn't upload local files referenced with attach://.
Since: Bot API 10.2
type Middleware ¶
type Middleware[T AppData] struct { // contains filtered or unexported fields }
Middleware represents a reusable execution interceptor. Can be synchronous (blocking) or asynchronous (non-blocking).
func NewMiddleware ¶
func NewMiddleware[T AppData](name string, executor MiddlewareExecutor[T]) Middleware[T]
NewMiddleware creates a new synchronous middleware.
func RequirePolicy ¶
func RequirePolicy[T AppData](name string, p Policy[T]) Middleware[T]
RequirePolicy adapts a Policy into a blocking middleware.
func (Middleware[T]) Execute ¶
func (m Middleware[T]) Execute(ctx *MessageContext, db T) bool
Execute runs the middleware. If async, runs in a goroutine and returns true immediately. Otherwise, returns the result of the executor.
Async note: the goroutine receives a shallow copy of MessageContext, so scalar fields (FromID, ChatID, CallbackQueryID, ...) remain a stable snapshot. Pointer and slice fields (Msg, From, Chat, API, Logger, Args) continue to share storage with the synchronous flow. Async middleware must treat those fields as read-only — mutating them races the sync chain that mutates the same context concurrently. Bot runtimes wait for tracked asynchronous middleware before returning.
func (Middleware[T]) SetAsync ¶
func (m Middleware[T]) SetAsync(async bool) Middleware[T]
SetAsync marks the middleware to run asynchronously. Execution continues regardless of its return value.
func (Middleware[T]) SetOrder ¶
func (m Middleware[T]) SetOrder(order int) Middleware[T]
SetOrder sets the bot-level middleware execution order.
type MiddlewareExecutor ¶
type MiddlewareExecutor[T AppData] func(ctx *MessageContext, db T) bool
MiddlewareExecutor is the function type for middleware logic. Returns true to continue execution, false to block it. If async, return value is ignored.
type MultiObserver ¶
type MultiObserver struct {
// contains filtered or unexported fields
}
func (MultiObserver) OnError ¶
func (m MultiObserver) OnError(ctx context.Context, event ErrorEvent)
func (MultiObserver) OnHandlerFinished ¶
func (m MultiObserver) OnHandlerFinished(ctx context.Context, event HandlerFinishedEvent)
func (MultiObserver) OnHandlerStarted ¶
func (m MultiObserver) OnHandlerStarted(ctx context.Context, event HandlerStartedEvent)
func (MultiObserver) OnPolicyChecked ¶
func (m MultiObserver) OnPolicyChecked(ctx context.Context, event PolicyCheckedEvent)
func (MultiObserver) OnPollingRetry ¶
func (m MultiObserver) OnPollingRetry(ctx context.Context, event PollingRetryEvent)
func (MultiObserver) OnRunnerFinished ¶
func (m MultiObserver) OnRunnerFinished(ctx context.Context, event RunnerFinishedEvent)
func (MultiObserver) OnSceneTransition ¶
func (m MultiObserver) OnSceneTransition(ctx context.Context, event SceneTransitionEvent)
func (MultiObserver) OnUpdateHandled ¶
func (m MultiObserver) OnUpdateHandled(ctx context.Context, event UpdateHandledEvent)
func (MultiObserver) OnUpdateReceived ¶
func (m MultiObserver) OnUpdateReceived(ctx context.Context, event UpdateReceivedEvent)
type NoData ¶
type NoData struct{}
NoData is a placeholder type for bots that do not use shared application data.
Use Bot[NoData] to indicate no shared dependency injection is required.
type Observer ¶
type Observer interface {
OnUpdateReceived(ctx context.Context, event UpdateReceivedEvent)
OnUpdateHandled(ctx context.Context, event UpdateHandledEvent)
OnHandlerStarted(ctx context.Context, event HandlerStartedEvent)
OnHandlerFinished(ctx context.Context, event HandlerFinishedEvent)
OnSceneTransition(ctx context.Context, event SceneTransitionEvent)
OnPolicyChecked(ctx context.Context, event PolicyCheckedEvent)
OnRunnerFinished(ctx context.Context, event RunnerFinishedEvent)
OnPollingRetry(ctx context.Context, event PollingRetryEvent)
OnError(ctx context.Context, event ErrorEvent)
}
Observer receives best-effort runtime instrumentation events.
During RunWithContext and RunWebhookWithContext, callbacks execute on a dedicated dispatcher goroutine in enqueue order and never block update handlers. The queue is bounded; overload drops events and emits sampled warnings. Runtime shutdown cancels callback contexts and drains queued events; Bot.Close returns ErrObserverShutdownTimeout if a callback ignores cancellation.
func NewMultiObserver ¶
type Plugin ¶
type Plugin[T AppData] struct { // contains filtered or unexported fields }
Plugin represents a collection of commands and payloads (e.g., callback handlers), with shared middleware and configuration.
A Plugin is intended to be fully configured before it is passed to Bot.AddPlugins. After registration, treat the plugin as committed and do not mutate it further. Post-registration changes through the original *Plugin are not a supported API.
func (*Plugin[T]) AddCommand ¶
AddCommand registers a command in the plugin.
func (*Plugin[T]) AddCommandGroup ¶
func (p *Plugin[T]) AddCommandGroup(group *CommandGroup[T]) *Plugin[T]
AddCommandGroup registers every command built by group.
func (*Plugin[T]) AddMiddleware ¶
func (p *Plugin[T]) AddMiddleware(middleware Middleware[T]) *Plugin[T]
AddMiddleware adds a middleware to the plugin's global middleware chain. Middlewares are executed before any command or payload.
func (*Plugin[T]) AddPayload ¶
AddPayload registers a payload (e.g., callback query data) in the plugin. Payloads are triggered by inline button callback_data, not by message text.
func (*Plugin[T]) AddUpdateHandler ¶
func (p *Plugin[T]) AddUpdateHandler(t tgapi.UpdateType, handler CommandExecutor[T]) *Plugin[T]
AddUpdateHandler registers a handler for a non-command update type. Message, channel post, and callback query updates stay on the command/payload flow.
func (*Plugin[T]) Close ¶
Close releases plugin-owned resources such as its logger and optional OnClose callback.
Only loggers created by the bot during registration are closed. A logger supplied via SetLogger remains the caller's responsibility — the framework never closes a logger it does not own.
func (*Plugin[T]) Command ¶
func (p *Plugin[T]) Command(command string, exec CommandExecutor[T], args ...CommandArg) *Command[T]
Command creates and immediately adds a new command to the plugin. Returns the created command for further configuration.
func (*Plugin[T]) CommandGroup ¶
func (p *Plugin[T]) CommandGroup(prefix string, groupFunc func(group *CommandGroup[T])) *Plugin[T]
CommandGroup configures and registers a prefixed command group.
func (*Plugin[T]) Payload ¶
func (p *Plugin[T]) Payload(command string, exec CommandExecutor[T], args ...CommandArg) *Command[T]
Payload creates and immediately adds a new payload command to the plugin. Returns the created payload command for further configuration.
func (*Plugin[T]) RemoveLogger ¶
RemoveLogger clears the custom logger for this plugin.
Call this before Bot.AddPlugins. If the plugin is already registered, changing the original *Plugin does not update the Bot's internal copy.
func (*Plugin[T]) SetLogger ¶
SetLogger sets the logger used for this plugin's handlers.
Call this before Bot.AddPlugins. If the plugin is already registered, changing the original *Plugin does not update the Bot's internal copy.
func (*Plugin[T]) SetMessageFallback ¶
func (p *Plugin[T]) SetMessageFallback(handler CommandExecutor[T]) *Plugin[T]
SetMessageFallback registers a fallback handler for messages that do not match a command.
func (*Plugin[T]) SetOnClose ¶
SetOnClose registers a callback invoked from Plugin.Close after the plugin logger is closed.
Call this before Bot.AddPlugins. If the plugin is already registered, changing the original *Plugin does not update the Bot's internal copy.
func (*Plugin[T]) SkipCommandAutoGen ¶
SkipCommandAutoGen marks the entire plugin to be excluded from auto-generated help menus.
type Policy ¶
type Policy[T AppData] func(ctx *MessageContext, data T) error
Policy defines a reusable authorization rule for the current update context.
func AllPolicies ¶
AllPolicies composes policies that all must succeed.
func RequireBotAdmin ¶
RequireBotAdmin allows execution only when the bot is an admin in the chat.
func RequireCallbackFromUser ¶
RequireCallbackFromUser allows execution only for callback queries sent by non-bot users.
func RequireChatAdmin ¶
RequireChatAdmin allows execution only for chat administrators or owners.
func RequireChatCreator ¶
RequireChatCreator allows execution only for the chat owner.
func RequireGroupChat ¶
RequireGroupChat allows execution only in group or supergroup chats.
func RequirePrivateChat ¶
RequirePrivateChat allows execution only in private chats.
func RequireSupergroupChat ¶
RequireSupergroupChat allows execution only in supergroup chats.
type PolicyCheckedEvent ¶
type PolicyCheckedEvent struct {
// Name identifies the evaluated policy.
Name string
// Plugin names the plugin that requested the policy check.
Plugin string
// FromID identifies the evaluated user when available.
FromID int64
// ChatID identifies the evaluated chat when available.
ChatID int64
// Passed reports whether the policy accepted the context.
Passed bool
// Err is the policy evaluation error, if any.
Err error
// Internal reports whether evaluation failed internally rather than denying access.
Internal bool
}
PolicyCheckedEvent describes the result of a policy evaluation.
type PollingRetryEvent ¶
type PollingRetryEvent struct {
// Attempt is the one-based retry number.
Attempt int
// Delay is the time before the next polling attempt.
Delay time.Duration
// Err is the polling error that triggered the retry.
Err error
}
PollingRetryEvent describes a polling retry after a failed getUpdates call.
type RandomDraftIDGenerator ¶
type RandomDraftIDGenerator struct{}
RandomDraftIDGenerator generates draft IDs using math/rand/v2.
Suitable for general use thanks to the wide 64-bit value space. Not suitable for security-sensitive purposes — use crypto/rand if unpredictability against an adversary matters.
func (*RandomDraftIDGenerator) Next ¶
func (g *RandomDraftIDGenerator) Next() uint64
Next returns a random 64-bit unsigned integer.
type Runner ¶
type Runner[T AppData] struct { // contains filtered or unexported fields }
Runner represents a configurable background or one-time task to be executed by a Bot.
Runners are configured using builder methods Async and Every. Once the bot's runtime has started executing the runner, it should not be modified.
Execution semantics:
- every=0, async=true: Run once in a goroutine (non-blocking, default).
- every=0, async=false: Run once synchronously (blocks runtime startup).
- every>0, async=true: Run repeatedly in a goroutine with the given interval.
- every>0, async=false: Invalid configuration — skipped with a warning.
func NewRunner ¶
NewRunner creates a new Runner with the given name and function.
The default configuration is async=true and every=0, i.e. a one-shot goroutine that fires once when the bot runtime starts. Use Async and Every to customize this. Do not call builder methods concurrently or after the bot runtime has begun executing runners.
func (Runner[T]) Async ¶
Async sets whether the runner executes synchronously or asynchronously. If true, the runner runs in a goroutine (non-blocking). If false, the runner blocks the caller during execution.
Note: periodic runners (Every > 0) require async=true and are skipped with a warning when async=false.
func (Runner[T]) Every ¶
Every sets the interval between repeated executions of a periodic runner.
A zero value (the default) keeps the runner one-shot. A positive value schedules the runner to fire repeatedly with the given interval and requires async=true; periodic sync runners are skipped with a warning.
type RunnerFinishedEvent ¶
type RunnerFinishedEvent struct {
// Name identifies the runner.
Name string
// Duration is the callback execution time.
Duration time.Duration
// Err is the callback error or recovered panic.
Err error
}
RunnerFinishedEvent describes a completed background runner execution.
type Scene ¶
type Scene[T any] struct { // contains filtered or unexported fields }
Scene defines a multi-step conversational flow.
func (*Scene[T]) OnCommand ¶
func (s *Scene[T]) OnCommand(cmd string, handler SceneHandler[T]) *Scene[T]
OnCommand registers a command handler active while the scene is running.
func (*Scene[T]) OnMessage ¶
func (s *Scene[T]) OnMessage(handler SceneHandler[T]) *Scene[T]
OnMessage registers a fallback handler used when no scene command or step matches.
func (*Scene[T]) OnPayload ¶
func (s *Scene[T]) OnPayload(cmd string, handler SceneHandler[T]) *Scene[T]
OnPayload registers a callback payload handler active while the scene is running.
func (*Scene[T]) OnStep ¶
func (s *Scene[T]) OnStep(step string, handler SceneHandler[T]) *Scene[T]
OnStep registers a handler for a named scene step.
func (*Scene[T]) SetScope ¶
func (s *Scene[T]) SetScope(scope SceneScope) *Scene[T]
SetScope changes how scene sessions are keyed and shared.
type SceneAction ¶
type SceneAction int
SceneAction controls how the bot updates scene state after a handler returns.
const ( // SceneActionStay keeps the current scene and step active. SceneActionStay SceneAction = iota // SceneActionNext moves the session to another named step. SceneActionNext // SceneActionExit removes the current scene session. SceneActionExit // SceneActionPass lets normal bot routing continue after the scene handler. SceneActionPass )
type SceneContext ¶
type SceneContext struct {
*MessageContext
// contains filtered or unexported fields
}
SceneContext wraps MessageContext with scene session state for scene handlers.
func (*SceneContext) BindData ¶
func (ctx *SceneContext) BindData(v any) error
BindData unmarshals the current scene session payload into v.
func (*SceneContext) Exit ¶
func (ctx *SceneContext) Exit() SceneResult
Exit leaves the current scene.
func (*SceneContext) Next ¶
func (ctx *SceneContext) Next(step string) SceneResult
Next advances the current scene to step.
func (*SceneContext) Pass ¶
func (ctx *SceneContext) Pass() SceneResult
Pass stops scene handling and lets normal routing continue.
func (*SceneContext) SaveData ¶
func (ctx *SceneContext) SaveData(v any) error
SaveData marshals v and stores it in the current scene session payload.
func (*SceneContext) Stay ¶
func (ctx *SceneContext) Stay() SceneResult
Stay keeps the current scene step active.
type SceneHandler ¶
type SceneHandler[T any] func(ctx *SceneContext, db T) (SceneResult, error)
SceneHandler handles a scene step, scene command, or fallback message.
type SceneResult ¶
type SceneResult struct {
// Action controls the scene state transition.
Action SceneAction
// Next names the destination step for SceneActionNext.
Next string
}
SceneResult describes how scene execution should proceed after a handler returns.
type SceneScope ¶
type SceneScope int
SceneScope defines how scene sessions are keyed.
const ( // SceneScopeUser shares a scene across all chats for one user. SceneScopeUser SceneScope = iota // SceneScopeChat shares a scene across all users in one chat. SceneScopeChat // SceneScopeUserChat isolates a scene per user-chat pair. SceneScopeUserChat )
type SceneSession ¶
type SceneSession struct {
// Scene is the registered scene name for the active session.
Scene string
// Step is the current step name inside the active scene.
Step string
// contains filtered or unexported fields
}
SceneSession stores the active scene state for one session key.
func (*SceneSession) BindData ¶
func (s *SceneSession) BindData(v any) error
BindData unmarshals the stored JSON payload into v.
func (*SceneSession) ClearData ¶
func (s *SceneSession) ClearData()
ClearData removes any stored session data.
func (*SceneSession) GetData ¶
func (s *SceneSession) GetData() []byte
GetData returns the raw session data payload.
func (*SceneSession) HasData ¶
func (s *SceneSession) HasData() bool
HasData reports whether the session has a non-empty data payload.
func (*SceneSession) SaveData ¶
func (s *SceneSession) SaveData(v any) error
SaveData marshals v as JSON and stores it in the session.
func (*SceneSession) SetData ¶
func (s *SceneSession) SetData(data []byte)
SetData stores arbitrary opaque session data.
type SceneTransitionEvent ¶
type SceneTransitionEvent struct {
// Plugin names the plugin that owns the scene.
Plugin string
// Scene names the transitioning scene.
Scene string
// From is the previous scene step.
From string
// To is the resulting scene step.
To string
// Action identifies the requested state transition.
Action SceneAction
// FromID identifies the session user when available.
FromID int64
// ChatID identifies the session chat when available.
ChatID int64
}
SceneTransitionEvent describes a scene state transition.
type SessionStore ¶
type SessionStore interface {
Get(key string) (SceneSession, error)
Set(key string, session SceneSession) error
Delete(key string) error
}
SessionStore persists scene sessions by key.
type UpdateHandledEvent ¶
type UpdateHandledEvent struct {
// UpdateID identifies the Telegram update.
UpdateID int
// UpdateType identifies the normalized update kind.
UpdateType tgapi.UpdateType
// FromID identifies the originating user when available.
FromID int64
// ChatID identifies the originating chat when available.
ChatID int64
// Duration is the total framework handling time.
Duration time.Duration
// Handled reports whether a registered path handled the update.
Handled bool
}
UpdateHandledEvent describes a completed update execution path.
type UpdateReceivedEvent ¶
type UpdateReceivedEvent struct {
// UpdateID identifies the Telegram update.
UpdateID int
// UpdateType identifies the normalized update kind.
UpdateType tgapi.UpdateType
// FromID identifies the originating user when available.
FromID int64
// ChatID identifies the originating chat when available.
ChatID int64
}
UpdateReceivedEvent describes an update entering the bot runtime.
Source Files
¶
- bot.go
- bot_client.go
- bot_config.go
- bot_opts.go
- bot_opts_loader.go
- bot_register.go
- bot_scene.go
- bot_utils.go
- bot_webhook.go
- cmd_generator.go
- commands.go
- doc.go
- drafts.go
- error_model.go
- errors.go
- handler.go
- keyboard.go
- l10n.go
- methods.go
- msg_context.go
- msg_handler.go
- observer.go
- observer_async.go
- plugins.go
- policy.go
- runners.go
- scene.go
- scene_context.go
- scene_handler.go
- scene_locks.go
- split.go
- update_context.go
- utils.go
