IUpdateFilter
Namespace: PolyBot.Routing
A synchronous gate over an incoming update, evaluated by the generated router before invoking a handler that carries filter attributes. The source generator discovers every concrete, non-abstract, non-generic class that implements IUpdateFilter and emits a matching [XxxFilterAttribute] in PolyBot.Attributes.
bool
Returns
true if the update is allowed through to the handler. Returning false skips the handler entirely.Update access) or subclass one of the generated abstract DTO bases (MessageFilter, CallbackQueryFilter, etc.) whose CanPass(Update) extracts the payload and delegates to CanPass(TDto).
GetService<T>()), falling back to ActivatorUtilities.CreateInstance. Parameterless filters work without being registered; filters with constructor dependencies should be registered in DI.
Filter attributes (
[NonEmptyTextFilter]) and With* extensions (WithNonEmptyTextFilter()) are emitted by the generator, not written by hand. See the Source Generator page for details.IStateMachine
Namespace: PolyBot.State
A typed facade over IStateStorage scoped to the update currently being routed. Keys are resolved from the current update via StateKeyResolver. Inject into handler parameters directly — the generator maps the IStateMachine parameter to GetRequiredService<IStateMachine>().
ValueTask<TEnum?>
Returns the current state for the resolved key, or
null when no current update is active, the key is unresolvable, or no state is stored.ValueTask
Stores
state for the resolved key. Throws InvalidOperationException when the key cannot be resolved — silent state loss is worse than a visible failure.ValueTask
Removes the stored state for the resolved key, if any. Throws
InvalidOperationException when the key cannot be resolved.StateKey enum
Extension methods: StateMachineExtensions
Namespace: PolyBot.State
Two convenience methods walk forward/backward through an ordered enum:
null when cleared). Both throw InvalidOperationException when a write is required but the key cannot be resolved.
IStateStorage
Namespace: PolyBot.State
The raw persistence layer for FSM states. IStateMachine wraps this with update-context awareness; use IStateStorage directly when you need to read or modify state outside the routing loop (e.g. admin commands that reset another user’s state).
ValueTask<TEnum?>
Returns the stored state for
key, or null when none (or an expired entry) exists.ValueTask
Stores
state for key, replacing any previously stored state.ValueTask
Removes the state stored for
key, if any.MemoryStateStorage (default implementation)
Namespace: PolyBot.State
The built-in IStateStorage backed by a ConcurrentDictionary<(Type, string), Entry>. Suitable for development and single-instance bots; not shared across process restarts or multiple app instances.
IUpdateAwaiter
Namespace: PolyBot.Awaits
Enables conversation-style inline awaiting: a handler builds a typed await registration, the framework suspends the handler and resumes it when a matching update arrives — without blocking the polling loop.
UpdateAwaiterBuilder<TUpdate>
Starts building a single-shot await for a
TUpdate payload. Chain marker methods (TextMatches, WithFilter, Where) then call a terminal method (ByUserId, ByChatId, ByUserInChat) to register the await and return a Task<TUpdate?>.ValueTask<bool>
Router-facing delivery hook called by the generated router after the branch’s static conditions have already passed. You never call this directly. Returns
true when the update was claimed by a pending await; false lets it fall through to normal routing.WaitForMessageAsync() and all other WaitFor*Async() extension methods are generated into PolyBot.Attributes by the source generator. With* extensions are emitted one-per-discovered-filter. These generated methods are marker calls — the generator reads them syntactically to emit the correct branch conditions into the router.UpdateAwaiterBuilder<TUpdate>
Returned by WaitForAsync<TUpdate>. Fluent builder for configuring the await before registering it.
IBotFatherSync
Namespace: PolyBot.BotFather
Holds the commands discovered from [Command] attributes and synchronizes them with BotFather via SetMyCommands. The concrete implementation PolyBotBotFatherSync is generated by the source generator and registered automatically by AddPolyBotRouter().
IReadOnlyList<BotCommand>
All commands found at build time that are not marked
IsHidden = true. Read-only.Task
Groups commands by
(Scope, LanguageCode) and sends one SetMyCommands API call per group. Called automatically by PolyBotClient.RunPollingAsync() before polling starts.DI registration defaults
AddPolyBotDefaults() registers the following with try-add semantics (your earlier registrations win):
AddPolyBotRouter() calls AddPolyBotDefaults() first, then additionally registers (without try-add — these always replace):
ITelegramBotClient is registered separately — by PolyBotClient.BuildProvider() when using the standalone runner, or by your own DI setup when using the generic host or ASP.NET Core.
To override IStateStorage with a custom implementation, register it before AddPolyBotRouter() (which calls AddPolyBotDefaults() internally — try-add semantics mean your earlier registration wins):