Current section
Files
Jump to
Current section
Files
src/telega@flow.erl
-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,
<<<<Token/binary, "_"/utf8>>/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) ->
<<<<<<<<Flow_name/binary, "_"/utf8>>/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,
<<<<Step_name/binary, "."/utf8>>/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}).