Package-level declarations

Types

Link copied to clipboard

Handles an Effect that shouldn't block the transition that produced it — typically network calls. Unlike EffectHandler, this doesn't run as part of the current transition and doesn't produce an EffectResult: it runs independently (cancelled if the chat goes idle, see ChatWorkers in telek's implementation), and whatever Event it returns re-enters the FSM as its own, later transition — handled by StateDispatcher's transition(state, event) overload.

Link copied to clipboard
data class Callback(val chatId: Long, val messageId: Long, val data: String) : Input
Link copied to clipboard
data class Command(val name: String, val addressedTo: String? = null, val argument: String? = null)

A command as Telegram actually delivers one: a name, optionally the bot it is addressed to, and optionally an argument.

Link copied to clipboard
data class Contact(val chatId: Long, val messageId: Long, val phoneNumber: String, val firstName: String, val lastName: String? = null, val userId: Long? = null) : Input

A contact, which is how "share your phone number" arrives.

Link copied to clipboard
data class ConversationKey(val chatId: Long, val userId: Long? = null)

What a conversation's state is filed under.

Link copied to clipboard
interface Debounced

Opt-in marker for an Effect whose async dispatch should cancel any previous in-flight async effect for the same chat with an equal debounceKey, instead of letting them run concurrently — e.g. a user clicking through categories quickly, where only the latest fetch's result should matter.

Link copied to clipboard
class DefaultFindDispatcherStrategy(dispatchers: List<StateDispatcher<out State>>, botUsername: String? = null) : FindDispatcherStrategy

Routes on the two things that can start a flow — a command and a callback — and on the conversation's current state for everything else.

Link copied to clipboard
interface Dispatcher
Link copied to clipboard
data class Document(val chatId: Long, val messageId: Long, val file: FileRef, val fileName: String? = null, val mimeType: String? = null, val caption: String? = null) : Input
Link copied to clipboard
interface Effect
Link copied to clipboard
interface EffectExecutor
Link copied to clipboard
class EffectExecutorImpl(effectRegistry: EffectRegistry, context: suspend () -> ExecutionContext, failurePolicy: EffectFailurePolicy = EffectFailurePolicy.CONTINUE, logger: TelekLogger = TelekLogger.NoOp) : EffectExecutor

Looks up a handler per effect in effectRegistry and runs it. context is resolved once per execute call — transport-specific executors (e.g. telegramEffectExecutor()) use this to supply an ExecutionContext that may only become available after telek itself is constructed (e.g. once a bot instance exists), without Telek needing to own or track that lifecycle.

Link copied to clipboard
class EffectFailed(val error: Throwable) : EffectResult
Link copied to clipboard

What to do when an effect in a batch fails.

Link copied to clipboard
interface EffectHandler<E : Effect>
Link copied to clipboard
data class EffectOutcome(val effect: Effect, val result: EffectResult)

An Effect and what running it produced.

Link copied to clipboard
Link copied to clipboard
interface EffectResult
Link copied to clipboard
Link copied to clipboard
data object EmptyState : State
Link copied to clipboard
interface Event

Something that happened asynchronously and needs to re-enter the FSM — the result of an AsyncEffectHandler, not something a user sent. Unlike Input, an Event can never start a flow: it's routed purely by the conversation's current state (see StateDispatcher.transition overload that takes an Event), never by command or callback data.

Link copied to clipboard
Link copied to clipboard
data class FileRef(val fileId: String, val uniqueId: String? = null, val sizeBytes: Long? = null)

A file Telegram holds, named the way Telegram names one.

Link copied to clipboard
interface FinalState
Link copied to clipboard
Link copied to clipboard
fun interface InitialStateProvider
Link copied to clipboard
interface Input

Something a user sent.

Link copied to clipboard
enum Keying : Enum<Keying>

How a transport turns an incoming update into a ConversationKey.

Link copied to clipboard
data class Location(val chatId: Long, val messageId: Long, val latitude: Double, val longitude: Double) : Input
Link copied to clipboard
data class Message(val chatId: Long, val text: String) : Input
Link copied to clipboard
data class MessageText(val pieces: List<TextPiece>)

