telega/flow/registry

FlowRegistry and router integration.

Types

Flow registry for centralized flow management

pub opaque type FlowRegistry(session, error, dependencies)

Values

pub fn apply_to_router(
  router: router.Router(session, error, dependencies),
  registry: FlowRegistry(session, error, dependencies),
) -> router.Router(session, error, dependencies)

Apply all registered flows to a router.

Besides each flow’s own trigger route this installs the auto-resume catch-alls: any text, any callback payload, and photo, video, voice, audio, location and command updates. Two things follow, and both matter for a bot that has routes of its own — apply the registry LAST, after those routes.

  • Patterns are ranked, so the catch-alls lose. on_text(Prefix("x")) and on_callback(Prefix("x:")) are more specific than the Prefix("") the registry adds, and the router picks the most specific match — the bot’s route still runs.
  • Typed input routes are TAKEN OVER. A photo, video, voice, audio, location or plain command carries no pattern to rank, so the registry’s handler wins over one the bot registered for the same input type, and when no flow is waiting the update is dropped rather than passed on. A bot that needs its own on_photo alongside flows should start those flows from a command or callback trigger and handle the media itself.

Commands registered with on_command are exempt: they dispatch by exact name, so only an UNREGISTERED command reaches the flow’s command resume.

pub fn call_flow(
  ctx ctx: bot.Context(session, error, dependencies),
  registry registry: FlowRegistry(session, error, dependencies),
  name flow_name: String,
  initial initial_data: dict.Dict(String, String),
) -> Result(bot.Context(session, error, dependencies), error)

Call a registered flow from any handler

pub fn cancel_flow_instance(
  registry: FlowRegistry(session, error, dependencies),
  flow_id flow_id: String,
) -> Result(Bool, error)

Cancel a specific flow instance by ID, without running its on_flow_exit hook. See cancel_flow_instance_for for the hook-running variant.

pub fn cancel_flow_instance_for(
  registry registry: FlowRegistry(session, error, dependencies),
  ctx ctx: bot.Context(session, error, dependencies),
  flow_id flow_id: String,
) -> Result(
  #(bot.Context(session, error, dependencies), Bool),
  error,
)

Cancel a specific flow instance by ID, running its on_flow_exit hook.

pub fn cancel_user_flows(
  registry: FlowRegistry(session, error, dependencies),
  user_id user_id: Int,
  chat_id chat_id: Int,
) -> Result(List(String), error)

Cancel all flows for a user in a chat, without running their on_flow_exit hooks — those take a Context this variant has none of.

Use it from admin tooling, cron jobs and shutdown paths. From a handler prefer cancel_user_flows_for, which does run the hooks.

pub fn cancel_user_flows_for(
  registry registry: FlowRegistry(session, error, dependencies),
  ctx ctx: bot.Context(session, error, dependencies),
  user_id user_id: Int,
  chat_id chat_id: Int,
) -> Result(
  #(bot.Context(session, error, dependencies), List(String)),
  error,
)

Cancel every flow the context’s user has running in this chat, running each flow’s on_flow_exit hook — this is what /cancel uses, and what a dialog relies on to take its live keyboard down.

Returns the cancelled instance ids. A hook that fails is reported through the flow’s own error handling; the instance is deleted either way.

pub fn new_registry() -> FlowRegistry(
  session,
  error,
  dependencies,
)

Create a new empty flow registry

pub fn refresh_flow(
  ctx ctx: bot.Context(session, error, dependencies),
  registry registry: FlowRegistry(session, error, dependencies),
  name flow_name: String,
) -> Result(
  #(bot.Context(session, error, dependencies), Bool),
  error,
)

Re-execute the current step of a user’s running flow — the render side of a flow, without advancing it.

Unlike call_flow this never starts anything: a user with no running instance of name is left alone and False comes back. Pair it with telega.background_context to refresh what a user is looking at from a job that finished elsewhere.

pub fn register(
  registry: FlowRegistry(session, error, dependencies),
  trigger: types.FlowTrigger,
  flow: types.Flow(step_type, session, error, dependencies),
) -> FlowRegistry(session, error, dependencies)

Add a flow to the registry with a trigger

pub fn register_callable(
  registry: FlowRegistry(session, error, dependencies),
  flow: types.Flow(step_type, session, error, dependencies),
) -> FlowRegistry(session, error, dependencies)

Register a flow without a trigger (for calling from handlers)

pub fn register_cancel_command(
  registry: FlowRegistry(session, error, dependencies),
  command: String,
) -> FlowRegistry(session, error, dependencies)

Register a cancel command that cancels all active flows for the user

pub fn register_cancel_command_with(
  registry: FlowRegistry(session, error, dependencies),
  command: String,
  on_cancel: fn(
    bot.Context(session, error, dependencies),
    List(String),
  ) -> Result(bot.Context(session, error, dependencies), error),
) -> FlowRegistry(session, error, dependencies)

Register a cancel command with a custom callback

pub fn register_with_data(
  registry: FlowRegistry(session, error, dependencies),
  trigger: types.FlowTrigger,
  flow: types.Flow(step_type, session, error, dependencies),
  initial_data: dict.Dict(String, String),
) -> FlowRegistry(session, error, dependencies)

Add a flow to the registry with a trigger and initial data

pub fn to_handler(
  flow flow: types.Flow(step_type, session, error, dependencies),
) -> fn(bot.Context(session, error, dependencies), update.Command) -> Result(
  bot.Context(session, error, dependencies),
  error,
)

Create a router handler that starts a flow

pub fn with_callback_filter(
  registry: FlowRegistry(session, error, dependencies),
  flow_name flow_name: String,
  filter filter: fn(String) -> Bool,
) -> FlowRegistry(session, error, dependencies)

Restrict a registered flow’s callback auto-resume to payloads accepted by filter. Auto-resume normally delivers a callback to the first waiting flow regardless of payload; with a filter, a press that belongs to another flow’s keyboard skips this one and reaches its real target. Used by the dialog engine, whose payloads are self-identifying (dlg:<dialog_id>:...).

pub fn with_orphan_callback_handler(
  registry: FlowRegistry(session, error, dependencies),
  matches matches: fn(String) -> Bool,
  handler handler: fn(
    bot.Context(session, error, dependencies),
    String,
  ) -> Result(bot.Context(session, error, dependencies), error),
) -> FlowRegistry(session, error, dependencies)

Handle callback payloads that no waiting flow consumed. Handlers are tried in registration order; the first whose matches accepts the raw payload runs. Used by dialogs to answer presses on messages of already finished dialogs (otherwise the spinner hangs and the press is silently swallowed by the registry’s catch-all route).

Search Document