-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(ASCI) :: {flow_storage, fun((flow_instance()) -> {ok, nil} | {error, ASCI}), fun((binary()) -> {ok, gleam@option:option(flow_instance())} | {error, ASCI}), fun((binary()) -> {ok, nil} | {error, ASCI}), fun((integer(), integer()) -> {ok, list(flow_instance())} | {error, ASCI})}. -opaque flow_builder(ASCJ, ASCK, ASCL) :: {flow_builder, binary(), gleam@dict:dict(binary(), step_config(ASCJ, ASCK, ASCL)), fun((ASCJ) -> binary()), fun((binary()) -> {ok, ASCJ} | {error, nil}), flow_storage(ASCL), gleam@option:option(fun((telega@bot:context(ASCK, ASCL), flow_instance()) -> {ok, telega@bot:context(ASCK, ASCL)} | {error, ASCL})), gleam@option:option(fun((telega@bot:context(ASCK, ASCL), flow_instance(), gleam@option:option(ASCL)) -> {ok, telega@bot:context(ASCK, ASCL)} | {error, ASCL})), list(fun((telega@bot:context(ASCK, ASCL), flow_instance(), fun(() -> {ok, {telega@bot:context(ASCK, ASCL), flow_action(ASCJ), flow_instance()}} | {error, ASCL})) -> {ok, {telega@bot:context(ASCK, ASCL), flow_action(ASCJ), flow_instance()}} | {error, ASCL})), list(conditional_transition(ASCJ)), list(parallel_config(ASCJ)), list(subflow_config(ASCJ, ASCK, ASCL))}. -opaque flow(ASCM, ASCN, ASCO) :: {flow, binary(), gleam@dict:dict(binary(), step_config(ASCM, ASCN, ASCO)), ASCM, fun((ASCM) -> binary()), fun((binary()) -> {ok, ASCM} | {error, nil}), flow_storage(ASCO), gleam@option:option(fun((telega@bot:context(ASCN, ASCO), flow_instance()) -> {ok, telega@bot:context(ASCN, ASCO)} | {error, ASCO})), gleam@option:option(fun((telega@bot:context(ASCN, ASCO), flow_instance(), gleam@option:option(ASCO)) -> {ok, telega@bot:context(ASCN, ASCO)} | {error, ASCO})), list(fun((telega@bot:context(ASCN, ASCO), flow_instance(), fun(() -> {ok, {telega@bot:context(ASCN, ASCO), flow_action(ASCM), flow_instance()}} | {error, ASCO})) -> {ok, {telega@bot:context(ASCN, ASCO), flow_action(ASCM), flow_instance()}} | {error, ASCO})), list(conditional_transition(ASCM)), list(parallel_config(ASCM)), list(subflow_config(ASCM, ASCN, ASCO))}. -opaque flow_registry(ASCP, ASCQ) :: {flow_registry, list({flow_trigger(), flow(gleam@dynamic:dynamic_(), ASCP, ASCQ), gleam@dict:dict(binary(), binary())}), gleam@dict:dict(binary(), flow(gleam@dynamic:dynamic_(), ASCP, ASCQ))}. -type step_config(ASCR, ASCS, ASCT) :: {step_config, fun((telega@bot:context(ASCS, ASCT), flow_instance()) -> {ok, {telega@bot:context(ASCS, ASCT), flow_action(ASCR), flow_instance()}} | {error, ASCT}), list(fun((telega@bot:context(ASCS, ASCT), flow_instance(), fun(() -> {ok, {telega@bot:context(ASCS, ASCT), flow_action(ASCR), flow_instance()}} | {error, ASCT})) -> {ok, {telega@bot:context(ASCS, ASCT), flow_action(ASCR), flow_instance()}} | {error, ASCT}))}. -type conditional_transition(ASCU) :: {conditional_transition, binary(), list({fun((flow_instance()) -> boolean()), ASCU}), ASCU}. -type parallel_config(ASCV) :: {parallel_config, binary(), list(ASCV), ASCV}. -type subflow_config(ASCW, ASCX, ASCY) :: {subflow_config, binary(), flow(gleam@dynamic:dynamic_(), ASCX, ASCY), ASCW, fun((flow_instance()) -> gleam@dict:dict(binary(), binary())), fun((gleam@dict:dict(binary(), binary()), flow_instance()) -> flow_instance())}. -type flow_action(ASCZ) :: {next, ASCZ} | {next_string, binary()} | back | {complete, gleam@dict:dict(binary(), binary())} | cancel | {wait, binary()} | {wait_callback, binary()} | {go_to, ASCZ} | {exit, gleam@option:option(gleam@dict:dict(binary(), binary()))} | {return_from_subflow, gleam@dict:dict(binary(), binary())} | {start_parallel, list(ASCZ), ASCZ} | {complete_parallel_step, ASCZ, 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(ASEB), fun((ASED) -> binary()), fun((binary()) -> {ok, ASED} | {error, nil}) ) -> flow_builder(ASED, any(), ASEB). 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(ASES, ASET, ASEU), ASES, fun((telega@bot:context(ASET, ASEU), flow_instance()) -> {ok, {telega@bot:context(ASET, ASEU), flow_action(ASES), flow_instance()}} | {error, ASEU}) ) -> flow_builder(ASES, ASET, ASEU). 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(ASFE, ASFF, ASFG), ASFE, list(fun((telega@bot:context(ASFF, ASFG), flow_instance(), fun(() -> {ok, {telega@bot:context(ASFF, ASFG), flow_action(ASFE), flow_instance()}} | {error, ASFG})) -> {ok, {telega@bot:context(ASFF, ASFG), flow_action(ASFE), flow_instance()}} | {error, ASFG})), fun((telega@bot:context(ASFF, ASFG), flow_instance()) -> {ok, {telega@bot:context(ASFF, ASFG), flow_action(ASFE), flow_instance()}} | {error, ASFG}) ) -> flow_builder(ASFE, ASFF, ASFG). 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(ASFU, ASFV, ASFW), fun((telega@bot:context(ASFV, ASFW), flow_instance(), fun(() -> {ok, {telega@bot:context(ASFV, ASFW), flow_action(ASFU), flow_instance()}} | {error, ASFW})) -> {ok, {telega@bot:context(ASFV, ASFW), flow_action(ASFU), flow_instance()}} | {error, ASFW}) ) -> flow_builder(ASFU, ASFV, ASFW). 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(ASGG, ASGH, ASGI), ASGG, fun((flow_instance()) -> boolean()), ASGG, ASGG ) -> flow_builder(ASGG, ASGH, ASGI). 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(ASGP, ASGQ, ASGR), ASGP, list({fun((flow_instance()) -> boolean()), ASGP}), ASGP ) -> flow_builder(ASGP, ASGQ, ASGR). 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(ASHJ, ASHK, ASHL), ASHJ, list(ASHJ), ASHJ) -> flow_builder(ASHJ, ASHK, ASHL). 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(ASGZ, ASHA, ASHB), ASGZ, list(ASGZ), ASGZ) -> flow_builder(ASGZ, ASHA, ASHB). 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(ASHT, ASHU, ASHV), ASHT, flow(gleam@dynamic:dynamic_(), ASHU, ASHV), ASHT, fun((flow_instance()) -> gleam@dict:dict(binary(), binary())), fun((gleam@dict:dict(binary(), binary()), flow_instance()) -> flow_instance()) ) -> flow_builder(ASHT, ASHU, ASHV). 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(ASIJ, ASIK, ASIL), fun((telega@bot:context(ASIK, ASIL), flow_instance()) -> {ok, telega@bot:context(ASIK, ASIL)} | {error, ASIL}) ) -> flow_builder(ASIJ, ASIK, ASIL). 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(ASIY, ASIZ, ASJA), fun((telega@bot:context(ASIZ, ASJA), flow_instance(), gleam@option:option(ASJA)) -> {ok, telega@bot:context(ASIZ, ASJA)} | {error, ASJA}) ) -> flow_builder(ASIY, ASIZ, ASJA). 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(ASJO, ASJP, ASJQ), ASJO) -> flow(ASJO, ASJP, ASJQ). 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(ASJX, ASJY), flow_instance(), ASKB) -> {ok, {telega@bot:context(ASJX, ASJY), flow_action(ASKB), flow_instance()}} | {error, ASJY}. 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(ASKF, ASKG), flow_instance(), binary()) -> {ok, {telega@bot:context(ASKF, ASKG), flow_action(any()), flow_instance()}} | {error, ASKG}. 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(ASKN, ASKO), flow_instance(), ASKR) -> {ok, {telega@bot:context(ASKN, ASKO), flow_action(ASKR), flow_instance()}} | {error, ASKO}. 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(ASKV, ASKW), flow_instance()) -> {ok, {telega@bot:context(ASKV, ASKW), flow_action(any()), flow_instance()}} | {error, ASKW}. back(Ctx, Instance) -> {ok, {Ctx, back, Instance}}. -file("src/telega/flow.gleam", 540). ?DOC(" Complete the flow\n"). -spec complete(telega@bot:context(ASLD, ASLE), flow_instance()) -> {ok, {telega@bot:context(ASLD, ASLE), flow_action(any()), flow_instance()}} | {error, ASLE}. 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(ASLL, ASLM), flow_instance()) -> {ok, {telega@bot:context(ASLL, ASLM), flow_action(any()), flow_instance()}} | {error, ASLM}. cancel(Ctx, Instance) -> {ok, {Ctx, cancel, Instance}}. -file("src/telega/flow.gleam", 556). ?DOC(" Wait for user input\n"). -spec wait(telega@bot:context(ASLT, ASLU), flow_instance(), binary()) -> {ok, {telega@bot:context(ASLT, ASLU), flow_action(any()), flow_instance()}} | {error, ASLU}. 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(ASMB, ASMC), flow_instance(), binary()) -> {ok, {telega@bot:context(ASMB, ASMC), flow_action(any()), flow_instance()}} | {error, ASMC}. 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(ASMJ, ASMK), flow_instance(), gleam@option:option(gleam@dict:dict(binary(), binary())) ) -> {ok, {telega@bot:context(ASMJ, ASMK), flow_action(any()), flow_instance()}} | {error, ASMK}. 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(ASNX, any(), any()), flow_instance()) -> {ok, ASNX} | {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(ASOI, ASOJ), flow_instance(), ASOM, binary(), binary() ) -> {ok, {telega@bot:context(ASOI, ASOJ), flow_action(ASOM), flow_instance()}} | {error, ASOJ}. 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(ASOQ), binary()) -> {ok, gleam@option:option(flow_instance())} | {error, ASOQ}. 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(), ASPV, ASPW), telega@bot:context(ASPV, ASPW), flow_instance(), gleam@option:option(ASPW) ) -> {ok, telega@bot:context(ASPV, ASPW)} | {error, ASPW}. 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", 1123). ?DOC(" Helper to create a string_to_step function for a list of steps\n"). -spec create_string_to_step(list({binary(), ASQJ})) -> fun((binary()) -> {ok, ASQJ} | {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(ASEK), list({binary(), ASEM}) ) -> flow_builder(ASEM, any(), ASEK). 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, [], [], [], []}. -file("src/telega/flow.gleam", 1131). ?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", 1136). ?DOC(" Create a text input step\n"). -spec text_step(binary(), binary(), ASQN) -> fun((telega@bot:context(ASQO, ASQP), flow_instance()) -> {ok, {telega@bot:context(ASQO, ASQP), flow_action(ASQN), flow_instance()}} | {error, ASQP}). 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", 1164). ?DOC(" Create a message display step\n"). -spec message_step( fun((flow_instance()) -> binary()), gleam@option:option(ASQT) ) -> fun((telega@bot:context(ASQV, ASQW), flow_instance()) -> {ok, {telega@bot:context(ASQV, ASQW), flow_action(ASQT), flow_instance()}} | {error, ASQW}). 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", 1270). ?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", 1357). -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", 1362). ?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", 1376). ?DOC(" Add a flow to the registry with a trigger and initial data\n"). -spec register_with_data( flow_registry(ASWG, ASWH), flow_trigger(), flow(any(), ASWG, ASWH), gleam@dict:dict(binary(), binary()) ) -> flow_registry(ASWG, ASWH). 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", 1367). ?DOC(" Add a flow to the registry with a trigger\n"). -spec register( flow_registry(ASVW, ASVX), flow_trigger(), flow(any(), ASVW, ASVX) ) -> flow_registry(ASVW, ASVX). register(Registry, Trigger, Flow) -> register_with_data(Registry, Trigger, Flow, maps:new()). -file("src/telega/flow.gleam", 1390). ?DOC(" Register a flow without a trigger (for calling from handlers)\n"). -spec register_callable(flow_registry(ASWS, ASWT), flow(any(), ASWS, ASWT)) -> flow_registry(ASWS, ASWT). 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", 1549). ?DOC(" Apply middleware chain to handler\n"). -spec apply_middlewares( telega@bot:context(ASYP, ASYQ), flow_instance(), fun(() -> {ok, {telega@bot:context(ASYP, ASYQ), flow_action(ASYT), flow_instance()}} | {error, ASYQ}), list(fun((telega@bot:context(ASYP, ASYQ), flow_instance(), fun(() -> {ok, {telega@bot:context(ASYP, ASYQ), flow_action(ASYT), flow_instance()}} | {error, ASYQ})) -> {ok, {telega@bot:context(ASYP, ASYQ), flow_action(ASYT), flow_instance()}} | {error, ASYQ})) ) -> {ok, {telega@bot:context(ASYP, ASYQ), flow_action(ASYT), flow_instance()}} | {error, ASYQ}. 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", 1566). ?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", 1598). ?DOC(" Check if current step triggers parallel execution\n"). -spec check_parallel_trigger(flow(ASZL, any(), any()), flow_instance()) -> gleam@option:option(parallel_config(ASZL)). 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", 1650). ?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", 1777). -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", 1787). -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", 1833). -spec validation_middleware( fun((flow_instance()) -> {ok, nil} | {error, binary()}) ) -> fun((telega@bot:context(ATCP, ATCQ), flow_instance(), fun(() -> {ok, {telega@bot:context(ATCP, ATCQ), flow_action(ATCO), flow_instance()}} | {error, ATCQ})) -> {ok, {telega@bot:context(ATCP, ATCQ), flow_action(ATCO), flow_instance()}} | {error, ATCQ}). 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(ASPH, ASPI, ASPJ), telega@bot:context(ASPI, ASPJ), flow_action(ASPH), flow_instance() ) -> {ok, telega@bot:context(ASPI, ASPJ)} | {error, ASPJ}. 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(), ASOW, ASOX), telega@bot:context(ASOW, ASOX), flow_instance() ) -> {ok, telega@bot:context(ASOW, ASOX)} | {error, ASOX}. 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(), ASMV, ASMW), telega@bot:context(ASMV, ASMW), integer(), integer(), gleam@dict:dict(binary(), binary()) ) -> {ok, telega@bot:context(ASMV, ASMW)} | {error, ASMW}. 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(), ASNJ, ASNK), telega@bot:context(ASNJ, ASNK), binary(), gleam@option:option(gleam@dict:dict(binary(), binary())) ) -> {ok, telega@bot:context(ASNJ, ASNK)} | {error, ASNK}. 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", 1200). ?DOC(" Create a text handler for resuming flows\n"). -spec create_text_handler(flow(any(), ASSA, ASSB)) -> fun((telega@bot:context(ASSA, ASSB), telega@update:update()) -> {ok, telega@bot:context(ASSA, ASSB)} | {error, ASSB}). 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", 1275). ?DOC(" Start a flow with optional initial data\n"). -spec start( flow(any(), ASTC, ASTD), gleam@dict:dict(binary(), binary()), telega@bot:context(ASTC, ASTD) ) -> {ok, telega@bot:context(ASTC, ASTD)} | {error, ASTD}. 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", 1257). ?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(ASSL, ASSM), flow_registry(ASSL, ASSM), binary(), gleam@dict:dict(binary(), binary()) ) -> {ok, telega@bot:context(ASSL, ASSM)} | {error, ASSM}. 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", 1285). ?DOC(" Create a router handler that starts a flow\n"). -spec to_handler(flow(any(), ASTQ, ASTR)) -> fun((telega@bot:context(ASTQ, ASTR), telega@update:command()) -> {ok, telega@bot:context(ASTQ, ASTR)} | {error, ASTR}). to_handler(Flow) -> fun(Ctx, _) -> start(Flow, maps:new(), Ctx) end. -file("src/telega/flow.gleam", 1293). ?DOC(" Create a router handler that starts a flow with initial data (internal)\n"). -spec to_handler_with_data( flow(any(), ASUC, ASUD), gleam@dict:dict(binary(), binary()) ) -> fun((telega@bot:context(ASUC, ASUD), telega@update:command()) -> {ok, telega@bot:context(ASUC, ASUD)} | {error, ASUD}). to_handler_with_data(Flow, Initial_data) -> fun(Ctx, _) -> start(Flow, Initial_data, Ctx) end. -file("src/telega/flow.gleam", 1302). ?DOC(" Create a router handler for resuming flows from callback queries (internal)\n"). -spec resume_handler(flow(any(), ASUQ, ASUR)) -> fun((telega@bot:context(ASUQ, ASUR), telega@update:update()) -> {ok, telega@bot:context(ASUQ, ASUR)} | {error, ASUR}). 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", 1183). ?DOC(" Create a router handler for resuming flows from callback queries\n"). -spec create_resume_handler(flow(any(), ASRB, ASRC)) -> fun((telega@bot:context(ASRB, ASRC), telega@update:update()) -> {ok, telega@bot:context(ASRB, ASRC)} | {error, ASRC}). create_resume_handler(Flow) -> resume_handler(Flow). -file("src/telega/flow.gleam", 1322). ?DOC(" Create a router handler for resuming flows from callback queries with keyboard parsing (internal)\n"). -spec resume_handler_with_keyboard( flow(any(), ASVC, ASVD), telega@keyboard:keyboard_callback_data(binary()) ) -> fun((telega@bot:context(ASVC, ASVD), telega@update:update()) -> {ok, telega@bot:context(ASVC, ASVD)} | {error, ASVD}). 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", 1191). ?DOC(" Create a router handler for resuming flows from callback queries with keyboard parsing\n"). -spec create_resume_handler_with_keyboard( flow(any(), ASRN, ASRO), telega@keyboard:keyboard_callback_data(binary()) ) -> fun((telega@bot:context(ASRN, ASRO), telega@update:update()) -> {ok, telega@bot:context(ASRN, ASRO)} | {error, ASRO}). create_resume_handler_with_keyboard(Flow, Callback_data) -> resume_handler_with_keyboard(Flow, Callback_data). -file("src/telega/flow.gleam", 1426). ?DOC(" Add a flow route to router\n"). -spec add_flow_route( telega@router:router(ASXK, ASXL), flow_trigger(), flow(gleam@dynamic:dynamic_(), ASXK, ASXL), gleam@dict:dict(binary(), binary()) ) -> telega@router:router(ASXK, ASXL). 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", 1469). ?DOC(" Auto-resume handler for text messages\n"). -spec auto_resume_handler(flow_registry(ASXV, ASXW)) -> fun((telega@bot:context(ASXV, ASXW), binary()) -> {ok, telega@bot:context(ASXV, ASXW)} | {error, ASXW}). 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", 1510). ?DOC(" Auto-resume handler for callback queries (internal)\n"). -spec auto_resume_callback_handler(flow_registry(ASYF, ASYG)) -> fun((telega@bot:context(ASYF, ASYG), binary(), binary()) -> {ok, telega@bot:context(ASYF, ASYG)} | {error, ASYG}). 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", 1402). ?DOC(" Apply all registered flows to a router\n"). -spec apply_to_router( telega@router:router(ASXC, ASXD), flow_registry(ASXC, ASXD) ) -> telega@router:router(ASXC, ASXD). 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", 1609). ?DOC(" Start parallel execution\n"). -spec start_parallel_execution( flow(ASZT, ASZU, ASZV), telega@bot:context(ASZU, ASZV), flow_instance(), parallel_config(ASZT) ) -> {ok, telega@bot:context(ASZU, ASZV)} | {error, ASZV}. 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", 1682). ?DOC(" Compose flows with conditional selection\n"). -spec compose_conditional( binary(), fun((flow_instance()) -> binary()), gleam@dict:dict(binary(), flow(gleam@dynamic:dynamic_(), ATAY, ATAZ)), flow_storage(ATAZ) ) -> flow(composed_step(), ATAY, ATAZ). 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", 1712). ?DOC(" Compose flows for parallel execution\n"). -spec compose_parallel( binary(), list(flow(gleam@dynamic:dynamic_(), ATBJ, ATBK)), fun((list(gleam@dict:dict(binary(), binary()))) -> gleam@dict:dict(binary(), binary())), flow_storage(ATBK) ) -> flow(composed_step(), ATBJ, ATBK). 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", 1816). -spec create_composed_handler( flow(gleam@dynamic:dynamic_(), ATCA, ATCB), list(flow(gleam@dynamic:dynamic_(), ATCA, ATCB)), integer() ) -> fun((telega@bot:context(ATCA, ATCB), flow_instance()) -> {ok, {telega@bot:context(ATCA, ATCB), flow_action(composed_step()), flow_instance()}} | {error, ATCB}). 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", 1662). ?DOC(" Compose flows sequentially\n"). -spec compose_sequential( binary(), list(flow(gleam@dynamic:dynamic_(), ATAO, ATAP)), flow_storage(ATAP) ) -> flow(composed_step(), ATAO, ATAP). 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}).