-module(telega@flow). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/telega/flow.gleam"). -export([new/4, add_step/3, add_step_with_middleware/4, add_step_with_hooks/5, add_step_with_hooks_and_middleware/6, add_global_middleware/2, add_conditional/5, add_multi_conditional/4, add_parallel_steps/4, parallel/4, add_subflow/6, inline_next/3, on_complete/2, on_error/2, set_on_flow_enter/2, set_on_flow_leave/2, set_on_flow_exit/2, build/2, next/3, unsafe_next/3, goto/3, back/2, complete/2, cancel/2, wait/3, wait_callback/3, exit/3, enter_subflow/4, return_from_subflow/3, get_current_step/2, store_step_data/3, get_step_data/2, clear_step_data/1, clear_step_data_key/2, is_callback_passed/3, store_data/3, get_data/2, next_with_data/5, create_memory_storage/0, new_with_default_converters/3, text_step/3, message_step/2, with_inline_subflow/6, with_inline_subflow_mapped/8, new_registry/0, register_with_data/4, register/3, register_callable/2, validation_middleware/1, create_text_handler/1, call_flow/4, to_handler/1, create_resume_handler/1, create_resume_handler_with_keyboard/2, apply_to_router/2, compose_conditional/4, compose_parallel/4, compose_sequential/3]). -export_type([flow_state/0, flow_stack_frame/0, parallel_state/0, flow_instance/0, flow_storage/1, flow_builder/3, flow/3, flow_registry/2, step_config/3, conditional_transition/1, parallel_config/1, subflow_config/3, flow_action/1, inline_step/0, flow_trigger/0, composed_step/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Type-safe, persistent flow system for building multi-step conversational interactions.\n" "\n" " ## Core Concepts\n" "\n" " - **Flow** - State machine for multi-step conversations with compile-time validated transitions\n" " - **FlowRegistry** - Central container managing all flows, supporting triggers and manual calls\n" " - **Storage** - Pluggable persistence (database, memory, Redis) with automatic state recovery\n" "\n" " ## Quick Start\n" "\n" " ```gleam\n" " // 1. Define flow steps\n" " pub type OnboardingStep {\n" " Welcome\n" " CollectName\n" " CollectEmail\n" " Complete\n" " }\n" "\n" " // 2. Build flow with handlers\n" " let onboarding_flow =\n" " flow.new(\"onboarding\", storage, step_to_string, string_to_step)\n" " |> flow.add_step(Welcome, welcome_handler)\n" " |> flow.add_step(CollectName, name_handler)\n" " |> flow.add_step(CollectEmail, email_handler)\n" " |> flow.add_step(Complete, complete_handler)\n" " |> flow.build(initial: Welcome)\n" "\n" " // 3. Register and apply to router\n" " let flow_registry =\n" " flow.new_registry()\n" " |> flow.register(flow.OnCommand(\"/start\"), onboarding_flow)\n" "\n" " router |> flow.apply_to_router(flow_registry)\n" " ```\n" "\n" " ## Advanced Usage\n" "\n" " ```gleam\n" " // Call flow from any handler\n" " fn my_handler(ctx, _data) {\n" " let initial_data = dict.from_list([#(\"product_id\", \"123\")])\n" " flow.call_flow(ctx, flow_registry, \"checkout\", initial_data)\n" " }\n" "\n" " // Conditional transitions\n" " |> flow.add_conditional(\n" " from: CollectAge,\n" " condition: fn(instance) {\n" " case flow.get_data(instance, \"age\") {\n" " Some(age) -> int.parse(age) |> result.unwrap(0) >= 18\n" " None -> False\n" " }\n" " },\n" " true: AdultFlow,\n" " false: MinorFlow\n" " )\n" "\n" " // Parallel step execution\n" " |> flow.add_parallel_steps(\n" " trigger_step: StartVerification,\n" " parallel_steps: [EmailVerify, PhoneVerify, DocumentVerify],\n" " join_at: VerificationComplete\n" " )\n" " ```\n" ). -type flow_state() :: {flow_state, binary(), gleam@dict:dict(binary(), binary()), list(binary()), list(flow_stack_frame()), gleam@option:option(parallel_state())}. -type flow_stack_frame() :: {flow_stack_frame, binary(), binary(), gleam@dict:dict(binary(), binary())}. -type parallel_state() :: {parallel_state, list(binary()), list(binary()), gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary())), binary()}. -type flow_instance() :: {flow_instance, binary(), binary(), integer(), integer(), flow_state(), gleam@dict:dict(binary(), binary()), gleam@option:option(binary()), integer(), integer()}. -type flow_storage(ATUN) :: {flow_storage, fun((flow_instance()) -> {ok, nil} | {error, ATUN}), fun((binary()) -> {ok, gleam@option:option(flow_instance())} | {error, ATUN}), fun((binary()) -> {ok, nil} | {error, ATUN}), fun((integer(), integer()) -> {ok, list(flow_instance())} | {error, ATUN})}. -opaque flow_builder(ATUO, ATUP, ATUQ) :: {flow_builder, binary(), gleam@dict:dict(binary(), step_config(ATUO, ATUP, ATUQ)), fun((ATUO) -> binary()), fun((binary()) -> {ok, ATUO} | {error, nil}), flow_storage(ATUQ), gleam@option:option(fun((telega@bot:context(ATUP, ATUQ), flow_instance()) -> {ok, telega@bot:context(ATUP, ATUQ)} | {error, ATUQ})), gleam@option:option(fun((telega@bot:context(ATUP, ATUQ), flow_instance(), gleam@option:option(ATUQ)) -> {ok, telega@bot:context(ATUP, ATUQ)} | {error, ATUQ})), list(fun((telega@bot:context(ATUP, ATUQ), flow_instance(), fun(() -> {ok, {telega@bot:context(ATUP, ATUQ), flow_action(ATUO), flow_instance()}} | {error, ATUQ})) -> {ok, {telega@bot:context(ATUP, ATUQ), flow_action(ATUO), flow_instance()}} | {error, ATUQ})), list(conditional_transition(ATUO)), list(parallel_config(ATUO)), list(subflow_config(ATUO, ATUP, ATUQ)), gleam@option:option(fun((telega@bot:context(ATUP, ATUQ), flow_instance()) -> {ok, {telega@bot:context(ATUP, ATUQ), flow_instance()}} | {error, ATUQ})), gleam@option:option(fun((telega@bot:context(ATUP, ATUQ), flow_instance()) -> {ok, {telega@bot:context(ATUP, ATUQ), flow_instance()}} | {error, ATUQ})), gleam@option:option(fun((telega@bot:context(ATUP, ATUQ), flow_instance()) -> {ok, telega@bot:context(ATUP, ATUQ)} | {error, ATUQ}))}. -opaque flow(ATUR, ATUS, ATUT) :: {flow, binary(), gleam@dict:dict(binary(), step_config(ATUR, ATUS, ATUT)), ATUR, fun((ATUR) -> binary()), fun((binary()) -> {ok, ATUR} | {error, nil}), flow_storage(ATUT), gleam@option:option(fun((telega@bot:context(ATUS, ATUT), flow_instance()) -> {ok, telega@bot:context(ATUS, ATUT)} | {error, ATUT})), gleam@option:option(fun((telega@bot:context(ATUS, ATUT), flow_instance(), gleam@option:option(ATUT)) -> {ok, telega@bot:context(ATUS, ATUT)} | {error, ATUT})), list(fun((telega@bot:context(ATUS, ATUT), flow_instance(), fun(() -> {ok, {telega@bot:context(ATUS, ATUT), flow_action(ATUR), flow_instance()}} | {error, ATUT})) -> {ok, {telega@bot:context(ATUS, ATUT), flow_action(ATUR), flow_instance()}} | {error, ATUT})), list(conditional_transition(ATUR)), list(parallel_config(ATUR)), list(subflow_config(ATUR, ATUS, ATUT)), gleam@option:option(fun((telega@bot:context(ATUS, ATUT), flow_instance()) -> {ok, {telega@bot:context(ATUS, ATUT), flow_instance()}} | {error, ATUT})), gleam@option:option(fun((telega@bot:context(ATUS, ATUT), flow_instance()) -> {ok, {telega@bot:context(ATUS, ATUT), flow_instance()}} | {error, ATUT})), gleam@option:option(fun((telega@bot:context(ATUS, ATUT), flow_instance()) -> {ok, telega@bot:context(ATUS, ATUT)} | {error, ATUT}))}. -opaque flow_registry(ATUU, ATUV) :: {flow_registry, list({flow_trigger(), flow(gleam@dynamic:dynamic_(), ATUU, ATUV), gleam@dict:dict(binary(), binary())}), gleam@dict:dict(binary(), flow(gleam@dynamic:dynamic_(), ATUU, ATUV))}. -type step_config(ATUW, ATUX, ATUY) :: {step_config, fun((telega@bot:context(ATUX, ATUY), flow_instance()) -> {ok, {telega@bot:context(ATUX, ATUY), flow_action(ATUW), flow_instance()}} | {error, ATUY}), list(fun((telega@bot:context(ATUX, ATUY), flow_instance(), fun(() -> {ok, {telega@bot:context(ATUX, ATUY), flow_action(ATUW), flow_instance()}} | {error, ATUY})) -> {ok, {telega@bot:context(ATUX, ATUY), flow_action(ATUW), flow_instance()}} | {error, ATUY})), gleam@option:option(fun((telega@bot:context(ATUX, ATUY), flow_instance()) -> {ok, {telega@bot:context(ATUX, ATUY), flow_instance()}} | {error, ATUY})), gleam@option:option(fun((telega@bot:context(ATUX, ATUY), flow_instance()) -> {ok, {telega@bot:context(ATUX, ATUY), flow_instance()}} | {error, ATUY}))}. -type conditional_transition(ATUZ) :: {conditional_transition, binary(), list({fun((flow_instance()) -> boolean()), ATUZ}), ATUZ}. -type parallel_config(ATVA) :: {parallel_config, binary(), list(ATVA), ATVA}. -type subflow_config(ATVB, ATVC, ATVD) :: {subflow_config, binary(), flow(gleam@dynamic:dynamic_(), ATVC, ATVD), ATVB, fun((flow_instance()) -> gleam@dict:dict(binary(), binary())), fun((gleam@dict:dict(binary(), binary()), flow_instance()) -> flow_instance())}. -type flow_action(ATVE) :: {next, ATVE} | {next_string, binary()} | back | {complete, gleam@dict:dict(binary(), binary())} | cancel | {wait, binary()} | {wait_callback, binary()} | {go_to, ATVE} | {exit, gleam@option:option(gleam@dict:dict(binary(), binary()))} | {return_from_subflow, gleam@dict:dict(binary(), binary())} | {start_parallel, list(ATVE), ATVE} | {complete_parallel_step, ATVE, gleam@dict:dict(binary(), binary())} | {enter_subflow, binary(), gleam@dict:dict(binary(), binary())}. -type inline_step() :: {inline_step, binary()}. -type flow_trigger() :: {on_command, binary()} | {on_text, telega@router:pattern()} | {on_callback, telega@router:pattern()} | {on_filtered, telega@router:filter()} | on_photo | on_video | on_audio | on_voice | on_any_text. -type composed_step() :: {composed_flow_step, integer()} | composed_select_flow | composed_start_parallel | {composed_parallel_flow, integer()} | composed_merge_results. -file("src/telega/flow.gleam", 316). ?DOC(" Create a new flow builder\n"). -spec new( binary(), flow_storage(ATXU), fun((ATXW) -> binary()), fun((binary()) -> {ok, ATXW} | {error, nil}) ) -> flow_builder(ATXW, any(), ATXU). new(Flow_name, Storage, Step_to_string, String_to_step) -> {flow_builder, Flow_name, maps:new(), Step_to_string, String_to_step, Storage, none, none, [], [], [], [], none, none, none}. -file("src/telega/flow.gleam", 365). ?DOC(" Add a step to the flow\n"). -spec add_step( flow_builder(ATYL, ATYM, ATYN), ATYL, fun((telega@bot:context(ATYM, ATYN), flow_instance()) -> {ok, {telega@bot:context(ATYM, ATYN), flow_action(ATYL), flow_instance()}} | {error, ATYN}) ) -> flow_builder(ATYL, ATYM, ATYN). add_step(Builder, Step, Handler) -> Step_name = (erlang:element(4, Builder))(Step), Config = {step_config, Handler, [], none, none}, {flow_builder, erlang:element(2, Builder), gleam@dict:insert(erlang:element(3, Builder), Step_name, Config), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 377). ?DOC(" Add a step with middleware\n"). -spec add_step_with_middleware( flow_builder(ATYX, ATYY, ATYZ), ATYX, list(fun((telega@bot:context(ATYY, ATYZ), flow_instance(), fun(() -> {ok, {telega@bot:context(ATYY, ATYZ), flow_action(ATYX), flow_instance()}} | {error, ATYZ})) -> {ok, {telega@bot:context(ATYY, ATYZ), flow_action(ATYX), flow_instance()}} | {error, ATYZ})), fun((telega@bot:context(ATYY, ATYZ), flow_instance()) -> {ok, {telega@bot:context(ATYY, ATYZ), flow_action(ATYX), flow_instance()}} | {error, ATYZ}) ) -> flow_builder(ATYX, ATYY, ATYZ). add_step_with_middleware(Builder, Step, Middlewares, Handler) -> Step_name = (erlang:element(4, Builder))(Step), Config = {step_config, Handler, Middlewares, none, none}, {flow_builder, erlang:element(2, Builder), gleam@dict:insert(erlang:element(3, Builder), Step_name, Config), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 409). ?DOC( " Add a step with lifecycle hooks\n" "\n" " ## Example\n" "\n" " ```gleam\n" " flow.new(\"checkout\", storage, step_to_string, string_to_step)\n" " |> flow.add_step_with_hooks(\n" " Payment,\n" " handler: payment_handler,\n" " on_enter: Some(fn(ctx, instance) {\n" " // Log payment step entry\n" " use _ <- result.try(reply.with_text(ctx, \"Entering payment...\"))\n" " Ok(#(ctx, instance))\n" " }),\n" " on_leave: Some(fn(ctx, instance) {\n" " // Cleanup or log\n" " Ok(#(ctx, instance))\n" " }),\n" " )\n" " ```\n" ). -spec add_step_with_hooks( flow_builder(ATZN, ATZO, ATZP), ATZN, fun((telega@bot:context(ATZO, ATZP), flow_instance()) -> {ok, {telega@bot:context(ATZO, ATZP), flow_action(ATZN), flow_instance()}} | {error, ATZP}), gleam@option:option(fun((telega@bot:context(ATZO, ATZP), flow_instance()) -> {ok, {telega@bot:context(ATZO, ATZP), flow_instance()}} | {error, ATZP})), gleam@option:option(fun((telega@bot:context(ATZO, ATZP), flow_instance()) -> {ok, {telega@bot:context(ATZO, ATZP), flow_instance()}} | {error, ATZP})) ) -> flow_builder(ATZN, ATZO, ATZP). add_step_with_hooks(Builder, Step, Handler, On_enter, On_leave) -> Step_name = (erlang:element(4, Builder))(Step), Config = {step_config, Handler, [], On_enter, On_leave}, {flow_builder, erlang:element(2, Builder), gleam@dict:insert(erlang:element(3, Builder), Step_name, Config), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 422). ?DOC(" Add a step with hooks and middleware\n"). -spec add_step_with_hooks_and_middleware( flow_builder(AUAF, AUAG, AUAH), AUAF, fun((telega@bot:context(AUAG, AUAH), flow_instance()) -> {ok, {telega@bot:context(AUAG, AUAH), flow_action(AUAF), flow_instance()}} | {error, AUAH}), list(fun((telega@bot:context(AUAG, AUAH), flow_instance(), fun(() -> {ok, {telega@bot:context(AUAG, AUAH), flow_action(AUAF), flow_instance()}} | {error, AUAH})) -> {ok, {telega@bot:context(AUAG, AUAH), flow_action(AUAF), flow_instance()}} | {error, AUAH})), gleam@option:option(fun((telega@bot:context(AUAG, AUAH), flow_instance()) -> {ok, {telega@bot:context(AUAG, AUAH), flow_instance()}} | {error, AUAH})), gleam@option:option(fun((telega@bot:context(AUAG, AUAH), flow_instance()) -> {ok, {telega@bot:context(AUAG, AUAH), flow_instance()}} | {error, AUAH})) ) -> flow_builder(AUAF, AUAG, AUAH). add_step_with_hooks_and_middleware( Builder, Step, Handler, Middlewares, On_enter, On_leave ) -> Step_name = (erlang:element(4, Builder))(Step), Config = {step_config, Handler, Middlewares, On_enter, On_leave}, {flow_builder, erlang:element(2, Builder), gleam@dict:insert(erlang:element(3, Builder), Step_name, Config), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 436). ?DOC(" Add global middleware that applies to all steps\n"). -spec add_global_middleware( flow_builder(AUBB, AUBC, AUBD), fun((telega@bot:context(AUBC, AUBD), flow_instance(), fun(() -> {ok, {telega@bot:context(AUBC, AUBD), flow_action(AUBB), flow_instance()}} | {error, AUBD})) -> {ok, {telega@bot:context(AUBC, AUBD), flow_action(AUBB), flow_instance()}} | {error, AUBD}) ) -> flow_builder(AUBB, AUBC, AUBD). add_global_middleware(Builder, Middleware) -> {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), lists:append(erlang:element(9, Builder), [Middleware]), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 447). ?DOC(" Add conditional transition\n"). -spec add_conditional( flow_builder(AUBN, AUBO, AUBP), AUBN, fun((flow_instance()) -> boolean()), AUBN, AUBN ) -> flow_builder(AUBN, AUBO, AUBP). add_conditional(Builder, From, Condition, On_true, On_false) -> From_str = (erlang:element(4, Builder))(From), Conditional = {conditional_transition, From_str, [{Condition, On_true}], On_false}, {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), lists:append(erlang:element(10, Builder), [Conditional]), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 468). ?DOC(" Add multi-way conditional\n"). -spec add_multi_conditional( flow_builder(AUBW, AUBX, AUBY), AUBW, list({fun((flow_instance()) -> boolean()), AUBW}), AUBW ) -> flow_builder(AUBW, AUBX, AUBY). add_multi_conditional(Builder, From, Conditions, Default) -> From_str = (erlang:element(4, Builder))(From), Conditional = {conditional_transition, From_str, Conditions, Default}, {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), lists:append(erlang:element(10, Builder), [Conditional]), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 516). ?DOC( " Add parallel step execution.\n" "\n" " @deprecated Use `parallel()` instead for cleaner API.\n" ). -spec add_parallel_steps(flow_builder(AUCQ, AUCR, AUCS), AUCQ, list(AUCQ), AUCQ) -> flow_builder(AUCQ, AUCR, AUCS). add_parallel_steps(Builder, Trigger_step, Parallel_steps, Join_at) -> Trigger_str = (erlang:element(4, Builder))(Trigger_step), Config = {parallel_config, Trigger_str, Parallel_steps, Join_at}, {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), lists:append(erlang:element(11, Builder), [Config]), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 504). ?DOC( " Add parallel step execution (simplified API).\n" "\n" " This is the recommended way to add parallel steps to a flow.\n" " When the flow reaches `from` step, it will execute all `steps` in parallel,\n" " and automatically transition to `join` step when all parallel steps complete.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " flow.new(\"kyc_verification\", storage, to_string, from_string)\n" " |> flow.add_step(Start, start_handler)\n" " |> flow.add_step(EmailVerify, email_handler)\n" " |> flow.add_step(PhoneVerify, phone_handler)\n" " |> flow.add_step(DocumentVerify, document_handler)\n" " |> flow.parallel(\n" " from: Start,\n" " steps: [EmailVerify, PhoneVerify, DocumentVerify],\n" " join: AllComplete,\n" " )\n" " |> flow.add_step(AllComplete, complete_handler)\n" " |> flow.build(initial: Start)\n" " ```\n" ). -spec parallel(flow_builder(AUCG, AUCH, AUCI), AUCG, list(AUCG), AUCG) -> flow_builder(AUCG, AUCH, AUCI). parallel(Builder, From, Steps, Join) -> add_parallel_steps(Builder, From, Steps, Join). -file("src/telega/flow.gleam", 562). ?DOC( " Add sub-flow\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let address_flow =\n" " flow.new(\"address\", storage, step_to_string, string_to_step)\n" " |> flow.add_step(Street, street_handler)\n" " |> flow.build(initial: Street)\n" "\n" " let checkout_flow =\n" " flow.new(\"checkout\", storage, step_to_string, string_to_step)\n" " |> flow.add_step(Cart, cart_handler)\n" " |> flow.add_subflow(\n" " trigger_step: CollectAddress,\n" " subflow: address_flow,\n" " return_to: Payment,\n" " map_args: fn(instance) { instance.state.data },\n" " map_result: fn(result, instance) {\n" " FlowInstance(..instance, state: FlowState(\n" " ..instance.state,\n" " data: dict.merge(instance.state.data, result)\n" " ))\n" " },\n" " )\n" " |> flow.build(initial: Cart)\n" " ```\n" ). -spec add_subflow( flow_builder(AUDA, AUDB, AUDC), AUDA, flow(gleam@dynamic:dynamic_(), AUDB, AUDC), AUDA, fun((flow_instance()) -> gleam@dict:dict(binary(), binary())), fun((gleam@dict:dict(binary(), binary()), flow_instance()) -> flow_instance()) ) -> flow_builder(AUDA, AUDB, AUDC). add_subflow(Builder, Trigger_step, Subflow, Return_to, Map_args, Map_result) -> Trigger_str = (erlang:element(4, Builder))(Trigger_step), Config = {subflow_config, Trigger_str, Subflow, Return_to, Map_args, Map_result}, {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), lists:append(erlang:element(12, Builder), [Config]), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 722). -spec inline_step_to_string(inline_step()) -> binary(). inline_step_to_string(Step) -> erlang:element(2, Step). -file("src/telega/flow.gleam", 726). -spec string_to_inline_step(binary()) -> {ok, inline_step()} | {error, nil}. string_to_inline_step(S) -> {ok, {inline_step, S}}. -file("src/telega/flow.gleam", 731). ?DOC(" Navigate to next inline step by name\n"). -spec inline_next(telega@bot:context(AUFA, AUFB), flow_instance(), binary()) -> {ok, {telega@bot:context(AUFA, AUFB), flow_action(inline_step()), flow_instance()}} | {error, AUFB}. inline_next(Ctx, Instance, Step_name) -> {ok, {Ctx, {next, {inline_step, Step_name}}, Instance}}. -file("src/telega/flow.gleam", 740). ?DOC(" Set completion handler\n"). -spec on_complete( flow_builder(AUFH, AUFI, AUFJ), fun((telega@bot:context(AUFI, AUFJ), flow_instance()) -> {ok, telega@bot:context(AUFI, AUFJ)} | {error, AUFJ}) ) -> flow_builder(AUFH, AUFI, AUFJ). on_complete(Builder, Handler) -> {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), {some, Handler}, erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 749). ?DOC(" Set error handler\n"). -spec on_error( flow_builder(AUFW, AUFX, AUFY), fun((telega@bot:context(AUFX, AUFY), flow_instance(), gleam@option:option(AUFY)) -> {ok, telega@bot:context(AUFX, AUFY)} | {error, AUFY}) ) -> flow_builder(AUFW, AUFX, AUFY). on_error(Builder, Handler) -> {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), {some, Handler}, erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 773). ?DOC( " Set flow enter hook\n" "\n" " Called when the flow is first started or resumed from a parent flow.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " flow.new(\"checkout\", storage, step_to_string, string_to_step)\n" " |> flow.set_on_flow_enter(fn(ctx, instance) {\n" " use ctx <- result.try(\n" " reply.with_text(ctx, \"Welcome to checkout!\")\n" " |> result.map_error(fn(e) { e })\n" " )\n" " Ok(#(ctx, instance))\n" " })\n" " ```\n" ). -spec set_on_flow_enter( flow_builder(AUGM, AUGN, AUGO), fun((telega@bot:context(AUGN, AUGO), flow_instance()) -> {ok, {telega@bot:context(AUGN, AUGO), flow_instance()}} | {error, AUGO}) ) -> flow_builder(AUGM, AUGN, AUGO). set_on_flow_enter(Builder, Hook) -> {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), {some, Hook}, erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 793). ?DOC( " Set flow leave hook\n" "\n" " Called when transitioning to a subflow.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " flow.new(\"checkout\", storage, step_to_string, string_to_step)\n" " |> flow.set_on_flow_leave(fn(ctx, instance) {\n" " // Save state before entering subflow\n" " Ok(#(ctx, instance))\n" " })\n" " ```\n" ). -spec set_on_flow_leave( flow_builder(AUGX, AUGY, AUGZ), fun((telega@bot:context(AUGY, AUGZ), flow_instance()) -> {ok, {telega@bot:context(AUGY, AUGZ), flow_instance()}} | {error, AUGZ}) ) -> flow_builder(AUGX, AUGY, AUGZ). set_on_flow_leave(Builder, Hook) -> {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), {some, Hook}, erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 816). ?DOC( " Set flow exit hook\n" "\n" " Called when the flow completes or is cancelled.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " flow.new(\"checkout\", storage, step_to_string, string_to_step)\n" " |> flow.set_on_flow_exit(fn(ctx, instance) {\n" " use _ <- result.try(\n" " reply.with_text(ctx, \"Checkout complete!\")\n" " |> result.map_error(fn(e) { e })\n" " )\n" " Ok(ctx)\n" " })\n" " ```\n" ). -spec set_on_flow_exit( flow_builder(AUHI, AUHJ, AUHK), fun((telega@bot:context(AUHJ, AUHK), flow_instance()) -> {ok, telega@bot:context(AUHJ, AUHK)} | {error, AUHK}) ) -> flow_builder(AUHI, AUHJ, AUHK). set_on_flow_exit(Builder, Hook) -> {flow_builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), {some, Hook}}. -file("src/telega/flow.gleam", 824). ?DOC(" Build the flow\n"). -spec build(flow_builder(AUHT, AUHU, AUHV), AUHT) -> flow(AUHT, AUHU, AUHV). build(Builder, Initial_step) -> {flow, erlang:element(2, Builder), erlang:element(3, Builder), Initial_step, erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder), erlang:element(11, Builder), erlang:element(12, Builder), erlang:element(13, Builder), erlang:element(14, Builder), erlang:element(15, Builder)}. -file("src/telega/flow.gleam", 848). ?DOC(" Next navigation\n"). -spec next(telega@bot:context(AUIC, AUID), flow_instance(), AUIG) -> {ok, {telega@bot:context(AUIC, AUID), flow_action(AUIG), flow_instance()}} | {error, AUID}. next(Ctx, Instance, Step) -> {ok, {Ctx, {next, Step}, Instance}}. -file("src/telega/flow.gleam", 857). ?DOC(" Next navigation with string step (for dynamic navigation)\n"). -spec unsafe_next(telega@bot:context(AUIK, AUIL), flow_instance(), binary()) -> {ok, {telega@bot:context(AUIK, AUIL), flow_action(any()), flow_instance()}} | {error, AUIL}. unsafe_next(Ctx, Instance, Step) -> {ok, {Ctx, {next_string, Step}, Instance}}. -file("src/telega/flow.gleam", 866). ?DOC(" Type-safe goto navigation (clears step data)\n"). -spec goto(telega@bot:context(AUIS, AUIT), flow_instance(), AUIW) -> {ok, {telega@bot:context(AUIS, AUIT), flow_action(AUIW), flow_instance()}} | {error, AUIT}. goto(Ctx, Instance, Step) -> {ok, {Ctx, {go_to, Step}, Instance}}. -file("src/telega/flow.gleam", 875). ?DOC(" Go back to previous step\n"). -spec back(telega@bot:context(AUJA, AUJB), flow_instance()) -> {ok, {telega@bot:context(AUJA, AUJB), flow_action(any()), flow_instance()}} | {error, AUJB}. back(Ctx, Instance) -> {ok, {Ctx, back, Instance}}. -file("src/telega/flow.gleam", 883). ?DOC(" Complete the flow\n"). -spec complete(telega@bot:context(AUJI, AUJJ), flow_instance()) -> {ok, {telega@bot:context(AUJI, AUJJ), flow_action(any()), flow_instance()}} | {error, AUJJ}. complete(Ctx, Instance) -> {ok, {Ctx, {complete, erlang:element(3, erlang:element(6, Instance))}, Instance}}. -file("src/telega/flow.gleam", 891). ?DOC(" Cancel the flow\n"). -spec cancel(telega@bot:context(AUJQ, AUJR), flow_instance()) -> {ok, {telega@bot:context(AUJQ, AUJR), flow_action(any()), flow_instance()}} | {error, AUJR}. cancel(Ctx, Instance) -> {ok, {Ctx, cancel, Instance}}. -file("src/telega/flow.gleam", 899). ?DOC(" Wait for user input\n"). -spec wait(telega@bot:context(AUJY, AUJZ), flow_instance(), binary()) -> {ok, {telega@bot:context(AUJY, AUJZ), flow_action(any()), flow_instance()}} | {error, AUJZ}. wait(Ctx, Instance, Token) -> {ok, {Ctx, {wait, Token}, Instance}}. -file("src/telega/flow.gleam", 908). ?DOC(" Wait for callback\n"). -spec wait_callback(telega@bot:context(AUKG, AUKH), flow_instance(), binary()) -> {ok, {telega@bot:context(AUKG, AUKH), flow_action(any()), flow_instance()}} | {error, AUKH}. wait_callback(Ctx, Instance, Token) -> {ok, {Ctx, {wait_callback, <<<>/binary, (erlang:element(2, Instance))/binary>>}, Instance}}. -file("src/telega/flow.gleam", 917). ?DOC(" Exit with result\n"). -spec exit( telega@bot:context(AUKO, AUKP), flow_instance(), gleam@option:option(gleam@dict:dict(binary(), binary())) ) -> {ok, {telega@bot:context(AUKO, AUKP), flow_action(any()), flow_instance()}} | {error, AUKP}. exit(Ctx, Instance, Result) -> {ok, {Ctx, {exit, Result}, Instance}}. -file("src/telega/flow.gleam", 938). ?DOC( " Enter a subflow by name\n" "\n" " This pushes the current flow state onto the stack and starts the subflow.\n" " When the subflow completes with `return_from_subflow`, execution returns\n" " to the parent flow at the step specified in `add_subflow`.\n" "\n" " ## Example\n" " ```gleam\n" " fn my_handler(ctx, instance) {\n" " // Enter address collection subflow\n" " flow.enter_subflow(ctx, instance, \"address_collection\", dict.new())\n" " }\n" " ```\n" ). -spec enter_subflow( telega@bot:context(AUKZ, AULA), flow_instance(), binary(), gleam@dict:dict(binary(), binary()) ) -> {ok, {telega@bot:context(AUKZ, AULA), flow_action(any()), flow_instance()}} | {error, AULA}. enter_subflow(Ctx, Instance, Subflow_name, Data) -> {ok, {Ctx, {enter_subflow, Subflow_name, Data}, Instance}}. -file("src/telega/flow.gleam", 962). ?DOC( " Return from a subflow with result data\n" "\n" " This pops the parent flow from the stack and merges the result data\n" " into the parent's state, then continues at the return step.\n" "\n" " ## Example\n" " ```gleam\n" " fn final_step_handler(ctx, instance) {\n" " let result = dict.from_list([\n" " #(\"street\", flow.get_data(instance, \"street\") |> option.unwrap(\"\")),\n" " #(\"city\", flow.get_data(instance, \"city\") |> option.unwrap(\"\")),\n" " ])\n" " flow.return_from_subflow(ctx, instance, result)\n" " }\n" " ```\n" ). -spec return_from_subflow( telega@bot:context(AULJ, AULK), flow_instance(), gleam@dict:dict(binary(), binary()) ) -> {ok, {telega@bot:context(AULJ, AULK), flow_action(any()), flow_instance()}} | {error, AULK}. return_from_subflow(Ctx, Instance, Result) -> {ok, {Ctx, {return_from_subflow, Result}, Instance}}. -file("src/telega/flow.gleam", 1062). ?DOC(" Get current step\n"). -spec get_current_step(flow(AUMW, any(), any()), flow_instance()) -> {ok, AUMW} | {error, nil}. get_current_step(Flow, Instance) -> (erlang:element(6, Flow))(erlang:element(2, erlang:element(6, Instance))). -file("src/telega/flow.gleam", 1070). ?DOC(" Store step data\n"). -spec store_step_data(flow_instance(), binary(), binary()) -> flow_instance(). store_step_data(Instance, Key, Value) -> {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), gleam@dict:insert(erlang:element(7, Instance), Key, Value), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance)}. -file("src/telega/flow.gleam", 1082). ?DOC(" Get step data\n"). -spec get_step_data(flow_instance(), binary()) -> gleam@option:option(binary()). get_step_data(Instance, Key) -> _pipe = gleam_stdlib:map_get(erlang:element(7, Instance), Key), gleam@option:from_result(_pipe). -file("src/telega/flow.gleam", 1088). ?DOC(" Clear all step data\n"). -spec clear_step_data(flow_instance()) -> flow_instance(). clear_step_data(Instance) -> {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), maps:new(), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance)}. -file("src/telega/flow.gleam", 1093). ?DOC(" Clear specific step data key\n"). -spec clear_step_data_key(flow_instance(), binary()) -> flow_instance(). clear_step_data_key(Instance, Key) -> {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), gleam@dict:delete(erlang:element(7, Instance), Key), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance)}. -file("src/telega/flow.gleam", 1100). -spec is_callback_passed(flow_instance(), binary(), binary()) -> gleam@option:option(boolean()). is_callback_passed(Instance, Key, Callback_id) -> case get_step_data(Instance, Key) of {some, Data} -> Callback_data = telega@keyboard:bool_callback_data(Callback_id), case telega@keyboard:unpack_callback(Data, Callback_data) of {ok, Callback} -> {some, erlang:element(2, Callback)}; {error, _} -> none end; none -> none end. -file("src/telega/flow.gleam", 1118). ?DOC(" Store data in the flow instance\n"). -spec store_data(flow_instance(), binary(), binary()) -> flow_instance(). store_data(Instance, Key, Value) -> {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record = erlang:element(6, Instance), {flow_state, erlang:element(2, _record), gleam@dict:insert( erlang:element(3, erlang:element(6, Instance)), Key, Value ), erlang:element(4, _record), erlang:element(5, _record), erlang:element(6, _record)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance)}. -file("src/telega/flow.gleam", 1133). ?DOC(" Get data from the flow instance\n"). -spec get_data(flow_instance(), binary()) -> gleam@option:option(binary()). get_data(Instance, Key) -> _pipe = gleam_stdlib:map_get( erlang:element(3, erlang:element(6, Instance)), Key ), _pipe@1 = gleam@result:map(_pipe, fun(Field@0) -> {some, Field@0} end), gleam@result:unwrap(_pipe@1, none). -file("src/telega/flow.gleam", 1140). ?DOC(" Update instance data and continue to next step\n"). -spec next_with_data( telega@bot:context(AUNH, AUNI), flow_instance(), AUNL, binary(), binary() ) -> {ok, {telega@bot:context(AUNH, AUNI), flow_action(AUNL), flow_instance()}} | {error, AUNI}. next_with_data(Ctx, Instance, Step, Key, Value) -> Updated_instance = store_data(Instance, Key, Value), next(Ctx, Updated_instance, Step). -file("src/telega/flow.gleam", 1151). -spec find_instance_by_token(flow_storage(AUNP), binary()) -> {ok, gleam@option:option(flow_instance())} | {error, AUNP}. find_instance_by_token(Storage, Token) -> case gleam@string:split(Token, <<":"/utf8>>) of [Instance_id | _] -> (erlang:element(3, Storage))(Instance_id); _ -> {ok, none} end. -file("src/telega/flow.gleam", 1239). ?DOC(" Run the enter hook if present\n"). -spec run_enter_hook( gleam@option:option(fun((telega@bot:context(AUOG, AUOH), flow_instance()) -> {ok, {telega@bot:context(AUOG, AUOH), flow_instance()}} | {error, AUOH})), telega@bot:context(AUOG, AUOH), flow_instance() ) -> {ok, {telega@bot:context(AUOG, AUOH), flow_instance()}} | {error, AUOH}. run_enter_hook(Hook, Ctx, Instance) -> case Hook of {some, Enter_fn} -> Enter_fn(Ctx, Instance); none -> {ok, {Ctx, Instance}} end. -file("src/telega/flow.gleam", 1251). ?DOC(" Run the leave hook if present\n"). -spec run_leave_hook( gleam@option:option(fun((telega@bot:context(AUOR, AUOS), flow_instance()) -> {ok, {telega@bot:context(AUOR, AUOS), flow_instance()}} | {error, AUOS})), telega@bot:context(AUOR, AUOS), flow_instance() ) -> {ok, {telega@bot:context(AUOR, AUOS), flow_instance()}} | {error, AUOS}. run_leave_hook(Hook, Ctx, Instance) -> case Hook of {some, Leave_fn} -> Leave_fn(Ctx, Instance); none -> {ok, {Ctx, Instance}} end. -file("src/telega/flow.gleam", 1263). ?DOC(" Run the flow enter hook if present\n"). -spec run_flow_enter_hook( gleam@option:option(fun((telega@bot:context(AUPC, AUPD), flow_instance()) -> {ok, {telega@bot:context(AUPC, AUPD), flow_instance()}} | {error, AUPD})), telega@bot:context(AUPC, AUPD), flow_instance() ) -> {ok, {telega@bot:context(AUPC, AUPD), flow_instance()}} | {error, AUPD}. run_flow_enter_hook(Hook, Ctx, Instance) -> case Hook of {some, Enter_fn} -> Enter_fn(Ctx, Instance); none -> {ok, {Ctx, Instance}} end. -file("src/telega/flow.gleam", 1275). ?DOC(" Run the flow leave hook if present\n"). -spec run_flow_leave_hook( gleam@option:option(fun((telega@bot:context(AUPN, AUPO), flow_instance()) -> {ok, {telega@bot:context(AUPN, AUPO), flow_instance()}} | {error, AUPO})), telega@bot:context(AUPN, AUPO), flow_instance() ) -> {ok, {telega@bot:context(AUPN, AUPO), flow_instance()}} | {error, AUPO}. run_flow_leave_hook(Hook, Ctx, Instance) -> case Hook of {some, Leave_fn} -> Leave_fn(Ctx, Instance); none -> {ok, {Ctx, Instance}} end. -file("src/telega/flow.gleam", 1287). ?DOC(" Run the flow exit hook if present\n"). -spec run_flow_exit_hook( gleam@option:option(fun((telega@bot:context(AUPY, AUPZ), flow_instance()) -> {ok, telega@bot:context(AUPY, AUPZ)} | {error, AUPZ})), telega@bot:context(AUPY, AUPZ), flow_instance() ) -> {ok, telega@bot:context(AUPY, AUPZ)} | {error, AUPZ}. run_flow_exit_hook(Hook, Ctx, Instance) -> case Hook of {some, Exit_fn} -> Exit_fn(Ctx, Instance); none -> {ok, Ctx} end. -file("src/telega/flow.gleam", 1668). -spec handle_error( flow(any(), AURN, AURO), telega@bot:context(AURN, AURO), flow_instance(), gleam@option:option(AURO) ) -> {ok, telega@bot:context(AURN, AURO)} | {error, AURO}. handle_error(Flow, Ctx, Instance, Error) -> case erlang:element(9, Flow) of {some, Handler} -> case Handler(Ctx, Instance, Error) of {ok, New_ctx} -> {ok, New_ctx}; {error, _} -> {ok, Ctx} end; none -> {ok, Ctx} end. -file("src/telega/flow.gleam", 1685). -spec generate_flow_id(integer(), integer(), binary()) -> binary(). generate_flow_id(User_id, Chat_id, Flow_name) -> <<<<<<<>/binary, (erlang:integer_to_binary(Chat_id))/binary>>/binary, "_"/utf8>>/binary, (erlang:integer_to_binary(User_id))/binary>>. -file("src/telega/flow.gleam", 1690). ?DOC(" Create in-memory storage (for testing)\n"). -spec create_memory_storage() -> flow_storage(any()). create_memory_storage() -> {flow_storage, fun(_) -> {ok, nil} end, fun(_) -> {ok, none} end, fun(_) -> {ok, nil} end, fun(_, _) -> {ok, []} end}. -file("src/telega/flow.gleam", 1700). ?DOC(" Helper to create a string_to_step function for a list of steps\n"). -spec create_string_to_step(list({binary(), AUSB})) -> fun((binary()) -> {ok, AUSB} | {error, nil}). create_string_to_step(Steps) -> Step_dict = maps:from_list(Steps), fun(Name) -> gleam_stdlib:map_get(Step_dict, Name) end. -file("src/telega/flow.gleam", 341). ?DOC(" Create a flow builder with default string conversion (uses string.inspect)\n"). -spec new_with_default_converters( binary(), flow_storage(ATYD), list({binary(), ATYF}) ) -> flow_builder(ATYF, any(), ATYD). new_with_default_converters(Flow_name, Storage, Steps) -> {flow_builder, Flow_name, maps:new(), fun gleam@string:inspect/1, create_string_to_step(Steps), Storage, none, none, [], [], [], [], none, none, none}. -file("src/telega/flow.gleam", 1708). ?DOC(" Generate a unique wait token\n"). -spec generate_wait_token(flow_instance()) -> binary(). generate_wait_token(Instance) -> <<<<(erlang:element(2, Instance))/binary, "_"/utf8>>/binary, (erlang:integer_to_binary(telega@internal@utils:current_time_ms()))/binary>>. -file("src/telega/flow.gleam", 1713). ?DOC(" Create a text input step\n"). -spec text_step(binary(), binary(), AUSF) -> fun((telega@bot:context(AUSG, AUSH), flow_instance()) -> {ok, {telega@bot:context(AUSG, AUSH), flow_action(AUSF), flow_instance()}} | {error, AUSH}). text_step(Prompt, Data_key, Next_step) -> fun(Ctx, Instance) -> case get_step_data(Instance, <<"user_input"/utf8>>) of {some, Value} -> Instance@1 = begin _pipe = Instance, _pipe@1 = store_data(_pipe, Data_key, Value), clear_step_data_key(_pipe@1, <<"user_input"/utf8>>) end, {ok, {Ctx, {next, Next_step}, Instance@1}}; none -> case telega@reply:with_text(Ctx, Prompt) of {ok, _} -> Token = generate_wait_token(Instance), {ok, {Ctx, {wait, Token}, Instance}}; {error, _} -> {ok, {Ctx, cancel, Instance}} end end end. -file("src/telega/flow.gleam", 1741). ?DOC(" Create a message display step\n"). -spec message_step( fun((flow_instance()) -> binary()), gleam@option:option(AUSL) ) -> fun((telega@bot:context(AUSN, AUSO), flow_instance()) -> {ok, {telega@bot:context(AUSN, AUSO), flow_action(AUSL), flow_instance()}} | {error, AUSO}). message_step(Message_fn, Next_step) -> fun(Ctx, Instance) -> Message = Message_fn(Instance), case telega@reply:with_text(Ctx, Message) of {ok, _} -> case Next_step of {some, Step} -> {ok, {Ctx, {next, Step}, Instance}}; none -> {ok, {Ctx, {complete, erlang:element( 3, erlang:element(6, Instance) )}, Instance}} end; {error, _} -> {ok, {Ctx, cancel, Instance}} end end. -file("src/telega/flow.gleam", 1847). ?DOC(" Extract user and chat IDs from context\n"). -spec extract_ids_from_context(telega@bot:context(any(), any())) -> {integer(), integer()}. extract_ids_from_context(Ctx) -> {erlang:element(2, erlang:element(3, Ctx)), erlang:element(3, erlang:element(3, Ctx))}. -file("src/telega/flow.gleam", 1934). -spec unsafe_coerce(any()) -> any(). unsafe_coerce(Value) -> _pipe = Value, _pipe@1 = erlang:term_to_binary(_pipe), erlang:binary_to_term(_pipe@1). -file("src/telega/flow.gleam", 620). ?DOC( " Add an inline subflow defined within the parent flow\n" "\n" " This creates a subflow inline without needing to define a separate flow.\n" " Steps are identified by string names.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let checkout_flow =\n" " flow.new(\"checkout\", storage, step_to_string, string_to_step)\n" " |> flow.add_step(Cart, cart_handler)\n" " |> flow.with_inline_subflow(\n" " name: \"address_collection\",\n" " trigger: CollectAddress,\n" " return_to: Payment,\n" " initial: \"street\",\n" " steps: [\n" " #(\"street\", fn(ctx, instance) {\n" " // Ask for street\n" " flow.wait(ctx, instance, \"street_input\")\n" " }),\n" " #(\"city\", fn(ctx, instance) {\n" " // Ask for city\n" " flow.wait(ctx, instance, \"city_input\")\n" " }),\n" " #(\"done\", fn(ctx, instance) {\n" " flow.return_from_subflow(ctx, instance, instance.state.data)\n" " }),\n" " ],\n" " )\n" " |> flow.add_step(Payment, payment_handler)\n" " |> flow.build(initial: Cart)\n" " ```\n" ). -spec with_inline_subflow( flow_builder(AUDQ, AUDR, AUDS), binary(), AUDQ, AUDQ, binary(), list({binary(), fun((telega@bot:context(AUDR, AUDS), flow_instance()) -> {ok, {telega@bot:context(AUDR, AUDS), flow_action(inline_step()), flow_instance()}} | {error, AUDS})}) ) -> flow_builder(AUDQ, AUDR, AUDS). with_inline_subflow(Builder, Name, Trigger, Return_to, Initial, Steps) -> Inline_flow_name = <<<<(erlang:element(2, Builder))/binary, "::"/utf8>>/binary, Name/binary>>, Inline_storage = erlang:element(6, Builder), Inline_builder = new( Inline_flow_name, Inline_storage, fun inline_step_to_string/1, fun string_to_inline_step/1 ), Inline_builder@1 = gleam@list:fold( Steps, Inline_builder, fun(B, Step_tuple) -> {Step_name, Handler} = Step_tuple, add_step(B, {inline_step, Step_name}, Handler) end ), Inline_flow = build(Inline_builder@1, {inline_step, Initial}), Coerced_flow = unsafe_coerce(Inline_flow), add_subflow( Builder, Trigger, Coerced_flow, Return_to, fun(Instance) -> erlang:element(3, erlang:element(6, Instance)) end, fun(Result, Instance@1) -> {flow_instance, erlang:element(2, Instance@1), erlang:element(3, Instance@1), erlang:element(4, Instance@1), erlang:element(5, Instance@1), begin _record = erlang:element(6, Instance@1), {flow_state, erlang:element(2, _record), maps:merge( erlang:element(3, erlang:element(6, Instance@1)), Result ), erlang:element(4, _record), erlang:element(5, _record), erlang:element(6, _record)} end, erlang:element(7, Instance@1), erlang:element(8, Instance@1), erlang:element(9, Instance@1), erlang:element(10, Instance@1)} end ). -file("src/telega/flow.gleam", 678). ?DOC(" Add an inline subflow with custom argument and result mapping\n"). -spec with_inline_subflow_mapped( flow_builder(AUEF, AUEG, AUEH), binary(), AUEF, AUEF, binary(), list({binary(), fun((telega@bot:context(AUEG, AUEH), flow_instance()) -> {ok, {telega@bot:context(AUEG, AUEH), flow_action(inline_step()), flow_instance()}} | {error, AUEH})}), fun((flow_instance()) -> gleam@dict:dict(binary(), binary())), fun((gleam@dict:dict(binary(), binary()), flow_instance()) -> flow_instance()) ) -> flow_builder(AUEF, AUEG, AUEH). with_inline_subflow_mapped( Builder, Name, Trigger, Return_to, Initial, Steps, Map_args, Map_result ) -> Inline_flow_name = <<<<(erlang:element(2, Builder))/binary, "::"/utf8>>/binary, Name/binary>>, Inline_storage = erlang:element(6, Builder), Inline_builder = new( Inline_flow_name, Inline_storage, fun inline_step_to_string/1, fun string_to_inline_step/1 ), Inline_builder@1 = gleam@list:fold( Steps, Inline_builder, fun(B, Step_tuple) -> {Step_name, Handler} = Step_tuple, add_step(B, {inline_step, Step_name}, Handler) end ), Inline_flow = build(Inline_builder@1, {inline_step, Initial}), Coerced_flow = unsafe_coerce(Inline_flow), add_subflow(Builder, Trigger, Coerced_flow, Return_to, Map_args, Map_result). -file("src/telega/flow.gleam", 1939). ?DOC(" Create a new empty flow registry\n"). -spec new_registry() -> flow_registry(any(), any()). new_registry() -> {flow_registry, [], maps:new()}. -file("src/telega/flow.gleam", 1953). ?DOC(" Add a flow to the registry with a trigger and initial data\n"). -spec register_with_data( flow_registry(AUXY, AUXZ), flow_trigger(), flow(any(), AUXY, AUXZ), gleam@dict:dict(binary(), binary()) ) -> flow_registry(AUXY, AUXZ). register_with_data(Registry, Trigger, Flow, Initial_data) -> Coerced_flow = unsafe_coerce(Flow), {flow_registry, lists:append( erlang:element(2, Registry), [{Trigger, Coerced_flow, Initial_data}] ), gleam@dict:insert( erlang:element(3, Registry), erlang:element(2, Flow), Coerced_flow )}. -file("src/telega/flow.gleam", 1944). ?DOC(" Add a flow to the registry with a trigger\n"). -spec register( flow_registry(AUXO, AUXP), flow_trigger(), flow(any(), AUXO, AUXP) ) -> flow_registry(AUXO, AUXP). register(Registry, Trigger, Flow) -> register_with_data(Registry, Trigger, Flow, maps:new()). -file("src/telega/flow.gleam", 1967). ?DOC(" Register a flow without a trigger (for calling from handlers)\n"). -spec register_callable(flow_registry(AUYK, AUYL), flow(any(), AUYK, AUYL)) -> flow_registry(AUYK, AUYL). register_callable(Registry, Flow) -> Coerced_flow = unsafe_coerce(Flow), {flow_registry, erlang:element(2, Registry), gleam@dict:insert( erlang:element(3, Registry), erlang:element(2, Flow), Coerced_flow )}. -file("src/telega/flow.gleam", 2126). ?DOC(" Apply middleware chain to handler\n"). -spec apply_middlewares( telega@bot:context(AVAH, AVAI), flow_instance(), fun(() -> {ok, {telega@bot:context(AVAH, AVAI), flow_action(AVAL), flow_instance()}} | {error, AVAI}), list(fun((telega@bot:context(AVAH, AVAI), flow_instance(), fun(() -> {ok, {telega@bot:context(AVAH, AVAI), flow_action(AVAL), flow_instance()}} | {error, AVAI})) -> {ok, {telega@bot:context(AVAH, AVAI), flow_action(AVAL), flow_instance()}} | {error, AVAI})) ) -> {ok, {telega@bot:context(AVAH, AVAI), flow_action(AVAL), flow_instance()}} | {error, AVAI}. apply_middlewares(Ctx, Instance, Handler, Middlewares) -> case Middlewares of [] -> Handler(); [Middleware | Rest] -> Middleware( Ctx, Instance, fun() -> apply_middlewares(Ctx, Instance, Handler, Rest) end ) end. -file("src/telega/flow.gleam", 2143). ?DOC(" Check for conditional transitions\n"). -spec check_conditionals(flow(any(), any(), any()), flow_instance()) -> gleam@option:option(binary()). check_conditionals(Flow, Instance) -> gleam@list:fold( erlang:element(11, Flow), none, fun(Acc, Conditional) -> case Acc of {some, _} -> Acc; none -> case erlang:element(2, Conditional) =:= erlang:element( 2, erlang:element(6, Instance) ) of true -> _pipe = gleam@list:fold( erlang:element(3, Conditional), none, fun(Inner_acc, Cond) -> case Inner_acc of {some, _} -> Inner_acc; none -> {Check_fn, Step} = Cond, case Check_fn(Instance) of true -> {some, (erlang:element(5, Flow))( Step )}; false -> none end end end ), gleam@option:'or'( _pipe, {some, (erlang:element(5, Flow))( erlang:element(4, Conditional) )} ); false -> none end end end ). -file("src/telega/flow.gleam", 2175). ?DOC(" Check if current step triggers parallel execution\n"). -spec check_parallel_trigger(flow(AVBD, any(), any()), flow_instance()) -> gleam@option:option(parallel_config(AVBD)). check_parallel_trigger(Flow, Instance) -> _pipe = gleam@list:find( erlang:element(12, Flow), fun(Config) -> erlang:element(2, Config) =:= erlang:element( 2, erlang:element(6, Instance) ) end ), gleam@option:from_result(_pipe). -file("src/telega/flow.gleam", 2186). ?DOC(" Check if current step triggers a subflow\n"). -spec check_subflow_trigger(flow(AVBL, AVBM, AVBN), flow_instance()) -> gleam@option:option(subflow_config(AVBL, AVBM, AVBN)). check_subflow_trigger(Flow, Instance) -> _pipe = gleam@list:find( erlang:element(13, Flow), fun(Config) -> erlang:element(2, Config) =:= erlang:element( 2, erlang:element(6, Instance) ) end ), gleam@option:from_result(_pipe). -file("src/telega/flow.gleam", 2426). ?DOC(" Return from subflow to parent flow\n"). -spec return_to_parent_flow( telega@bot:context(AVDP, AVDQ), flow_instance(), gleam@dict:dict(binary(), binary()), subflow_config(any(), AVDP, AVDQ) ) -> {ok, telega@bot:context(AVDP, AVDQ)} | {error, AVDQ}. return_to_parent_flow(Ctx, Instance, Result, Config) -> case erlang:element(5, erlang:element(6, Instance)) of [Frame | Rest_stack] -> Temp_instance = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record = erlang:element(6, Instance), {flow_state, erlang:element(2, _record), erlang:element(4, Frame), erlang:element(4, _record), erlang:element(5, _record), erlang:element(6, _record)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance)}, Mapped_instance = (erlang:element(6, Config))(Result, Temp_instance), Updated_instance = {flow_instance, erlang:element(2, Mapped_instance), erlang:element(2, Frame), erlang:element(4, Mapped_instance), erlang:element(5, Mapped_instance), begin _record@1 = erlang:element(6, Mapped_instance), {flow_state, erlang:element(3, Frame), erlang:element(3, _record@1), [erlang:element(3, Frame) | erlang:element( 4, erlang:element(6, Mapped_instance) )], Rest_stack, erlang:element(6, _record@1)} end, maps:new(), erlang:element(8, Mapped_instance), erlang:element(9, Mapped_instance), telega@internal@utils:current_time_ms()}, case (erlang:element( 2, erlang:element(7, erlang:element(3, Config)) ))(Updated_instance) of {ok, _} -> {ok, Ctx}; {error, _} -> {ok, Ctx} end; [] -> {ok, Ctx} end. -file("src/telega/flow.gleam", 2467). ?DOC(" Handle error within a subflow\n"). -spec handle_subflow_error( flow(gleam@dynamic:dynamic_(), AVED, AVEE), telega@bot:context(AVED, AVEE), flow_instance(), gleam@option:option(AVEE), subflow_config(any(), AVED, AVEE) ) -> {ok, telega@bot:context(AVED, AVEE)} | {error, AVEE}. handle_subflow_error(Flow, Ctx, Instance, Error, _) -> case erlang:element(9, Flow) of {some, Handler} -> case Handler(Ctx, Instance, Error) of {ok, New_ctx} -> {ok, New_ctx}; {error, _} -> {ok, Ctx} end; none -> {ok, Ctx} end. -file("src/telega/flow.gleam", 2527). ?DOC(" Merge results from parallel execution\n"). -spec merge_parallel_results( gleam@dict:dict(binary(), binary()), gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary())) ) -> gleam@dict:dict(binary(), binary()). merge_parallel_results(Base_data, Parallel_results) -> gleam@dict:fold( Parallel_results, Base_data, fun(Acc, Step_name, Step_results) -> gleam@dict:fold( Step_results, Acc, fun(Inner_acc, Key, Value) -> gleam@dict:insert( Inner_acc, <<<>/binary, Key/binary>>, Value ) end ) end ). -file("src/telega/flow.gleam", 2654). -spec composed_step_to_string(composed_step()) -> binary(). composed_step_to_string(Step) -> case Step of {composed_flow_step, N} -> <<"flow_"/utf8, (erlang:integer_to_binary(N))/binary>>; composed_select_flow -> <<"select_flow"/utf8>>; composed_start_parallel -> <<"start_parallel"/utf8>>; {composed_parallel_flow, N@1} -> <<"parallel_"/utf8, (erlang:integer_to_binary(N@1))/binary>>; composed_merge_results -> <<"merge_results"/utf8>> end. -file("src/telega/flow.gleam", 2664). -spec string_to_composed_step(binary()) -> {ok, composed_step()} | {error, nil}. string_to_composed_step(String) -> case String of <<"select_flow"/utf8>> -> {ok, composed_select_flow}; <<"start_parallel"/utf8>> -> {ok, composed_start_parallel}; <<"merge_results"/utf8>> -> {ok, composed_merge_results}; _ -> case gleam_stdlib:string_starts_with(String, <<"flow_"/utf8>>) of true -> _pipe = gleam@string:drop_start(String, 5), _pipe@1 = gleam_stdlib:parse_int(_pipe), _pipe@2 = gleam@result:map( _pipe@1, fun(Field@0) -> {composed_flow_step, Field@0} end ), gleam@result:replace_error(_pipe@2, nil); false -> case gleam_stdlib:string_starts_with( String, <<"parallel_"/utf8>> ) of true -> _pipe@3 = gleam@string:drop_start(String, 9), _pipe@4 = gleam_stdlib:parse_int(_pipe@3), _pipe@5 = gleam@result:map( _pipe@4, fun(Field@0) -> {composed_parallel_flow, Field@0} end ), gleam@result:replace_error(_pipe@5, nil); false -> {error, nil} end end end. -file("src/telega/flow.gleam", 2710). -spec validation_middleware( fun((flow_instance()) -> {ok, nil} | {error, binary()}) ) -> fun((telega@bot:context(AVHP, AVHQ), flow_instance(), fun(() -> {ok, {telega@bot:context(AVHP, AVHQ), flow_action(AVHO), flow_instance()}} | {error, AVHQ})) -> {ok, {telega@bot:context(AVHP, AVHQ), flow_action(AVHO), flow_instance()}} | {error, AVHQ}). validation_middleware(Validator) -> fun(Ctx, Instance, Next) -> case Validator(Instance) of {ok, _} -> Next(); {error, Msg} -> case telega@reply:with_text( Ctx, <<"Validation failed: "/utf8, Msg/binary>> ) of {ok, _} -> {ok, {Ctx, back, Instance}}; {error, _} -> {ok, {Ctx, cancel, Instance}} end end end. -file("src/telega/flow.gleam", 1320). -spec process_action( flow(AUQZ, AURA, AURB), telega@bot:context(AURA, AURB), flow_action(AUQZ), flow_instance() ) -> {ok, telega@bot:context(AURA, AURB)} | {error, AURB}. process_action(Flow, Ctx, Action, Instance) -> case Action of {next, Step} -> Step_name = (erlang:element(5, Flow))(Step), Updated_instance = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record = erlang:element(6, Instance), {flow_state, Step_name, erlang:element(3, _record), [erlang:element(2, erlang:element(6, Instance)) | erlang:element(4, erlang:element(6, Instance))], erlang:element(5, _record), erlang:element(6, _record)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))(Updated_instance) of {ok, _} -> execute_step(Flow, Ctx, Updated_instance); {error, Err} -> handle_error(Flow, Ctx, Instance, {some, Err}) end; {next_string, Step_name@1} -> Updated_instance@1 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record@1 = erlang:element(6, Instance), {flow_state, Step_name@1, erlang:element(3, _record@1), [erlang:element(2, erlang:element(6, Instance)) | erlang:element(4, erlang:element(6, Instance))], erlang:element(5, _record@1), erlang:element(6, _record@1)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@1 ) of {ok, _} -> execute_step(Flow, Ctx, Updated_instance@1); {error, Err@1} -> handle_error(Flow, Ctx, Instance, {some, Err@1}) end; {return_from_subflow, Result} -> case erlang:element(5, erlang:element(6, Instance)) of [Frame | Rest_stack] -> Updated_instance@2 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record@2 = erlang:element(6, Instance), {flow_state, erlang:element(3, Frame), maps:merge( erlang:element( 3, erlang:element(6, Instance) ), Result ), erlang:element(4, _record@2), Rest_stack, erlang:element(6, _record@2)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@2 ) of {ok, _} -> execute_step(Flow, Ctx, Updated_instance@2); {error, Err@2} -> handle_error(Flow, Ctx, Instance, {some, Err@2}) end; [] -> {ok, Ctx} end; {start_parallel, Steps, Join_at} -> Step_names = gleam@list:map(Steps, erlang:element(5, Flow)), Join_step_name = (erlang:element(5, Flow))(Join_at), Parallel_state = {parallel_state, Step_names, [], maps:new(), Join_step_name}, Updated_instance@3 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record@3 = erlang:element(6, Instance), {flow_state, erlang:element(2, _record@3), erlang:element(3, _record@3), erlang:element(4, _record@3), erlang:element(5, _record@3), {some, Parallel_state}} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@3 ) of {ok, _} -> case Step_names of [First | _] -> Step_instance = {flow_instance, erlang:element(2, Updated_instance@3), erlang:element(3, Updated_instance@3), erlang:element(4, Updated_instance@3), erlang:element(5, Updated_instance@3), begin _record@4 = erlang:element( 6, Updated_instance@3 ), {flow_state, First, erlang:element(3, _record@4), erlang:element(4, _record@4), erlang:element(5, _record@4), erlang:element(6, _record@4)} end, erlang:element(7, Updated_instance@3), erlang:element(8, Updated_instance@3), erlang:element(9, Updated_instance@3), erlang:element(10, Updated_instance@3)}, execute_step(Flow, Ctx, Step_instance); [] -> {ok, Ctx} end; {error, Err@3} -> handle_error(Flow, Ctx, Instance, {some, Err@3}) end; {complete_parallel_step, Step@1, Result@1} -> case erlang:element(6, erlang:element(6, Instance)) of {some, Parallel_state@1} -> Step_name@2 = (erlang:element(5, Flow))(Step@1), Updated_parallel = {parallel_state, gleam@list:filter( erlang:element(2, Parallel_state@1), fun(S) -> S /= Step_name@2 end ), [Step_name@2 | erlang:element(3, Parallel_state@1)], gleam@dict:insert( erlang:element(4, Parallel_state@1), Step_name@2, Result@1 ), erlang:element(5, Parallel_state@1)}, case erlang:element(2, Updated_parallel) of [] -> Updated_instance@4 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record@5 = erlang:element(6, Instance), {flow_state, erlang:element(5, Updated_parallel), merge_parallel_results( erlang:element( 3, erlang:element(6, Instance) ), erlang:element(4, Updated_parallel) ), erlang:element(4, _record@5), erlang:element(5, _record@5), none} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@4 ) of {ok, _} -> execute_step(Flow, Ctx, Updated_instance@4); {error, Err@4} -> handle_error( Flow, Ctx, Instance, {some, Err@4} ) end; [Next | _] -> Updated_instance@5 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record@6 = erlang:element(6, Instance), {flow_state, Next, erlang:element(3, _record@6), erlang:element(4, _record@6), erlang:element(5, _record@6), {some, Updated_parallel}} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@5 ) of {ok, _} -> execute_step(Flow, Ctx, Updated_instance@5); {error, Err@5} -> handle_error( Flow, Ctx, Instance, {some, Err@5} ) end end; none -> {ok, Ctx} end; {go_to, Step@2} -> Step_name@3 = (erlang:element(5, Flow))(Step@2), Updated_instance@6 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), {flow_state, Step_name@3, erlang:element(3, erlang:element(6, Instance)), [Step_name@3], [], none}, maps:new(), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@6 ) of {ok, _} -> execute_step(Flow, Ctx, Updated_instance@6); {error, Err@6} -> handle_error(Flow, Ctx, Instance, {some, Err@6}) end; back -> case erlang:element(4, erlang:element(6, Instance)) of [Previous_step | Rest] -> Updated_instance@7 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record@7 = erlang:element(6, Instance), {flow_state, Previous_step, erlang:element(3, _record@7), Rest, erlang:element(5, _record@7), erlang:element(6, _record@7)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@7 ) of {ok, _} -> execute_step(Flow, Ctx, Updated_instance@7); {error, Err@7} -> handle_error(Flow, Ctx, Instance, {some, Err@7}) end; [] -> {ok, Ctx} end; {complete, Data} -> Completed_instance = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record@8 = erlang:element(6, Instance), {flow_state, erlang:element(2, _record@8), Data, erlang:element(4, _record@8), erlang:element(5, _record@8), erlang:element(6, _record@8)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance)}, case erlang:element(8, Flow) of {some, Handler} -> case Handler(Ctx, Completed_instance) of {ok, New_ctx} -> case run_flow_exit_hook( erlang:element(16, Flow), New_ctx, Completed_instance ) of {ok, Final_ctx} -> _ = (erlang:element( 4, erlang:element(7, Flow) ))(erlang:element(2, Instance)), {ok, Final_ctx}; {error, Err@8} -> handle_error( Flow, Ctx, Instance, {some, Err@8} ) end; {error, Err@9} -> handle_error(Flow, Ctx, Instance, {some, Err@9}) end; none -> case run_flow_exit_hook( erlang:element(16, Flow), Ctx, Completed_instance ) of {ok, Final_ctx@1} -> _ = (erlang:element(4, erlang:element(7, Flow)))( erlang:element(2, Instance) ), {ok, Final_ctx@1}; {error, Err@10} -> handle_error(Flow, Ctx, Instance, {some, Err@10}) end end; cancel -> case run_flow_exit_hook(erlang:element(16, Flow), Ctx, Instance) of {ok, Final_ctx@2} -> _ = (erlang:element(4, erlang:element(7, Flow)))( erlang:element(2, Instance) ), {ok, Final_ctx@2}; {error, Err@11} -> handle_error(Flow, Ctx, Instance, {some, Err@11}) end; {wait, Token} -> Updated_instance@8 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), erlang:element(7, Instance), {some, Token}, erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@8 ) of {ok, _} -> {ok, Ctx}; {error, Err@12} -> handle_error(Flow, Ctx, Instance, {some, Err@12}) end; {wait_callback, Token@1} -> Updated_instance@9 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), erlang:element(7, Instance), {some, Token@1}, erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@9 ) of {ok, _} -> {ok, Ctx}; {error, Err@13} -> handle_error(Flow, Ctx, Instance, {some, Err@13}) end; {exit, _} -> _ = (erlang:element(4, erlang:element(7, Flow)))( erlang:element(2, Instance) ), {ok, Ctx}; {enter_subflow, Subflow_name, Data@1} -> case gleam@list:find( erlang:element(13, Flow), fun(Config) -> erlang:element(2, erlang:element(3, Config)) =:= Subflow_name end ) of {ok, Subflow_config} -> Return_step = (erlang:element(5, Flow))( erlang:element(4, Subflow_config) ), Stack_frame = {flow_stack_frame, erlang:element(2, Flow), Return_step, erlang:element(3, erlang:element(6, Instance))}, Subflow_initial_step = (erlang:element( 5, erlang:element(3, Subflow_config) ))(erlang:element(4, erlang:element(3, Subflow_config))), Updated_instance@10 = {flow_instance, erlang:element(2, Instance), erlang:element(2, erlang:element(3, Subflow_config)), erlang:element(4, Instance), erlang:element(5, Instance), {flow_state, Subflow_initial_step, maps:merge( erlang:element(3, erlang:element(6, Instance)), Data@1 ), [Subflow_initial_step], [Stack_frame | erlang:element(5, erlang:element(6, Instance))], none}, maps:new(), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@10 ) of {ok, _} -> execute_subflow_step( erlang:element(3, Subflow_config), Ctx, Updated_instance@10, Subflow_config ); {error, Err@14} -> handle_error(Flow, Ctx, Instance, {some, Err@14}) end; {error, _} -> {ok, Ctx} end end. -file("src/telega/flow.gleam", 1161). -spec execute_step( flow(any(), AUNV, AUNW), telega@bot:context(AUNV, AUNW), flow_instance() ) -> {ok, telega@bot:context(AUNV, AUNW)} | {error, AUNW}. execute_step(Flow, Ctx, Instance) -> case check_conditionals(Flow, Instance) of {some, Next_step} -> Updated_instance = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record = erlang:element(6, Instance), {flow_state, Next_step, erlang:element(3, _record), [erlang:element(2, erlang:element(6, Instance)) | erlang:element(4, erlang:element(6, Instance))], erlang:element(5, _record), erlang:element(6, _record)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))(Updated_instance) of {ok, _} -> execute_step(Flow, Ctx, Updated_instance); {error, Err} -> handle_error(Flow, Ctx, Instance, {some, Err}) end; none -> case check_parallel_trigger(Flow, Instance) of {some, Config} -> start_parallel_execution(Flow, Ctx, Instance, Config); none -> case check_subflow_trigger(Flow, Instance) of {some, Subflow_config} -> start_subflow_execution( Flow, Ctx, Instance, Subflow_config ); none -> case gleam_stdlib:map_get( erlang:element(3, Flow), erlang:element(2, erlang:element(6, Instance)) ) of {ok, Config@1} -> case run_enter_hook( erlang:element(4, Config@1), Ctx, Instance ) of {ok, {Ctx_after_enter, Instance_after_enter}} -> Handler_fn = fun() -> (erlang:element(2, Config@1))( Ctx_after_enter, Instance_after_enter ) end, Result = apply_middlewares( Ctx_after_enter, Instance_after_enter, Handler_fn, lists:append( erlang:element(10, Flow), erlang:element(3, Config@1) ) ), case Result of {ok, {New_ctx, Action, New_instance}} -> process_action_with_leave_hook( Flow, New_ctx, Action, New_instance, erlang:element( 5, Config@1 ) ); {error, Err@1} -> handle_error( Flow, Ctx, Instance, {some, Err@1} ) end; {error, Err@2} -> handle_error( Flow, Ctx, Instance, {some, Err@2} ) end; {error, _} -> handle_error(Flow, Ctx, Instance, none) end end end end. -file("src/telega/flow.gleam", 1299). ?DOC(" Process action with leave hook support\n"). -spec process_action_with_leave_hook( flow(AUQJ, AUQK, AUQL), telega@bot:context(AUQK, AUQL), flow_action(AUQJ), flow_instance(), gleam@option:option(fun((telega@bot:context(AUQK, AUQL), flow_instance()) -> {ok, {telega@bot:context(AUQK, AUQL), flow_instance()}} | {error, AUQL})) ) -> {ok, telega@bot:context(AUQK, AUQL)} | {error, AUQL}. process_action_with_leave_hook(Flow, Ctx, Action, Instance, Leave_hook) -> case Action of {wait, _} -> process_action(Flow, Ctx, Action, Instance); {wait_callback, _} -> process_action(Flow, Ctx, Action, Instance); _ -> case run_leave_hook(Leave_hook, Ctx, Instance) of {ok, {Ctx_after_leave, Instance_after_leave}} -> process_action( Flow, Ctx_after_leave, Action, Instance_after_leave ); {error, Err} -> handle_error(Flow, Ctx, Instance, {some, Err}) end end. -file("src/telega/flow.gleam", 970). -spec start_or_resume( flow(any(), AULU, AULV), telega@bot:context(AULU, AULV), integer(), integer(), gleam@dict:dict(binary(), binary()) ) -> {ok, telega@bot:context(AULU, AULV)} | {error, AULV}. start_or_resume(Flow, Ctx, User_id, Chat_id, Initial_data) -> Flow_id = generate_flow_id(User_id, Chat_id, erlang:element(2, Flow)), case (erlang:element(3, erlang:element(7, Flow)))(Flow_id) of {ok, {some, Instance}} -> execute_step(Flow, Ctx, Instance); {ok, none} -> Initial_step_name = (erlang:element(5, Flow))( erlang:element(4, Flow) ), New_instance = {flow_instance, Flow_id, erlang:element(2, Flow), User_id, Chat_id, {flow_state, Initial_step_name, Initial_data, [Initial_step_name], [], none}, maps:new(), none, telega@internal@utils:current_time_ms(), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))(New_instance) of {ok, _} -> case run_flow_enter_hook( erlang:element(14, Flow), Ctx, New_instance ) of {ok, {Ctx_after_enter, Instance_after_enter}} -> execute_step( Flow, Ctx_after_enter, Instance_after_enter ); {error, Err} -> handle_error(Flow, Ctx, New_instance, {some, Err}) end; {error, Err@1} -> handle_error(Flow, Ctx, New_instance, {some, Err@1}) end; {error, Err@2} -> Dummy_instance = {flow_instance, Flow_id, erlang:element(2, Flow), User_id, Chat_id, {flow_state, <<""/utf8>>, maps:new(), [], [], none}, maps:new(), none, 0, 0}, handle_error(Flow, Ctx, Dummy_instance, {some, Err@2}) end. -file("src/telega/flow.gleam", 1038). -spec resume_with_token( flow(any(), AUMI, AUMJ), telega@bot:context(AUMI, AUMJ), binary(), gleam@option:option(gleam@dict:dict(binary(), binary())) ) -> {ok, telega@bot:context(AUMI, AUMJ)} | {error, AUMJ}. resume_with_token(Flow, Ctx, Token, Data) -> case find_instance_by_token(erlang:element(7, Flow), Token) of {ok, {some, Instance}} -> Updated_instance = case Data of {some, D} -> {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), maps:merge(erlang:element(7, Instance), D), none, erlang:element(9, Instance), erlang:element(10, Instance)}; none -> {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), erlang:element(7, Instance), none, erlang:element(9, Instance), erlang:element(10, Instance)} end, execute_step(Flow, Ctx, Updated_instance); _ -> {ok, Ctx} end. -file("src/telega/flow.gleam", 1777). ?DOC(" Create a text handler for resuming flows\n"). -spec create_text_handler(flow(any(), AUTS, AUTT)) -> fun((telega@bot:context(AUTS, AUTT), telega@update:update()) -> {ok, telega@bot:context(AUTS, AUTT)} | {error, AUTT}). create_text_handler(Flow) -> fun(Ctx, Update) -> case Update of {text_update, From_id, Chat_id, Text, _, _} -> case (erlang:element(5, erlang:element(7, Flow)))( From_id, Chat_id ) of {ok, [Instance | _]} when erlang:element(8, Instance) =/= none -> Data = maps:from_list([{<<"user_input"/utf8>>, Text}]), resume_with_token( Flow, Ctx, gleam@option:unwrap( erlang:element(8, Instance), <<""/utf8>> ), {some, Data} ); _ -> {ok, Ctx} end; _ -> {ok, Ctx} end end. -file("src/telega/flow.gleam", 1852). ?DOC(" Start a flow with optional initial data\n"). -spec start( flow(any(), AUUU, AUUV), gleam@dict:dict(binary(), binary()), telega@bot:context(AUUU, AUUV) ) -> {ok, telega@bot:context(AUUU, AUUV)} | {error, AUUV}. start(Flow, Initial_data, Ctx) -> {From_id, Chat_id} = extract_ids_from_context(Ctx), start_or_resume(Flow, Ctx, From_id, Chat_id, Initial_data). -file("src/telega/flow.gleam", 1834). ?DOC( " Call a registered flow from any handler\n" "\n" " ## Parameters\n" " - `ctx`: Current context\n" " - `registry`: The flow registry containing the flow\n" " - `flow_name`: Name of the flow to call\n" " - `initial_data`: Initial data to pass to the flow\n" "\n" " ## Example\n" " ```gleam\n" " fn my_handler(ctx, registry, _data) {\n" " let initial_data = dict.from_list([\n" " #(\"user_name\", \"John\"),\n" " #(\"product_id\", \"123\")\n" " ])\n" " flow.call_flow(ctx, registry, \"checkout\", initial_data)\n" " }\n" " ```\n" ). -spec call_flow( telega@bot:context(AUUD, AUUE), flow_registry(AUUD, AUUE), binary(), gleam@dict:dict(binary(), binary()) ) -> {ok, telega@bot:context(AUUD, AUUE)} | {error, AUUE}. call_flow(Ctx, Registry, Flow_name, Initial_data) -> case gleam_stdlib:map_get(erlang:element(3, Registry), Flow_name) of {ok, Found_flow} -> start(Found_flow, Initial_data, Ctx); {error, _} -> {ok, Ctx} end. -file("src/telega/flow.gleam", 1862). ?DOC(" Create a router handler that starts a flow\n"). -spec to_handler(flow(any(), AUVI, AUVJ)) -> fun((telega@bot:context(AUVI, AUVJ), telega@update:command()) -> {ok, telega@bot:context(AUVI, AUVJ)} | {error, AUVJ}). to_handler(Flow) -> fun(Ctx, _) -> start(Flow, maps:new(), Ctx) end. -file("src/telega/flow.gleam", 1870). ?DOC(" Create a router handler that starts a flow with initial data (internal)\n"). -spec to_handler_with_data( flow(any(), AUVU, AUVV), gleam@dict:dict(binary(), binary()) ) -> fun((telega@bot:context(AUVU, AUVV), telega@update:command()) -> {ok, telega@bot:context(AUVU, AUVV)} | {error, AUVV}). to_handler_with_data(Flow, Initial_data) -> fun(Ctx, _) -> start(Flow, Initial_data, Ctx) end. -file("src/telega/flow.gleam", 1879). ?DOC(" Create a router handler for resuming flows from callback queries (internal)\n"). -spec resume_handler(flow(any(), AUWI, AUWJ)) -> fun((telega@bot:context(AUWI, AUWJ), telega@update:update()) -> {ok, telega@bot:context(AUWI, AUWJ)} | {error, AUWJ}). resume_handler(Flow) -> fun(Ctx, Update) -> case Update of {callback_query_update, _, _, Query, _} -> Data = gleam@option:unwrap( erlang:element(7, Query), <<""/utf8>> ), Token@1 = case gleam@string:split(Data, <<":"/utf8>>) of [_, Token | _] -> Token; _ -> Data end, resume_with_token(Flow, Ctx, Token@1, none); _ -> {ok, Ctx} end end. -file("src/telega/flow.gleam", 1760). ?DOC(" Create a router handler for resuming flows from callback queries\n"). -spec create_resume_handler(flow(any(), AUST, AUSU)) -> fun((telega@bot:context(AUST, AUSU), telega@update:update()) -> {ok, telega@bot:context(AUST, AUSU)} | {error, AUSU}). create_resume_handler(Flow) -> resume_handler(Flow). -file("src/telega/flow.gleam", 1899). ?DOC(" Create a router handler for resuming flows from callback queries with keyboard parsing (internal)\n"). -spec resume_handler_with_keyboard( flow(any(), AUWU, AUWV), telega@keyboard:keyboard_callback_data(binary()) ) -> fun((telega@bot:context(AUWU, AUWV), telega@update:update()) -> {ok, telega@bot:context(AUWU, AUWV)} | {error, AUWV}). resume_handler_with_keyboard(Flow, Callback_data) -> fun(Ctx, Update) -> case Update of {callback_query_update, _, _, Query, _} -> Data = gleam@option:unwrap( erlang:element(7, Query), <<""/utf8>> ), case telega@keyboard:unpack_callback(Data, Callback_data) of {ok, Callback} -> resume_with_token( Flow, Ctx, erlang:element(2, Callback), none ); {error, _} -> Token@1 = case gleam@string:split(Data, <<":"/utf8>>) of [_, Token | _] -> Token; _ -> Data end, resume_with_token(Flow, Ctx, Token@1, none) end; _ -> {ok, Ctx} end end. -file("src/telega/flow.gleam", 1768). ?DOC(" Create a router handler for resuming flows from callback queries with keyboard parsing\n"). -spec create_resume_handler_with_keyboard( flow(any(), AUTF, AUTG), telega@keyboard:keyboard_callback_data(binary()) ) -> fun((telega@bot:context(AUTF, AUTG), telega@update:update()) -> {ok, telega@bot:context(AUTF, AUTG)} | {error, AUTG}). create_resume_handler_with_keyboard(Flow, Callback_data) -> resume_handler_with_keyboard(Flow, Callback_data). -file("src/telega/flow.gleam", 2003). ?DOC(" Add a flow route to router\n"). -spec add_flow_route( telega@router:router(AUZC, AUZD), flow_trigger(), flow(gleam@dynamic:dynamic_(), AUZC, AUZD), gleam@dict:dict(binary(), binary()) ) -> telega@router:router(AUZC, AUZD). add_flow_route(Router, Trigger, Flow, Initial_data) -> case Trigger of {on_command, Command} -> telega@router:on_command( Router, Command, to_handler_with_data(Flow, Initial_data) ); {on_text, Pattern} -> telega@router:on_text( Router, Pattern, fun(Ctx, _) -> start(Flow, Initial_data, Ctx) end ); {on_callback, Pattern@1} -> telega@router:on_callback( Router, Pattern@1, fun(Ctx@1, _, _) -> start(Flow, Initial_data, Ctx@1) end ); {on_filtered, Filter} -> telega@router:on_filtered( Router, Filter, fun(Ctx@2, _) -> start(Flow, Initial_data, Ctx@2) end ); on_photo -> telega@router:on_photo( Router, fun(Ctx@3, _) -> start(Flow, Initial_data, Ctx@3) end ); on_video -> telega@router:on_video( Router, fun(Ctx@4, _) -> start(Flow, Initial_data, Ctx@4) end ); on_audio -> telega@router:on_audio( Router, fun(Ctx@5, _) -> start(Flow, Initial_data, Ctx@5) end ); on_voice -> telega@router:on_voice( Router, fun(Ctx@6, _) -> start(Flow, Initial_data, Ctx@6) end ); on_any_text -> telega@router:on_any_text( Router, fun(Ctx@7, _) -> start(Flow, Initial_data, Ctx@7) end ) end. -file("src/telega/flow.gleam", 2046). ?DOC(" Auto-resume handler for text messages\n"). -spec auto_resume_handler(flow_registry(AUZN, AUZO)) -> fun((telega@bot:context(AUZN, AUZO), binary()) -> {ok, telega@bot:context(AUZN, AUZO)} | {error, AUZO}). auto_resume_handler(Registry) -> fun(Ctx, Text) -> {User_id, Chat_id} = extract_ids_from_context(Ctx), Flows = maps:values(erlang:element(3, Registry)), Result = gleam@list:fold(Flows, none, fun(Acc, Flow) -> case Acc of {some, _} -> Acc; none -> Flow_id = generate_flow_id( User_id, Chat_id, erlang:element(2, Flow) ), case (erlang:element(3, erlang:element(7, Flow)))( Flow_id ) of {ok, {some, Instance}} when erlang:element( 8, Instance ) =/= none -> Data = maps:from_list( [{<<"user_input"/utf8>>, Text}] ), _pipe = resume_with_token( Flow, Ctx, gleam@option:unwrap( erlang:element(8, Instance), <<""/utf8>> ), {some, Data} ), {some, _pipe}; _ -> none end end end), case Result of {some, Res} -> Res; none -> {ok, Ctx} end end. -file("src/telega/flow.gleam", 2087). ?DOC(" Auto-resume handler for callback queries (internal)\n"). -spec auto_resume_callback_handler(flow_registry(AUZX, AUZY)) -> fun((telega@bot:context(AUZX, AUZY), binary(), binary()) -> {ok, telega@bot:context(AUZX, AUZY)} | {error, AUZY}). auto_resume_callback_handler(Registry) -> fun(Ctx, _, Data) -> {User_id, Chat_id} = extract_ids_from_context(Ctx), Flows = maps:values(erlang:element(3, Registry)), Result = gleam@list:fold(Flows, none, fun(Acc, Flow) -> case Acc of {some, _} -> Acc; none -> Flow_id = generate_flow_id( User_id, Chat_id, erlang:element(2, Flow) ), case (erlang:element(3, erlang:element(7, Flow)))( Flow_id ) of {ok, {some, Instance}} when erlang:element( 8, Instance ) =/= none -> Callback_data = maps:from_list( [{<<"callback_data"/utf8>>, Data}] ), _pipe = resume_with_token( Flow, Ctx, gleam@option:unwrap( erlang:element(8, Instance), <<""/utf8>> ), {some, Callback_data} ), {some, _pipe}; _ -> none end end end), case Result of {some, Res} -> Res; none -> {ok, Ctx} end end. -file("src/telega/flow.gleam", 1979). ?DOC(" Apply all registered flows to a router\n"). -spec apply_to_router( telega@router:router(AUYU, AUYV), flow_registry(AUYU, AUYV) ) -> telega@router:router(AUYU, AUYV). apply_to_router(Router, Registry) -> Router_with_flows = gleam@list:fold( erlang:element(2, Registry), Router, fun(Router@1, Flow_entry) -> {Trigger, Flow, Initial_data} = Flow_entry, add_flow_route(Router@1, Trigger, Flow, Initial_data) end ), case maps:size(erlang:element(3, Registry)) of 0 -> Router_with_flows; _ -> _pipe = Router_with_flows, _pipe@1 = telega@router:on_any_text( _pipe, auto_resume_handler(Registry) ), telega@router:on_callback( _pipe@1, {prefix, <<""/utf8>>}, auto_resume_callback_handler(Registry) ) end. -file("src/telega/flow.gleam", 2486). ?DOC(" Start parallel execution\n"). -spec start_parallel_execution( flow(AVET, AVEU, AVEV), telega@bot:context(AVEU, AVEV), flow_instance(), parallel_config(AVET) ) -> {ok, telega@bot:context(AVEU, AVEV)} | {error, AVEV}. start_parallel_execution(Flow, Ctx, Instance, Config) -> Pending_steps = gleam@list:map( erlang:element(3, Config), erlang:element(5, Flow) ), Join_step = (erlang:element(5, Flow))(erlang:element(4, Config)), Parallel_state = {parallel_state, Pending_steps, [], maps:new(), Join_step}, Updated_instance = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record = erlang:element(6, Instance), {flow_state, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), erlang:element(5, _record), {some, Parallel_state}} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))(Updated_instance) of {ok, _} -> case Pending_steps of [Current_step | _] -> Step_instance = {flow_instance, erlang:element(2, Updated_instance), erlang:element(3, Updated_instance), erlang:element(4, Updated_instance), erlang:element(5, Updated_instance), begin _record@1 = erlang:element(6, Updated_instance), {flow_state, Current_step, erlang:element(3, _record@1), erlang:element(4, _record@1), erlang:element(5, _record@1), erlang:element(6, _record@1)} end, erlang:element(7, Updated_instance), erlang:element(8, Updated_instance), erlang:element(9, Updated_instance), erlang:element(10, Updated_instance)}, execute_step(Flow, Ctx, Step_instance); [] -> {ok, Ctx} end; {error, Err} -> handle_error(Flow, Ctx, Instance, {some, Err}) end. -file("src/telega/flow.gleam", 2559). ?DOC(" Compose flows with conditional selection\n"). -spec compose_conditional( binary(), fun((flow_instance()) -> binary()), gleam@dict:dict(binary(), flow(gleam@dynamic:dynamic_(), AVFY, AVFZ)), flow_storage(AVFZ) ) -> flow(composed_step(), AVFY, AVFZ). compose_conditional(Name, Condition, Flows, Storage) -> Builder = new( Name, Storage, fun composed_step_to_string/1, fun string_to_composed_step/1 ), Builder@1 = add_step( Builder, composed_select_flow, fun(Ctx, Instance) -> Flow_name = Condition(Instance), case gleam_stdlib:map_get(Flows, Flow_name) of {ok, Flow} -> {User_id, Chat_id} = extract_ids_from_context(Ctx), _pipe = start_or_resume( Flow, Ctx, User_id, Chat_id, erlang:element(3, erlang:element(6, Instance)) ), gleam@result:map( _pipe, fun(New_ctx) -> {New_ctx, {complete, erlang:element( 3, erlang:element(6, Instance) )}, Instance} end ); {error, _} -> {ok, {Ctx, cancel, Instance}} end end ), build(Builder@1, composed_select_flow). -file("src/telega/flow.gleam", 2589). ?DOC(" Compose flows for parallel execution\n"). -spec compose_parallel( binary(), list(flow(gleam@dynamic:dynamic_(), AVGJ, AVGK)), fun((list(gleam@dict:dict(binary(), binary()))) -> gleam@dict:dict(binary(), binary())), flow_storage(AVGK) ) -> flow(composed_step(), AVGJ, AVGK). compose_parallel(Name, Flows, Merge_results, Storage) -> Builder = new( Name, Storage, fun composed_step_to_string/1, fun string_to_composed_step/1 ), Parallel_steps = gleam@list:index_map( Flows, fun(_, Index) -> {composed_parallel_flow, Index} end ), Builder@1 = add_step( Builder, composed_start_parallel, fun(Ctx, Instance) -> {ok, {Ctx, {start_parallel, Parallel_steps, composed_merge_results}, Instance}} end ), Builder@3 = gleam@list:index_fold( Flows, Builder@1, fun(Builder@2, Flow, Index@1) -> Step = {composed_parallel_flow, Index@1}, add_step( Builder@2, Step, fun(Ctx@1, Instance@1) -> {User_id, Chat_id} = extract_ids_from_context(Ctx@1), _pipe = start_or_resume( Flow, Ctx@1, User_id, Chat_id, erlang:element(3, erlang:element(6, Instance@1)) ), gleam@result:map( _pipe, fun(New_ctx) -> {New_ctx, {complete_parallel_step, Step, erlang:element( 3, erlang:element(6, Instance@1) )}, Instance@1} end ) end ) end ), Builder@4 = add_step( Builder@3, composed_merge_results, fun(Ctx@2, Instance@2) -> case erlang:element(6, erlang:element(6, Instance@2)) of {some, State} -> Results = maps:values(erlang:element(4, State)), Merged = Merge_results(Results), Updated_instance = {flow_instance, erlang:element(2, Instance@2), erlang:element(3, Instance@2), erlang:element(4, Instance@2), erlang:element(5, Instance@2), begin _record = erlang:element(6, Instance@2), {flow_state, erlang:element(2, _record), Merged, erlang:element(4, _record), erlang:element(5, _record), erlang:element(6, _record)} end, erlang:element(7, Instance@2), erlang:element(8, Instance@2), erlang:element(9, Instance@2), erlang:element(10, Instance@2)}, {ok, {Ctx@2, {complete, Merged}, Updated_instance}}; none -> {ok, {Ctx@2, {complete, erlang:element(3, erlang:element(6, Instance@2))}, Instance@2}} end end ), Builder@5 = add_parallel_steps( Builder@4, composed_start_parallel, Parallel_steps, composed_merge_results ), build(Builder@5, composed_start_parallel). -file("src/telega/flow.gleam", 2693). -spec create_composed_handler( flow(gleam@dynamic:dynamic_(), AVHA, AVHB), list(flow(gleam@dynamic:dynamic_(), AVHA, AVHB)), integer() ) -> fun((telega@bot:context(AVHA, AVHB), flow_instance()) -> {ok, {telega@bot:context(AVHA, AVHB), flow_action(composed_step()), flow_instance()}} | {error, AVHB}). create_composed_handler(Flow, All_flows, Index) -> fun(Ctx, Instance) -> {User_id, Chat_id} = extract_ids_from_context(Ctx), _pipe = start_or_resume( Flow, Ctx, User_id, Chat_id, erlang:element(3, erlang:element(6, Instance)) ), gleam@result:map( _pipe, fun(New_ctx) -> case gleam@list:drop(All_flows, Index + 1) of [_ | _] -> {New_ctx, {next, {composed_flow_step, Index + 1}}, Instance}; [] -> {New_ctx, {complete, erlang:element(3, erlang:element(6, Instance))}, Instance} end end ) end. -file("src/telega/flow.gleam", 2539). ?DOC(" Compose flows sequentially\n"). -spec compose_sequential( binary(), list(flow(gleam@dynamic:dynamic_(), AVFO, AVFP)), flow_storage(AVFP) ) -> flow(composed_step(), AVFO, AVFP). compose_sequential(Name, Flows, Storage) -> Builder = new( Name, Storage, fun composed_step_to_string/1, fun string_to_composed_step/1 ), Builder@2 = gleam@list:index_fold( Flows, Builder, fun(Builder@1, Flow, Index) -> Step = {composed_flow_step, Index}, add_step( Builder@1, Step, create_composed_handler(Flow, Flows, Index) ) end ), build(Builder@2, {composed_flow_step, 0}). -file("src/telega/flow.gleam", 2282). ?DOC(" Process action within a subflow\n"). -spec process_subflow_action( flow(gleam@dynamic:dynamic_(), AVCZ, AVDA), telega@bot:context(AVCZ, AVDA), flow_action(gleam@dynamic:dynamic_()), flow_instance(), subflow_config(any(), AVCZ, AVDA) ) -> {ok, telega@bot:context(AVCZ, AVDA)} | {error, AVDA}. process_subflow_action(Flow, Ctx, Action, Instance, Config) -> case Action of {complete, Data} -> return_to_parent_flow(Ctx, Instance, Data, Config); {exit, {some, Data}} -> return_to_parent_flow(Ctx, Instance, Data, Config); {exit, none} -> return_to_parent_flow( Ctx, Instance, erlang:element(3, erlang:element(6, Instance)), Config ); {return_from_subflow, Result} -> return_to_parent_flow(Ctx, Instance, Result, Config); cancel -> _ = (erlang:element(4, erlang:element(7, Flow)))( erlang:element(2, Instance) ), {ok, Ctx}; {next, Step} -> Step_name = (erlang:element(5, Flow))(Step), Updated_instance = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record = erlang:element(6, Instance), {flow_state, Step_name, erlang:element(3, _record), [erlang:element(2, erlang:element(6, Instance)) | erlang:element(4, erlang:element(6, Instance))], erlang:element(5, _record), erlang:element(6, _record)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))(Updated_instance) of {ok, _} -> execute_subflow_step(Flow, Ctx, Updated_instance, Config); {error, Err} -> handle_subflow_error( Flow, Ctx, Instance, {some, Err}, Config ) end; {next_string, Step_name@1} -> Updated_instance@1 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record@1 = erlang:element(6, Instance), {flow_state, Step_name@1, erlang:element(3, _record@1), [erlang:element(2, erlang:element(6, Instance)) | erlang:element(4, erlang:element(6, Instance))], erlang:element(5, _record@1), erlang:element(6, _record@1)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@1 ) of {ok, _} -> execute_subflow_step(Flow, Ctx, Updated_instance@1, Config); {error, Err@1} -> handle_subflow_error( Flow, Ctx, Instance, {some, Err@1}, Config ) end; {go_to, Step@1} -> Step_name@2 = (erlang:element(5, Flow))(Step@1), Updated_instance@2 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), {flow_state, Step_name@2, erlang:element(3, erlang:element(6, Instance)), [Step_name@2], erlang:element(5, erlang:element(6, Instance)), none}, maps:new(), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@2 ) of {ok, _} -> execute_subflow_step(Flow, Ctx, Updated_instance@2, Config); {error, Err@2} -> handle_subflow_error( Flow, Ctx, Instance, {some, Err@2}, Config ) end; back -> case erlang:element(4, erlang:element(6, Instance)) of [Previous_step | Rest] -> Updated_instance@3 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), begin _record@2 = erlang:element(6, Instance), {flow_state, Previous_step, erlang:element(3, _record@2), Rest, erlang:element(5, _record@2), erlang:element(6, _record@2)} end, erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@3 ) of {ok, _} -> execute_subflow_step( Flow, Ctx, Updated_instance@3, Config ); {error, Err@3} -> handle_subflow_error( Flow, Ctx, Instance, {some, Err@3}, Config ) end; [] -> {ok, Ctx} end; {wait, Token} -> Updated_instance@4 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), erlang:element(7, Instance), {some, Token}, erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@4 ) of {ok, _} -> {ok, Ctx}; {error, Err@4} -> handle_subflow_error( Flow, Ctx, Instance, {some, Err@4}, Config ) end; {wait_callback, Token@1} -> Updated_instance@5 = {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), erlang:element(7, Instance), {some, Token@1}, erlang:element(9, Instance), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Flow)))( Updated_instance@5 ) of {ok, _} -> {ok, Ctx}; {error, Err@5} -> handle_subflow_error( Flow, Ctx, Instance, {some, Err@5}, Config ) end; {start_parallel, _, _} -> {ok, Ctx}; {complete_parallel_step, _, _} -> {ok, Ctx}; {enter_subflow, _, _} -> {ok, Ctx} end. -file("src/telega/flow.gleam", 2254). ?DOC(" Execute a step within a subflow context\n"). -spec execute_subflow_step( flow(gleam@dynamic:dynamic_(), AVCK, AVCL), telega@bot:context(AVCK, AVCL), flow_instance(), subflow_config(any(), AVCK, AVCL) ) -> {ok, telega@bot:context(AVCK, AVCL)} | {error, AVCL}. execute_subflow_step(Flow, Ctx, Instance, Config) -> case gleam_stdlib:map_get( erlang:element(3, Flow), erlang:element(2, erlang:element(6, Instance)) ) of {ok, Step_config} -> Handler_fn = fun() -> (erlang:element(2, Step_config))(Ctx, Instance) end, Result = apply_middlewares( Ctx, Instance, Handler_fn, lists:append( erlang:element(10, Flow), erlang:element(3, Step_config) ) ), case Result of {ok, {New_ctx, Action, New_instance}} -> process_subflow_action( Flow, New_ctx, Action, New_instance, Config ); {error, Err} -> handle_subflow_error( Flow, Ctx, Instance, {some, Err}, Config ) end; {error, _} -> handle_subflow_error(Flow, Ctx, Instance, none, Config) end. -file("src/telega/flow.gleam", 2197). ?DOC(" Start subflow execution\n"). -spec start_subflow_execution( flow(AVBV, AVBW, AVBX), telega@bot:context(AVBW, AVBX), flow_instance(), subflow_config(AVBV, AVBW, AVBX) ) -> {ok, telega@bot:context(AVBW, AVBX)} | {error, AVBX}. start_subflow_execution(Parent_flow, Ctx, Instance, Config) -> case run_flow_leave_hook(erlang:element(15, Parent_flow), Ctx, Instance) of {ok, {Ctx_after_leave, Instance_after_leave}} -> Return_step = (erlang:element(5, Parent_flow))( erlang:element(4, Config) ), Stack_frame = {flow_stack_frame, erlang:element(2, Parent_flow), Return_step, erlang:element(3, erlang:element(6, Instance_after_leave))}, Subflow_data = (erlang:element(5, Config))(Instance_after_leave), Subflow_initial_step = (erlang:element(5, erlang:element(3, Config)))( erlang:element(4, erlang:element(3, Config)) ), Updated_instance = {flow_instance, erlang:element(2, Instance_after_leave), erlang:element(2, erlang:element(3, Config)), erlang:element(4, Instance_after_leave), erlang:element(5, Instance_after_leave), {flow_state, Subflow_initial_step, Subflow_data, [Subflow_initial_step], [Stack_frame | erlang:element( 5, erlang:element(6, Instance_after_leave) )], none}, maps:new(), erlang:element(8, Instance_after_leave), erlang:element(9, Instance_after_leave), telega@internal@utils:current_time_ms()}, case (erlang:element(2, erlang:element(7, Parent_flow)))( Updated_instance ) of {ok, _} -> execute_subflow_step( erlang:element(3, Config), Ctx_after_leave, Updated_instance, Config ); {error, Err} -> handle_error(Parent_flow, Ctx, Instance, {some, Err}) end; {error, Err@1} -> handle_error(Parent_flow, Ctx, Instance, {some, Err@1}) end.