A message body as a document, not as a string a server parses.

Link copied to clipboard
Link copied to clipboard
annotation class MessageTextDsl
Link copied to clipboard
data class Photo(val chatId: Long, val messageId: Long, val file: FileRef, val caption: String? = null) : Input

A photo. Telegram offers several sizes of one; file is the one the transport designates, and telek models no others — a bot that needs a particular size asks the transport for it, which is out of this model on purpose.

Link copied to clipboard
interface State
Link copied to clipboard
Link copied to clipboard
interface StateMachine<S : State, I : Input>
Link copied to clipboard
interface StateStorage<S : State>
Link copied to clipboard
class Telek(scope: CoroutineScope = CoroutineScope(Dispatchers.Default), userStateStore: UserStateStore = DefaultUserStateStore(), dispatchers: List<StateDispatcher<out State>>, initialStateProvider: InitialStateProvider = InitialStateProvider { EmptyState }, interceptors: List<TelekInterceptor> = emptyList(), effectExecutor: EffectExecutor, findDispatcherStrategy: FindDispatcherStrategy = DefaultFindDispatcherStrategy(dispatchers), chatWorkerIdleTimeout: Duration = 15.minutes, chatInboxCapacity: Int = 64, logger: TelekLogger = TelekLogger.NoOp)
Link copied to clipboard
Link copied to clipboard
interface TelekLogger

telek's own logging seam: println/java.util.logging are not acceptable in a library, since the consumer can neither redirect nor silence them. Pass an implementation that forwards to whatever the consumer already uses (slf4j, kotlin-logging, ...) — telek has no opinion on the concrete backend and does not depend on one.

Link copied to clipboard
Link copied to clipboard
data class TextEntity(val type: TextEntityType, val offset: Int, val length: Int, val url: String? = null, val language: String? = null)

A MessageText flattened the way the Bot API wants it: plain text plus ranges over it.

Link copied to clipboard
Link copied to clipboard
sealed interface TextPiece

One node of a MessageText.

Link copied to clipboard

The styles that wrap other pieces. See TextPiece.Code for the two that do not.

Link copied to clipboard
Link copied to clipboard
interface TransitionGate<S : State>
Link copied to clipboard
data class TransitionResult<S : State>(val newState: S, val effects: List<Effect> = emptyList())
Link copied to clipboard
data class UpdateResult(val oldState: State?, val newState: State, val effects: List<Effect>, val dispatcher: StateDispatcher<out State>?)
Link copied to clipboard
interface UserStateStore

Stores one FSM state per ConversationKey — which is a chat, or a person within a chat; see ConversationKey for why that is not the same as the chat a reply is addressed to.

Link copied to clipboard
annotation class WizardDsl

Properties

Link copied to clipboard
expect val telekIoDispatcher: CoroutineDispatcher

The dispatcher telek runs blocking-capable work on — synchronous EffectHandlers (see EffectExecutorImpl) and, in :persistence, file I/O.

actual val telekIoDispatcher: CoroutineDispatcher

The dispatcher telek runs blocking-capable work on — synchronous EffectHandlers (see EffectExecutorImpl) and, in :persistence, file I/O.

actual val telekIoDispatcher: CoroutineDispatcher

Dispatchers.IO is unreachable from a Kotlin/Native source set: kotlinx-coroutines declares the public one as an expect extension in its concurrent source set, but Dispatchers on Native also has an internal val IO member, and a member always shadows an extension — so the reference resolves to the internal one and fails to compile outside kotlinx-coroutines itself.

Functions

Link copied to clipboard

Parses Message.text as a command, or returns null when it is not one.

Link copied to clipboard

The entities for this message, in the order their ranges open.

Link copied to clipboard

Builds a MessageText outside a transition — useful when a message is assembled elsewhere.

Link copied to clipboard
Link copied to clipboard
inline fun <S : State> transition(block: TransitionBuilder<S>.() -> Unit): TransitionResult<S>