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(ASXL) :: {flow_storage,
fun((flow_instance()) -> {ok, nil} | {error, ASXL}),
fun((binary()) -> {ok, gleam@option:option(flow_instance())} |
{error, ASXL}),
fun((binary()) -> {ok, nil} | {error, ASXL}),
fun((integer(), integer()) -> {ok, list(flow_instance())} |
{error, ASXL})}.
-opaque flow_builder(ASXM, ASXN, ASXO) :: {flow_builder,
binary(),
gleam@dict:dict(binary(), step_config(ASXM, ASXN, ASXO)),
fun((ASXM) -> binary()),
fun((binary()) -> {ok, ASXM} | {error, nil}),
flow_storage(ASXO),
gleam@option:option(fun((telega@bot:context(ASXN, ASXO), flow_instance()) -> {ok,
telega@bot:context(ASXN, ASXO)} |
{error, ASXO})),
gleam@option:option(fun((telega@bot:context(ASXN, ASXO), flow_instance(), gleam@option:option(ASXO)) -> {ok,
telega@bot:context(ASXN, ASXO)} |
{error, ASXO})),
list(fun((telega@bot:context(ASXN, ASXO), flow_instance(), fun(() -> {ok,
{telega@bot:context(ASXN, ASXO),
flow_action(ASXM),
flow_instance()}} |
{error, ASXO})) -> {ok,
{telega@bot:context(ASXN, ASXO),
flow_action(ASXM),
flow_instance()}} |
{error, ASXO})),
list(conditional_transition(ASXM)),
list(parallel_config(ASXM)),
list(subflow_config(ASXM, ASXN, ASXO))}.
-opaque flow(ASXP, ASXQ, ASXR) :: {flow,
binary(),
gleam@dict:dict(binary(), step_config(ASXP, ASXQ, ASXR)),
ASXP,
fun((ASXP) -> binary()),
fun((binary()) -> {ok, ASXP} | {error, nil}),
flow_storage(ASXR),
gleam@option:option(fun((telega@bot:context(ASXQ, ASXR), flow_instance()) -> {ok,
telega@bot:context(ASXQ, ASXR)} |
{error, ASXR})),
gleam@option:option(fun((telega@bot:context(ASXQ, ASXR), flow_instance(), gleam@option:option(ASXR)) -> {ok,
telega@bot:context(ASXQ, ASXR)} |
{error, ASXR})),
list(fun((telega@bot:context(ASXQ, ASXR), flow_instance(), fun(() -> {ok,
{telega@bot:context(ASXQ, ASXR),
flow_action(ASXP),
flow_instance()}} |
{error, ASXR})) -> {ok,
{telega@bot:context(ASXQ, ASXR),
flow_action(ASXP),
flow_instance()}} |
{error, ASXR})),
list(conditional_transition(ASXP)),
list(parallel_config(ASXP)),
list(subflow_config(ASXP, ASXQ, ASXR))}.
-opaque flow_registry(ASXS, ASXT) :: {flow_registry,
list({flow_trigger(),
flow(gleam@dynamic:dynamic_(), ASXS, ASXT),
gleam@dict:dict(binary(), binary())}),
gleam@dict:dict(binary(), flow(gleam@dynamic:dynamic_(), ASXS, ASXT))}.
-type step_config(ASXU, ASXV, ASXW) :: {step_config,
fun((telega@bot:context(ASXV, ASXW), flow_instance()) -> {ok,
{telega@bot:context(ASXV, ASXW),
flow_action(ASXU),
flow_instance()}} |
{error, ASXW}),
list(fun((telega@bot:context(ASXV, ASXW), flow_instance(), fun(() -> {ok,
{telega@bot:context(ASXV, ASXW),
flow_action(ASXU),
flow_instance()}} |
{error, ASXW})) -> {ok,
{telega@bot:context(ASXV, ASXW),
flow_action(ASXU),
flow_instance()}} |
{error, ASXW}))}.
-type conditional_transition(ASXX) :: {conditional_transition,
binary(),
list({fun((flow_instance()) -> boolean()), ASXX}),
ASXX}.
-type parallel_config(ASXY) :: {parallel_config, binary(), list(ASXY), ASXY}.
-type subflow_config(ASXZ, ASYA, ASYB) :: {subflow_config,
binary(),
flow(gleam@dynamic:dynamic_(), ASYA, ASYB),
ASXZ,
fun((flow_instance()) -> gleam@dict:dict(binary(), binary())),
fun((gleam@dict:dict(binary(), binary()), flow_instance()) -> flow_instance())}.
-type flow_action(ASYC) :: {next, ASYC} |
{next_string, binary()} |
back |
{complete, gleam@dict:dict(binary(), binary())} |
cancel |
{wait, binary()} |
{wait_callback, binary()} |
{go_to, ASYC} |
{exit, gleam@option:option(gleam@dict:dict(binary(), binary()))} |
{return_from_subflow, gleam@dict:dict(binary(), binary())} |
{start_parallel, list(ASYC), ASYC} |
{complete_parallel_step, ASYC, 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(ASZE),
fun((ASZG) -> binary()),
fun((binary()) -> {ok, ASZG} | {error, nil})
) -> flow_builder(ASZG, any(), ASZE).
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(ASZV, ASZW, ASZX),
ASZV,
fun((telega@bot:context(ASZW, ASZX), flow_instance()) -> {ok,
{telega@bot:context(ASZW, ASZX), flow_action(ASZV), flow_instance()}} |
{error, ASZX})
) -> flow_builder(ASZV, ASZW, ASZX).
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(ATAH, ATAI, ATAJ),
ATAH,
list(fun((telega@bot:context(ATAI, ATAJ), flow_instance(), fun(() -> {ok,
{telega@bot:context(ATAI, ATAJ), flow_action(ATAH), flow_instance()}} |
{error, ATAJ})) -> {ok,
{telega@bot:context(ATAI, ATAJ), flow_action(ATAH), flow_instance()}} |
{error, ATAJ})),
fun((telega@bot:context(ATAI, ATAJ), flow_instance()) -> {ok,
{telega@bot:context(ATAI, ATAJ), flow_action(ATAH), flow_instance()}} |
{error, ATAJ})
) -> flow_builder(ATAH, ATAI, ATAJ).
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(ATAX, ATAY, ATAZ),
fun((telega@bot:context(ATAY, ATAZ), flow_instance(), fun(() -> {ok,
{telega@bot:context(ATAY, ATAZ), flow_action(ATAX), flow_instance()}} |
{error, ATAZ})) -> {ok,
{telega@bot:context(ATAY, ATAZ), flow_action(ATAX), flow_instance()}} |
{error, ATAZ})
) -> flow_builder(ATAX, ATAY, ATAZ).
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(ATBJ, ATBK, ATBL),
ATBJ,
fun((flow_instance()) -> boolean()),
ATBJ,
ATBJ
) -> flow_builder(ATBJ, ATBK, ATBL).
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(ATBS, ATBT, ATBU),
ATBS,
list({fun((flow_instance()) -> boolean()), ATBS}),
ATBS
) -> flow_builder(ATBS, ATBT, ATBU).
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(ATCM, ATCN, ATCO), ATCM, list(ATCM), ATCM) -> flow_builder(ATCM, ATCN, ATCO).
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(ATCC, ATCD, ATCE), ATCC, list(ATCC), ATCC) -> flow_builder(ATCC, ATCD, ATCE).
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(ATCW, ATCX, ATCY),
ATCW,
flow(gleam@dynamic:dynamic_(), ATCX, ATCY),
ATCW,
fun((flow_instance()) -> gleam@dict:dict(binary(), binary())),
fun((gleam@dict:dict(binary(), binary()), flow_instance()) -> flow_instance())
) -> flow_builder(ATCW, ATCX, ATCY).
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(ATDM, ATDN, ATDO),
fun((telega@bot:context(ATDN, ATDO), flow_instance()) -> {ok,
telega@bot:context(ATDN, ATDO)} |
{error, ATDO})
) -> flow_builder(ATDM, ATDN, ATDO).
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(ATEB, ATEC, ATED),
fun((telega@bot:context(ATEC, ATED), flow_instance(), gleam@option:option(ATED)) -> {ok,
telega@bot:context(ATEC, ATED)} |
{error, ATED})
) -> flow_builder(ATEB, ATEC, ATED).
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(ATER, ATES, ATET), ATER) -> flow(ATER, ATES, ATET).
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(ATFA, ATFB), flow_instance(), ATFE) -> {ok,
{telega@bot:context(ATFA, ATFB), flow_action(ATFE), flow_instance()}} |
{error, ATFB}.
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(ATFI, ATFJ), flow_instance(), binary()) -> {ok,
{telega@bot:context(ATFI, ATFJ), flow_action(any()), flow_instance()}} |
{error, ATFJ}.
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(ATFQ, ATFR), flow_instance(), ATFU) -> {ok,
{telega@bot:context(ATFQ, ATFR), flow_action(ATFU), flow_instance()}} |
{error, ATFR}.
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(ATFY, ATFZ), flow_instance()) -> {ok,
{telega@bot:context(ATFY, ATFZ), flow_action(any()), flow_instance()}} |
{error, ATFZ}.
back(Ctx, Instance) ->
{ok, {Ctx, back, Instance}}.
-file("src/telega/flow.gleam", 540).
?DOC(" Complete the flow\n").
-spec complete(telega@bot:context(ATGG, ATGH), flow_instance()) -> {ok,
{telega@bot:context(ATGG, ATGH), flow_action(any()), flow_instance()}} |
{error, ATGH}.
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(ATGO, ATGP), flow_instance()) -> {ok,
{telega@bot:context(ATGO, ATGP), flow_action(any()), flow_instance()}} |
{error, ATGP}.
cancel(Ctx, Instance) ->
{ok, {Ctx, cancel, Instance}}.
-file("src/telega/flow.gleam", 556).
?DOC(" Wait for user input\n").
-spec wait(telega@bot:context(ATGW, ATGX), flow_instance(), binary()) -> {ok,
{telega@bot:context(ATGW, ATGX), flow_action(any()), flow_instance()}} |
{error, ATGX}.
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(ATHE, ATHF), flow_instance(), binary()) -> {ok,
{telega@bot:context(ATHE, ATHF), flow_action(any()), flow_instance()}} |
{error, ATHF}.
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(ATHM, ATHN),
flow_instance(),
gleam@option:option(gleam@dict:dict(binary(), binary()))
) -> {ok, {telega@bot:context(ATHM, ATHN), flow_action(any()), flow_instance()}} |
{error, ATHN}.
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(ATJA, any(), any()), flow_instance()) -> {ok, ATJA} |
{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(ATJL, ATJM),
flow_instance(),
ATJP,
binary(),
binary()
) -> {ok, {telega@bot:context(ATJL, ATJM), flow_action(ATJP), flow_instance()}} |
{error, ATJM}.
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(ATJT), binary()) -> {ok,
gleam@option:option(flow_instance())} |
{error, ATJT}.
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(), ATKY, ATKZ),
telega@bot:context(ATKY, ATKZ),
flow_instance(),
gleam@option:option(ATKZ)
) -> {ok, telega@bot:context(ATKY, ATKZ)} | {error, ATKZ}.
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", 1123).
?DOC(" Helper to create a string_to_step function for a list of steps\n").
-spec create_string_to_step(list({binary(), ATLM})) -> fun((binary()) -> {ok,
ATLM} |
{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(ASZN),
list({binary(), ASZP})
) -> flow_builder(ASZP, any(), ASZN).
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(), ATLQ) -> fun((telega@bot:context(ATLR, ATLS), flow_instance()) -> {ok,
{telega@bot:context(ATLR, ATLS), flow_action(ATLQ), flow_instance()}} |
{error, ATLS}).
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(ATLW)
) -> fun((telega@bot:context(ATLY, ATLZ), flow_instance()) -> {ok,
{telega@bot:context(ATLY, ATLZ), flow_action(ATLW), flow_instance()}} |
{error, ATLZ}).
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(ATRJ, ATRK),
flow_trigger(),
flow(any(), ATRJ, ATRK),
gleam@dict:dict(binary(), binary())
) -> flow_registry(ATRJ, ATRK).
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(ATQZ, ATRA),
flow_trigger(),
flow(any(), ATQZ, ATRA)
) -> flow_registry(ATQZ, ATRA).
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(ATRV, ATRW), flow(any(), ATRV, ATRW)) -> flow_registry(ATRV, ATRW).
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(ATTS, ATTT),
flow_instance(),
fun(() -> {ok,
{telega@bot:context(ATTS, ATTT), flow_action(ATTW), flow_instance()}} |
{error, ATTT}),
list(fun((telega@bot:context(ATTS, ATTT), flow_instance(), fun(() -> {ok,
{telega@bot:context(ATTS, ATTT), flow_action(ATTW), flow_instance()}} |
{error, ATTT})) -> {ok,
{telega@bot:context(ATTS, ATTT), flow_action(ATTW), flow_instance()}} |
{error, ATTT}))
) -> {ok, {telega@bot:context(ATTS, ATTT), flow_action(ATTW), flow_instance()}} |
{error, ATTT}.
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(ATUO, any(), any()), flow_instance()) -> gleam@option:option(parallel_config(ATUO)).
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,
<<<<Step_name/binary, "."/utf8>>/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(ATXS, ATXT), flow_instance(), fun(() -> {ok,
{telega@bot:context(ATXS, ATXT), flow_action(ATXR), flow_instance()}} |
{error, ATXT})) -> {ok,
{telega@bot:context(ATXS, ATXT), flow_action(ATXR), flow_instance()}} |
{error, ATXT}).
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(ATKK, ATKL, ATKM),
telega@bot:context(ATKL, ATKM),
flow_action(ATKK),
flow_instance()
) -> {ok, telega@bot:context(ATKL, ATKM)} | {error, ATKM}.
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(), ATJZ, ATKA),
telega@bot:context(ATJZ, ATKA),
flow_instance()
) -> {ok, telega@bot:context(ATJZ, ATKA)} | {error, ATKA}.
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(), ATHY, ATHZ),
telega@bot:context(ATHY, ATHZ),
integer(),
integer(),
gleam@dict:dict(binary(), binary())
) -> {ok, telega@bot:context(ATHY, ATHZ)} | {error, ATHZ}.
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(), ATIM, ATIN),
telega@bot:context(ATIM, ATIN),
binary(),
gleam@option:option(gleam@dict:dict(binary(), binary()))
) -> {ok, telega@bot:context(ATIM, ATIN)} | {error, ATIN}.
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(), ATND, ATNE)) -> fun((telega@bot:context(ATND, ATNE), telega@update:update()) -> {ok,
telega@bot:context(ATND, ATNE)} |
{error, ATNE}).
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(), ATOF, ATOG),
gleam@dict:dict(binary(), binary()),
telega@bot:context(ATOF, ATOG)
) -> {ok, telega@bot:context(ATOF, ATOG)} | {error, ATOG}.
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(ATNO, ATNP),
flow_registry(ATNO, ATNP),
binary(),
gleam@dict:dict(binary(), binary())
) -> {ok, telega@bot:context(ATNO, ATNP)} | {error, ATNP}.
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(), ATOT, ATOU)) -> fun((telega@bot:context(ATOT, ATOU), telega@update:command()) -> {ok,
telega@bot:context(ATOT, ATOU)} |
{error, ATOU}).
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(), ATPF, ATPG),
gleam@dict:dict(binary(), binary())
) -> fun((telega@bot:context(ATPF, ATPG), telega@update:command()) -> {ok,
telega@bot:context(ATPF, ATPG)} |
{error, ATPG}).
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(), ATPT, ATPU)) -> fun((telega@bot:context(ATPT, ATPU), telega@update:update()) -> {ok,
telega@bot:context(ATPT, ATPU)} |
{error, ATPU}).
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(), ATME, ATMF)) -> fun((telega@bot:context(ATME, ATMF), telega@update:update()) -> {ok,
telega@bot:context(ATME, ATMF)} |
{error, ATMF}).
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(), ATQF, ATQG),
telega@keyboard:keyboard_callback_data(binary())
) -> fun((telega@bot:context(ATQF, ATQG), telega@update:update()) -> {ok,
telega@bot:context(ATQF, ATQG)} |
{error, ATQG}).
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(), ATMQ, ATMR),
telega@keyboard:keyboard_callback_data(binary())
) -> fun((telega@bot:context(ATMQ, ATMR), telega@update:update()) -> {ok,
telega@bot:context(ATMQ, ATMR)} |
{error, ATMR}).
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(ATSN, ATSO),
flow_trigger(),
flow(gleam@dynamic:dynamic_(), ATSN, ATSO),
gleam@dict:dict(binary(), binary())
) -> telega@router:router(ATSN, ATSO).
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(ATSY, ATSZ)) -> fun((telega@bot:context(ATSY, ATSZ), binary()) -> {ok,
telega@bot:context(ATSY, ATSZ)} |
{error, ATSZ}).
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(ATTI, ATTJ)) -> fun((telega@bot:context(ATTI, ATTJ), binary(), binary()) -> {ok,
telega@bot:context(ATTI, ATTJ)} |
{error, ATTJ}).
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(ATSF, ATSG),
flow_registry(ATSF, ATSG)
) -> telega@router:router(ATSF, ATSG).
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(ATUW, ATUX, ATUY),
telega@bot:context(ATUX, ATUY),
flow_instance(),
parallel_config(ATUW)
) -> {ok, telega@bot:context(ATUX, ATUY)} | {error, ATUY}.
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_(), ATWB, ATWC)),
flow_storage(ATWC)
) -> flow(composed_step(), ATWB, ATWC).
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_(), ATWM, ATWN)),
fun((list(gleam@dict:dict(binary(), binary()))) -> gleam@dict:dict(binary(), binary())),
flow_storage(ATWN)
) -> flow(composed_step(), ATWM, ATWN).
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_(), ATXD, ATXE),
list(flow(gleam@dynamic:dynamic_(), ATXD, ATXE)),
integer()
) -> fun((telega@bot:context(ATXD, ATXE), flow_instance()) -> {ok,
{telega@bot:context(ATXD, ATXE),
flow_action(composed_step()),
flow_instance()}} |
{error, ATXE}).
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_(), ATVR, ATVS)),
flow_storage(ATVS)
) -> flow(composed_step(), ATVR, ATVS).
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}).