-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_global_middleware/2, add_conditional/5, add_multi_conditional/4, add_parallel_steps/4, parallel/4, add_subflow/6, on_complete/2, on_error/2, build/2, next/3, unsafe_next/3, goto/3, back/2, complete/2, cancel/2, wait/3, wait_callback/3, exit/3, get_current_step/2, store_scene_data/3, get_scene_data/2, clear_scene_data/1, clear_scene_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, 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, 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(AQZD) :: {flow_storage, fun((flow_instance()) -> {ok, nil} | {error, AQZD}), fun((binary()) -> {ok, gleam@option:option(flow_instance())} | {error, AQZD}), fun((binary()) -> {ok, nil} | {error, AQZD}), fun((integer(), integer()) -> {ok, list(flow_instance())} | {error, AQZD})}. -opaque flow_builder(AQZE, AQZF, AQZG) :: {flow_builder, binary(), gleam@dict:dict(binary(), step_config(AQZE, AQZF, AQZG)), fun((AQZE) -> binary()), fun((binary()) -> {ok, AQZE} | {error, nil}), flow_storage(AQZG), gleam@option:option(fun((telega@bot:context(AQZF, AQZG), flow_instance()) -> {ok, telega@bot:context(AQZF, AQZG)} | {error, AQZG})), gleam@option:option(fun((telega@bot:context(AQZF, AQZG), flow_instance(), gleam@option:option(AQZG)) -> {ok, telega@bot:context(AQZF, AQZG)} | {error, AQZG})), list(fun((telega@bot:context(AQZF, AQZG), flow_instance(), fun(() -> {ok, {telega@bot:context(AQZF, AQZG), flow_action(AQZE), flow_instance()}} | {error, AQZG})) -> {ok, {telega@bot:context(AQZF, AQZG), flow_action(AQZE), flow_instance()}} | {error, AQZG})), list(conditional_transition(AQZE)), list(parallel_config(AQZE)), list(subflow_config(AQZE, AQZF, AQZG))}. -opaque flow(AQZH, AQZI, AQZJ) :: {flow, binary(), gleam@dict:dict(binary(), step_config(AQZH, AQZI, AQZJ)), AQZH, fun((AQZH) -> binary()), fun((binary()) -> {ok, AQZH} | {error, nil}), flow_storage(AQZJ), gleam@option:option(fun((telega@bot:context(AQZI, AQZJ), flow_instance()) -> {ok, telega@bot:context(AQZI, AQZJ)} | {error, AQZJ})), gleam@option:option(fun((telega@bot:context(AQZI, AQZJ), flow_instance(), gleam@option:option(AQZJ)) -> {ok, telega@bot:context(AQZI, AQZJ)} | {error, AQZJ})), list(fun((telega@bot:context(AQZI, AQZJ), flow_instance(), fun(() -> {ok, {telega@bot:context(AQZI, AQZJ), flow_action(AQZH), flow_instance()}} | {error, AQZJ})) -> {ok, {telega@bot:context(AQZI, AQZJ), flow_action(AQZH), flow_instance()}} | {error, AQZJ})), list(conditional_transition(AQZH)), list(parallel_config(AQZH)), list(subflow_config(AQZH, AQZI, AQZJ))}. -opaque flow_registry(AQZK, AQZL) :: {flow_registry, list({flow_trigger(), flow(gleam@dynamic:dynamic_(), AQZK, AQZL), gleam@dict:dict(binary(), binary())}), gleam@dict:dict(binary(), flow(gleam@dynamic:dynamic_(), AQZK, AQZL))}. -type step_config(AQZM, AQZN, AQZO) :: {step_config, fun((telega@bot:context(AQZN, AQZO), flow_instance()) -> {ok, {telega@bot:context(AQZN, AQZO), flow_action(AQZM), flow_instance()}} | {error, AQZO}), list(fun((telega@bot:context(AQZN, AQZO), flow_instance(), fun(() -> {ok, {telega@bot:context(AQZN, AQZO), flow_action(AQZM), flow_instance()}} | {error, AQZO})) -> {ok, {telega@bot:context(AQZN, AQZO), flow_action(AQZM), flow_instance()}} | {error, AQZO}))}. -type conditional_transition(AQZP) :: {conditional_transition, binary(), list({fun((flow_instance()) -> boolean()), AQZP}), AQZP}. -type parallel_config(AQZQ) :: {parallel_config, binary(), list(AQZQ), AQZQ}. -type subflow_config(AQZR, AQZS, AQZT) :: {subflow_config, binary(), flow(gleam@dynamic:dynamic_(), AQZS, AQZT), AQZR, fun((flow_instance()) -> gleam@dict:dict(binary(), binary())), fun((gleam@dict:dict(binary(), binary()), flow_instance()) -> flow_instance())}. -type flow_action(AQZU) :: {next, AQZU} | {next_string, binary()} | back | {complete, gleam@dict:dict(binary(), binary())} | cancel | {wait, binary()} | {wait_callback, binary()} | {go_to, AQZU} | {exit, gleam@option:option(gleam@dict:dict(binary(), binary()))} | {return_from_subflow, gleam@dict:dict(binary(), binary())} | {start_parallel, list(AQZU), AQZU} | {complete_parallel_step, AQZU, gleam@dict:dict(binary(), 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", 279). ?DOC(" Create a new flow builder\n"). -spec new( binary(), flow_storage(ARAW), fun((ARAY) -> binary()), fun((binary()) -> {ok, ARAY} | {error, nil}) ) -> flow_builder(ARAY, any(), ARAW). 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, [], [], [], []}. -file("src/telega/flow.gleam", 322). ?DOC(" Add a step to the flow\n"). -spec add_step( flow_builder(ARBN, ARBO, ARBP), ARBN, fun((telega@bot:context(ARBO, ARBP), flow_instance()) -> {ok, {telega@bot:context(ARBO, ARBP), flow_action(ARBN), flow_instance()}} | {error, ARBP}) ) -> flow_builder(ARBN, ARBO, ARBP). add_step(Builder, Step, Handler) -> Step_name = (erlang:element(4, Builder))(Step), Config = {step_config, Handler, []}, {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)}. -file("src/telega/flow.gleam", 333). ?DOC(" Add a step with middleware\n"). -spec add_step_with_middleware( flow_builder(ARBZ, ARCA, ARCB), ARBZ, list(fun((telega@bot:context(ARCA, ARCB), flow_instance(), fun(() -> {ok, {telega@bot:context(ARCA, ARCB), flow_action(ARBZ), flow_instance()}} | {error, ARCB})) -> {ok, {telega@bot:context(ARCA, ARCB), flow_action(ARBZ), flow_instance()}} | {error, ARCB})), fun((telega@bot:context(ARCA, ARCB), flow_instance()) -> {ok, {telega@bot:context(ARCA, ARCB), flow_action(ARBZ), flow_instance()}} | {error, ARCB}) ) -> flow_builder(ARBZ, ARCA, ARCB). add_step_with_middleware(Builder, Step, Middlewares, Handler) -> Step_name = (erlang:element(4, Builder))(Step), Config = {step_config, Handler, Middlewares}, {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)}. -file("src/telega/flow.gleam", 345). ?DOC(" Add global middleware that applies to all steps\n"). -spec add_global_middleware( flow_builder(ARCP, ARCQ, ARCR), fun((telega@bot:context(ARCQ, ARCR), flow_instance(), fun(() -> {ok, {telega@bot:context(ARCQ, ARCR), flow_action(ARCP), flow_instance()}} | {error, ARCR})) -> {ok, {telega@bot:context(ARCQ, ARCR), flow_action(ARCP), flow_instance()}} | {error, ARCR}) ) -> flow_builder(ARCP, ARCQ, ARCR). 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)}. -file("src/telega/flow.gleam", 356). ?DOC(" Add conditional transition\n"). -spec add_conditional( flow_builder(ARDB, ARDC, ARDD), ARDB, fun((flow_instance()) -> boolean()), ARDB, ARDB ) -> flow_builder(ARDB, ARDC, ARDD). 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)}. -file("src/telega/flow.gleam", 377). ?DOC(" Add multi-way conditional\n"). -spec add_multi_conditional( flow_builder(ARDK, ARDL, ARDM), ARDK, list({fun((flow_instance()) -> boolean()), ARDK}), ARDK ) -> flow_builder(ARDK, ARDL, ARDM). 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)}. -file("src/telega/flow.gleam", 425). ?DOC( " Add parallel step execution.\n" "\n" " @deprecated Use `parallel()` instead for cleaner API.\n" ). -spec add_parallel_steps(flow_builder(AREE, AREF, AREG), AREE, list(AREE), AREE) -> flow_builder(AREE, AREF, AREG). 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)}. -file("src/telega/flow.gleam", 413). ?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(ARDU, ARDV, ARDW), ARDU, list(ARDU), ARDU) -> flow_builder(ARDU, ARDV, ARDW). parallel(Builder, From, Steps, Join) -> add_parallel_steps(Builder, From, Steps, Join). -file("src/telega/flow.gleam", 445). ?DOC(" Add sub-flow\n"). -spec add_subflow( flow_builder(AREO, AREP, AREQ), AREO, flow(gleam@dynamic:dynamic_(), AREP, AREQ), AREO, fun((flow_instance()) -> gleam@dict:dict(binary(), binary())), fun((gleam@dict:dict(binary(), binary()), flow_instance()) -> flow_instance()) ) -> flow_builder(AREO, AREP, AREQ). 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])}. -file("src/telega/flow.gleam", 466). ?DOC(" Set completion handler\n"). -spec on_complete( flow_builder(ARFE, ARFF, ARFG), fun((telega@bot:context(ARFF, ARFG), flow_instance()) -> {ok, telega@bot:context(ARFF, ARFG)} | {error, ARFG}) ) -> flow_builder(ARFE, ARFF, ARFG). 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)}. -file("src/telega/flow.gleam", 475). ?DOC(" Set error handler\n"). -spec on_error( flow_builder(ARFT, ARFU, ARFV), fun((telega@bot:context(ARFU, ARFV), flow_instance(), gleam@option:option(ARFV)) -> {ok, telega@bot:context(ARFU, ARFV)} | {error, ARFV}) ) -> flow_builder(ARFT, ARFU, ARFV). 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)}. -file("src/telega/flow.gleam", 484). ?DOC(" Build the flow\n"). -spec build(flow_builder(ARGJ, ARGK, ARGL), ARGJ) -> flow(ARGJ, ARGK, ARGL). 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)}. -file("src/telega/flow.gleam", 505). ?DOC(" Next navigation\n"). -spec next(telega@bot:context(ARGS, ARGT), flow_instance(), ARGW) -> {ok, {telega@bot:context(ARGS, ARGT), flow_action(ARGW), flow_instance()}} | {error, ARGT}. next(Ctx, Instance, Step) -> {ok, {Ctx, {next, Step}, Instance}}. -file("src/telega/flow.gleam", 514). ?DOC(" Next navigation with string step (for dynamic navigation)\n"). -spec unsafe_next(telega@bot:context(ARHA, ARHB), flow_instance(), binary()) -> {ok, {telega@bot:context(ARHA, ARHB), flow_action(any()), flow_instance()}} | {error, ARHB}. unsafe_next(Ctx, Instance, Step) -> {ok, {Ctx, {next_string, Step}, Instance}}. -file("src/telega/flow.gleam", 523). ?DOC(" Type-safe goto navigation (clears scene data)\n"). -spec goto(telega@bot:context(ARHI, ARHJ), flow_instance(), ARHM) -> {ok, {telega@bot:context(ARHI, ARHJ), flow_action(ARHM), flow_instance()}} | {error, ARHJ}. goto(Ctx, Instance, Step) -> {ok, {Ctx, {go_to, Step}, Instance}}. -file("src/telega/flow.gleam", 532). ?DOC(" Go back to previous step\n"). -spec back(telega@bot:context(ARHQ, ARHR), flow_instance()) -> {ok, {telega@bot:context(ARHQ, ARHR), flow_action(any()), flow_instance()}} | {error, ARHR}. back(Ctx, Instance) -> {ok, {Ctx, back, Instance}}. -file("src/telega/flow.gleam", 540). ?DOC(" Complete the flow\n"). -spec complete(telega@bot:context(ARHY, ARHZ), flow_instance()) -> {ok, {telega@bot:context(ARHY, ARHZ), flow_action(any()), flow_instance()}} | {error, ARHZ}. complete(Ctx, Instance) -> {ok, {Ctx, {complete, erlang:element(3, erlang:element(6, Instance))}, Instance}}. -file("src/telega/flow.gleam", 548). ?DOC(" Cancel the flow\n"). -spec cancel(telega@bot:context(ARIG, ARIH), flow_instance()) -> {ok, {telega@bot:context(ARIG, ARIH), flow_action(any()), flow_instance()}} | {error, ARIH}. cancel(Ctx, Instance) -> {ok, {Ctx, cancel, Instance}}. -file("src/telega/flow.gleam", 556). ?DOC(" Wait for user input\n"). -spec wait(telega@bot:context(ARIO, ARIP), flow_instance(), binary()) -> {ok, {telega@bot:context(ARIO, ARIP), flow_action(any()), flow_instance()}} | {error, ARIP}. wait(Ctx, Instance, Token) -> {ok, {Ctx, {wait, Token}, Instance}}. -file("src/telega/flow.gleam", 565). ?DOC(" Wait for callback\n"). -spec wait_callback(telega@bot:context(ARIW, ARIX), flow_instance(), binary()) -> {ok, {telega@bot:context(ARIW, ARIX), flow_action(any()), flow_instance()}} | {error, ARIX}. wait_callback(Ctx, Instance, Token) -> {ok, {Ctx, {wait_callback, <<<>/binary, (erlang:element(2, Instance))/binary>>}, Instance}}. -file("src/telega/flow.gleam", 574). ?DOC(" Exit with result\n"). -spec exit( telega@bot:context(ARJE, ARJF), flow_instance(), gleam@option:option(gleam@dict:dict(binary(), binary())) ) -> {ok, {telega@bot:context(ARJE, ARJF), flow_action(any()), flow_instance()}} | {error, ARJF}. exit(Ctx, Instance, Result) -> {ok, {Ctx, {exit, Result}, Instance}}. -file("src/telega/flow.gleam", 667). ?DOC(" Get current step\n"). -spec get_current_step(flow(ARKS, any(), any()), flow_instance()) -> {ok, ARKS} | {error, nil}. get_current_step(Flow, Instance) -> (erlang:element(6, Flow))(erlang:element(2, erlang:element(6, Instance))). -file("src/telega/flow.gleam", 675). ?DOC(" Store scene data\n"). -spec store_scene_data(flow_instance(), binary(), binary()) -> flow_instance(). store_scene_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", 687). ?DOC(" Get scene data\n"). -spec get_scene_data(flow_instance(), binary()) -> gleam@option:option(binary()). get_scene_data(Instance, Key) -> _pipe = gleam_stdlib:map_get(erlang:element(7, Instance), Key), gleam@option:from_result(_pipe). -file("src/telega/flow.gleam", 693). ?DOC(" Clear all scene data\n"). -spec clear_scene_data(flow_instance()) -> flow_instance(). clear_scene_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", 698). ?DOC(" Clear specific scene data key\n"). -spec clear_scene_data_key(flow_instance(), binary()) -> flow_instance(). clear_scene_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", 705). -spec is_callback_passed(flow_instance(), binary(), binary()) -> gleam@option:option(boolean()). is_callback_passed(Instance, Key, Callback_id) -> case get_scene_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", 723). ?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", 738). ?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", 745). ?DOC(" Update instance data and continue to next step\n"). -spec next_with_data( telega@bot:context(ARLD, ARLE), flow_instance(), ARLH, binary(), binary() ) -> {ok, {telega@bot:context(ARLD, ARLE), flow_action(ARLH), flow_instance()}} | {error, ARLE}. 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", 756). -spec find_instance_by_token(flow_storage(ARLL), binary()) -> {ok, gleam@option:option(flow_instance())} | {error, ARLL}. 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", 1091). -spec handle_error( flow(any(), ARMQ, ARMR), telega@bot:context(ARMQ, ARMR), flow_instance(), gleam@option:option(ARMR) ) -> {ok, telega@bot:context(ARMQ, ARMR)} | {error, ARMR}. 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", 1108). -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", 1113). ?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", 1124). ?DOC(" Convert a step type to string using the type's string representation\n"). -spec step_to_string_default(any()) -> binary(). step_to_string_default(Step) -> gleam@string:inspect(Step). -file("src/telega/flow.gleam", 1129). ?DOC(" Helper to create a string_to_step function for a list of steps\n"). -spec create_string_to_step(list({binary(), ARNF})) -> fun((binary()) -> {ok, ARNF} | {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", 301). ?DOC(" Create a flow builder with default string conversion (uses string.inspect)\n"). -spec new_with_default_converters( binary(), flow_storage(ARBF), list({binary(), ARBH}) ) -> flow_builder(ARBH, any(), ARBF). new_with_default_converters(Flow_name, Storage, Steps) -> {flow_builder, Flow_name, maps:new(), fun step_to_string_default/1, create_string_to_step(Steps), Storage, none, none, [], [], [], []}. -file("src/telega/flow.gleam", 1137). ?DOC(" Generate a unique wait token (internal)\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", 1142). ?DOC(" Create a text input step\n"). -spec text_step(binary(), binary(), ARNJ) -> fun((telega@bot:context(ARNK, ARNL), flow_instance()) -> {ok, {telega@bot:context(ARNK, ARNL), flow_action(ARNJ), flow_instance()}} | {error, ARNL}). text_step(Prompt, Data_key, Next_step) -> fun(Ctx, Instance) -> case get_scene_data(Instance, <<"user_input"/utf8>>) of {some, Value} -> Instance@1 = begin _pipe = Instance, _pipe@1 = store_data(_pipe, Data_key, Value), clear_scene_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", 1170). ?DOC(" Create a message display step\n"). -spec message_step( fun((flow_instance()) -> binary()), gleam@option:option(ARNP) ) -> fun((telega@bot:context(ARNR, ARNS), flow_instance()) -> {ok, {telega@bot:context(ARNR, ARNS), flow_action(ARNP), flow_instance()}} | {error, ARNS}). 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", 1276). ?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", 1363). -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", 1368). ?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", 1382). ?DOC(" Add a flow to the registry with a trigger and initial data\n"). -spec register_with_data( flow_registry(ARTC, ARTD), flow_trigger(), flow(any(), ARTC, ARTD), gleam@dict:dict(binary(), binary()) ) -> flow_registry(ARTC, ARTD). 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", 1373). ?DOC(" Add a flow to the registry with a trigger\n"). -spec register( flow_registry(ARSS, ARST), flow_trigger(), flow(any(), ARSS, ARST) ) -> flow_registry(ARSS, ARST). register(Registry, Trigger, Flow) -> register_with_data(Registry, Trigger, Flow, maps:new()). -file("src/telega/flow.gleam", 1396). ?DOC(" Register a flow without a trigger (for calling from handlers)\n"). -spec register_callable(flow_registry(ARTO, ARTP), flow(any(), ARTO, ARTP)) -> flow_registry(ARTO, ARTP). 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", 1555). ?DOC(" Apply middleware chain to handler\n"). -spec apply_middlewares( telega@bot:context(ARVL, ARVM), flow_instance(), fun(() -> {ok, {telega@bot:context(ARVL, ARVM), flow_action(ARVP), flow_instance()}} | {error, ARVM}), list(fun((telega@bot:context(ARVL, ARVM), flow_instance(), fun(() -> {ok, {telega@bot:context(ARVL, ARVM), flow_action(ARVP), flow_instance()}} | {error, ARVM})) -> {ok, {telega@bot:context(ARVL, ARVM), flow_action(ARVP), flow_instance()}} | {error, ARVM})) ) -> {ok, {telega@bot:context(ARVL, ARVM), flow_action(ARVP), flow_instance()}} | {error, ARVM}. 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", 1572). ?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", 1604). ?DOC(" Check if current step triggers parallel execution\n"). -spec check_parallel_trigger(flow(ARWH, any(), any()), flow_instance()) -> gleam@option:option(parallel_config(ARWH)). 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", 1656). ?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", 1783). -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", 1793). -spec string_to_composed_step(binary()) -> {ok, composed_step()} | {error, nil}. string_to_composed_step(S) -> case S 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(S, <<"flow_"/utf8>>) of true -> _pipe = gleam@string:drop_start(S, 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( S, <<"parallel_"/utf8>> ) of true -> _pipe@3 = gleam@string:drop_start(S, 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", 1840). ?DOC(" Validation middleware\n"). -spec validation_middleware( fun((flow_instance()) -> {ok, nil} | {error, binary()}) ) -> fun((telega@bot:context(ARZL, ARZM), flow_instance(), fun(() -> {ok, {telega@bot:context(ARZL, ARZM), flow_action(ARZK), flow_instance()}} | {error, ARZM})) -> {ok, {telega@bot:context(ARZL, ARZM), flow_action(ARZK), flow_instance()}} | {error, ARZM}). 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", 818). -spec process_action( flow(ARMC, ARMD, ARME), telega@bot:context(ARMD, ARME), flow_action(ARMC), flow_instance() ) -> {ok, telega@bot:context(ARMD, ARME)} | {error, ARME}. 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} -> case erlang:element(8, Flow) of {some, Handler} -> 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 Handler(Ctx, Completed_instance) of {ok, New_ctx} -> _ = (erlang:element(4, erlang:element(7, Flow)))( erlang:element(2, Instance) ), {ok, New_ctx}; {error, Err@8} -> handle_error(Flow, Ctx, Instance, {some, Err@8}) end; none -> _ = (erlang:element(4, erlang:element(7, Flow)))( erlang:element(2, Instance) ), {ok, Ctx} end; cancel -> _ = (erlang:element(4, erlang:element(7, Flow)))( erlang:element(2, Instance) ), {ok, Ctx}; {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@9} -> handle_error(Flow, Ctx, Instance, {some, Err@9}) 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@10} -> handle_error(Flow, Ctx, Instance, {some, Err@10}) end; {exit, _} -> _ = (erlang:element(4, erlang:element(7, Flow)))( erlang:element(2, Instance) ), {ok, Ctx} end. -file("src/telega/flow.gleam", 766). -spec execute_step( flow(any(), ARLR, ARLS), telega@bot:context(ARLR, ARLS), flow_instance() ) -> {ok, telega@bot:context(ARLR, ARLS)} | {error, ARLS}. 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 gleam_stdlib:map_get( erlang:element(3, Flow), erlang:element(2, erlang:element(6, Instance)) ) of {ok, Config@1} -> Handler_fn = fun() -> (erlang:element(2, Config@1))(Ctx, Instance) end, Result = apply_middlewares( Ctx, Instance, Handler_fn, lists:append( erlang:element(10, Flow), erlang:element(3, Config@1) ) ), case Result of {ok, {New_ctx, Action, New_instance}} -> process_action( Flow, New_ctx, Action, New_instance ); {error, Err@1} -> handle_error( Flow, Ctx, Instance, {some, Err@1} ) end; {error, _} -> handle_error(Flow, Ctx, Instance, none) end end end. -file("src/telega/flow.gleam", 582). -spec start_or_resume( flow(any(), ARJQ, ARJR), telega@bot:context(ARJQ, ARJR), integer(), integer(), gleam@dict:dict(binary(), binary()) ) -> {ok, telega@bot:context(ARJQ, ARJR)} | {error, ARJR}. 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, _} -> execute_step(Flow, Ctx, New_instance); {error, Err} -> handle_error(Flow, Ctx, New_instance, {some, Err}) end; {error, Err@1} -> 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@1}) end. -file("src/telega/flow.gleam", 643). -spec resume_with_token( flow(any(), ARKE, ARKF), telega@bot:context(ARKE, ARKF), binary(), gleam@option:option(gleam@dict:dict(binary(), binary())) ) -> {ok, telega@bot:context(ARKE, ARKF)} | {error, ARKF}. 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", 1206). ?DOC(" Create a text handler for resuming flows\n"). -spec create_text_handler(flow(any(), AROW, AROX)) -> fun((telega@bot:context(AROW, AROX), telega@update:update()) -> {ok, telega@bot:context(AROW, AROX)} | {error, AROX}). 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", 1281). ?DOC(" Start a flow with optional initial data\n"). -spec start( flow(any(), ARPY, ARPZ), gleam@dict:dict(binary(), binary()), telega@bot:context(ARPY, ARPZ) ) -> {ok, telega@bot:context(ARPY, ARPZ)} | {error, ARPZ}. 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", 1263). ?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(ARPH, ARPI), flow_registry(ARPH, ARPI), binary(), gleam@dict:dict(binary(), binary()) ) -> {ok, telega@bot:context(ARPH, ARPI)} | {error, ARPI}. 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", 1291). ?DOC(" Create a router handler that starts a flow\n"). -spec to_handler(flow(any(), ARQM, ARQN)) -> fun((telega@bot:context(ARQM, ARQN), telega@update:command()) -> {ok, telega@bot:context(ARQM, ARQN)} | {error, ARQN}). to_handler(Flow) -> fun(Ctx, _) -> start(Flow, maps:new(), Ctx) end. -file("src/telega/flow.gleam", 1299). ?DOC(" Create a router handler that starts a flow with initial data (internal)\n"). -spec to_handler_with_data( flow(any(), ARQY, ARQZ), gleam@dict:dict(binary(), binary()) ) -> fun((telega@bot:context(ARQY, ARQZ), telega@update:command()) -> {ok, telega@bot:context(ARQY, ARQZ)} | {error, ARQZ}). to_handler_with_data(Flow, Initial_data) -> fun(Ctx, _) -> start(Flow, Initial_data, Ctx) end. -file("src/telega/flow.gleam", 1308). ?DOC(" Create a router handler for resuming flows from callback queries (internal)\n"). -spec resume_handler(flow(any(), ARRM, ARRN)) -> fun((telega@bot:context(ARRM, ARRN), telega@update:update()) -> {ok, telega@bot:context(ARRM, ARRN)} | {error, ARRN}). 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", 1189). ?DOC(" Create a router handler for resuming flows from callback queries\n"). -spec create_resume_handler(flow(any(), ARNX, ARNY)) -> fun((telega@bot:context(ARNX, ARNY), telega@update:update()) -> {ok, telega@bot:context(ARNX, ARNY)} | {error, ARNY}). create_resume_handler(Flow) -> resume_handler(Flow). -file("src/telega/flow.gleam", 1328). ?DOC(" Create a router handler for resuming flows from callback queries with keyboard parsing (internal)\n"). -spec resume_handler_with_keyboard( flow(any(), ARRY, ARRZ), telega@keyboard:keyboard_callback_data(binary()) ) -> fun((telega@bot:context(ARRY, ARRZ), telega@update:update()) -> {ok, telega@bot:context(ARRY, ARRZ)} | {error, ARRZ}). 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", 1197). ?DOC(" Create a router handler for resuming flows from callback queries with keyboard parsing\n"). -spec create_resume_handler_with_keyboard( flow(any(), AROJ, AROK), telega@keyboard:keyboard_callback_data(binary()) ) -> fun((telega@bot:context(AROJ, AROK), telega@update:update()) -> {ok, telega@bot:context(AROJ, AROK)} | {error, AROK}). create_resume_handler_with_keyboard(Flow, Callback_data) -> resume_handler_with_keyboard(Flow, Callback_data). -file("src/telega/flow.gleam", 1432). ?DOC(" Internal: Add a flow route to router\n"). -spec add_flow_route( telega@router:router(ARUG, ARUH), flow_trigger(), flow(gleam@dynamic:dynamic_(), ARUG, ARUH), gleam@dict:dict(binary(), binary()) ) -> telega@router:router(ARUG, ARUH). 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", 1475). ?DOC(" Auto-resume handler for text messages\n"). -spec auto_resume_handler(flow_registry(ARUR, ARUS)) -> fun((telega@bot:context(ARUR, ARUS), binary()) -> {ok, telega@bot:context(ARUR, ARUS)} | {error, ARUS}). 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", 1516). ?DOC(" Auto-resume handler for callback queries (internal)\n"). -spec auto_resume_callback_handler(flow_registry(ARVB, ARVC)) -> fun((telega@bot:context(ARVB, ARVC), binary(), binary()) -> {ok, telega@bot:context(ARVB, ARVC)} | {error, ARVC}). 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", 1408). ?DOC(" Apply all registered flows to a router\n"). -spec apply_to_router( telega@router:router(ARTY, ARTZ), flow_registry(ARTY, ARTZ) ) -> telega@router:router(ARTY, ARTZ). 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", 1615). ?DOC(" Start parallel execution\n"). -spec start_parallel_execution( flow(ARWP, ARWQ, ARWR), telega@bot:context(ARWQ, ARWR), flow_instance(), parallel_config(ARWP) ) -> {ok, telega@bot:context(ARWQ, ARWR)} | {error, ARWR}. 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", 1688). ?DOC(" Compose flows with conditional selection\n"). -spec compose_conditional( binary(), fun((flow_instance()) -> binary()), gleam@dict:dict(binary(), flow(gleam@dynamic:dynamic_(), ARXU, ARXV)), flow_storage(ARXV) ) -> flow(composed_step(), ARXU, ARXV). 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", 1718). ?DOC(" Compose flows for parallel execution\n"). -spec compose_parallel( binary(), list(flow(gleam@dynamic:dynamic_(), ARYF, ARYG)), fun((list(gleam@dict:dict(binary(), binary()))) -> gleam@dict:dict(binary(), binary())), flow_storage(ARYG) ) -> flow(composed_step(), ARYF, ARYG). 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", 1822). -spec create_composed_handler( flow(gleam@dynamic:dynamic_(), ARYW, ARYX), list(flow(gleam@dynamic:dynamic_(), ARYW, ARYX)), integer() ) -> fun((telega@bot:context(ARYW, ARYX), flow_instance()) -> {ok, {telega@bot:context(ARYW, ARYX), flow_action(composed_step()), flow_instance()}} | {error, ARYX}). 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", 1668). ?DOC(" Compose flows sequentially\n"). -spec compose_sequential( binary(), list(flow(gleam@dynamic:dynamic_(), ARXK, ARXL)), flow_storage(ARXL) ) -> flow(composed_step(), ARXK, ARXL). 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}).