-module(telega@flow@instance). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/telega/flow/instance.gleam"). -export([new_instance/5, new_instance_with_data/6, instance_id/1, instance_flow_name/1, instance_user_id/1, instance_chat_id/1, instance_current_step/1, instance_wait_token/1, instance_created_at/1, instance_updated_at/1, store_step_data/3, get_step_data/2, clear_step_data/1, clear_step_data_key/2, store_data/3, get_data/2, get_wait_result/1, clear_wait_result/1, instance_to_row/1, instance_from_row/1, to_json/1, instance_decoder/0, to_json_string/1, from_json_string/1, is_expired/2, next_with_data/5, get_current_step/2, encode_text_wait_result/1, encode_callback_wait_result/1]). -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(" Instance CRUD, accessors, factories, WaitResult, and serialization.\n"). -file("src/telega/flow/instance.gleam", 22). ?DOC(" Create a new FlowInstance with minimal required fields\n"). -spec new_instance(binary(), binary(), integer(), integer(), binary()) -> telega@flow@types:flow_instance(). new_instance(Id, Flow_name, User_id, Chat_id, Current_step) -> {flow_instance, Id, Flow_name, User_id, Chat_id, {flow_state, Current_step, maps:new(), [Current_step], [], none}, maps:new(), none, none, telega@internal@utils:current_time_ms(), telega@internal@utils:current_time_ms()}. -file("src/telega/flow/instance.gleam", 50). ?DOC(" Create a new FlowInstance with initial data\n"). -spec new_instance_with_data( binary(), binary(), integer(), integer(), binary(), gleam@dict:dict(binary(), binary()) ) -> telega@flow@types:flow_instance(). new_instance_with_data(Id, Flow_name, User_id, Chat_id, Current_step, Data) -> {flow_instance, Id, Flow_name, User_id, Chat_id, {flow_state, Current_step, Data, [Current_step], [], none}, maps:new(), none, none, telega@internal@utils:current_time_ms(), telega@internal@utils:current_time_ms()}. -file("src/telega/flow/instance.gleam", 79). ?DOC(" Get the instance ID\n"). -spec instance_id(telega@flow@types:flow_instance()) -> binary(). instance_id(Instance) -> erlang:element(2, Instance). -file("src/telega/flow/instance.gleam", 84). ?DOC(" Get the flow name\n"). -spec instance_flow_name(telega@flow@types:flow_instance()) -> binary(). instance_flow_name(Instance) -> erlang:element(3, Instance). -file("src/telega/flow/instance.gleam", 89). ?DOC(" Get the user ID\n"). -spec instance_user_id(telega@flow@types:flow_instance()) -> integer(). instance_user_id(Instance) -> erlang:element(4, Instance). -file("src/telega/flow/instance.gleam", 94). ?DOC(" Get the chat ID\n"). -spec instance_chat_id(telega@flow@types:flow_instance()) -> integer(). instance_chat_id(Instance) -> erlang:element(5, Instance). -file("src/telega/flow/instance.gleam", 99). ?DOC(" Get the current step name\n"). -spec instance_current_step(telega@flow@types:flow_instance()) -> binary(). instance_current_step(Instance) -> erlang:element(2, erlang:element(6, Instance)). -file("src/telega/flow/instance.gleam", 104). ?DOC(" Get the wait token\n"). -spec instance_wait_token(telega@flow@types:flow_instance()) -> gleam@option:option(binary()). instance_wait_token(Instance) -> erlang:element(8, Instance). -file("src/telega/flow/instance.gleam", 109). ?DOC(" Get the created_at timestamp\n"). -spec instance_created_at(telega@flow@types:flow_instance()) -> integer(). instance_created_at(Instance) -> erlang:element(10, Instance). -file("src/telega/flow/instance.gleam", 114). ?DOC(" Get the updated_at timestamp\n"). -spec instance_updated_at(telega@flow@types:flow_instance()) -> integer(). instance_updated_at(Instance) -> erlang:element(11, Instance). -file("src/telega/flow/instance.gleam", 119). ?DOC(" Store step data\n"). -spec store_step_data(telega@flow@types:flow_instance(), binary(), binary()) -> telega@flow@types:flow_instance(). store_step_data(Instance, Key, Value) -> {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), gleam@dict:insert(erlang:element(7, Instance), Key, Value), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance), erlang:element(11, Instance)}. -file("src/telega/flow/instance.gleam", 131). ?DOC(" Get step data\n"). -spec get_step_data(telega@flow@types:flow_instance(), binary()) -> gleam@option:option(binary()). get_step_data(Instance, Key) -> _pipe = gleam_stdlib:map_get(erlang:element(7, Instance), Key), gleam@option:from_result(_pipe). -file("src/telega/flow/instance.gleam", 140). ?DOC(" Clear all step data\n"). -spec clear_step_data(telega@flow@types:flow_instance()) -> telega@flow@types:flow_instance(). clear_step_data(Instance) -> {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), maps:new(), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance), erlang:element(11, Instance)}. -file("src/telega/flow/instance.gleam", 145). ?DOC(" Clear specific step data key\n"). -spec clear_step_data_key(telega@flow@types:flow_instance(), binary()) -> telega@flow@types:flow_instance(). clear_step_data_key(Instance, Key) -> {flow_instance, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(6, Instance), gleam@dict:delete(erlang:element(7, Instance), Key), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance), erlang:element(11, Instance)}. -file("src/telega/flow/instance.gleam", 153). ?DOC(" Store data in the flow instance\n"). -spec store_data(telega@flow@types:flow_instance(), binary(), binary()) -> telega@flow@types: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), erlang:element(11, Instance)}. -file("src/telega/flow/instance.gleam", 168). ?DOC(" Get data from the flow instance\n"). -spec get_data(telega@flow@types: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/instance.gleam", 466). -spec parse_command_result(binary()) -> telega@flow@types:wait_result(). parse_command_result(Raw) -> case gleam@string:split_once(Raw, <<":"/utf8>>) of {ok, {Cmd, Payload}} -> {command_input, Cmd, Payload}; {error, _} -> {command_input, Raw, <<""/utf8>>} end. -file("src/telega/flow/instance.gleam", 455). -spec parse_location_result(binary()) -> telega@flow@types:wait_result(). parse_location_result(Raw) -> case gleam@string:split(Raw, <<","/utf8>>) of [Lat_str, Lng_str] -> case {gleam_stdlib:parse_float(Lat_str), gleam_stdlib:parse_float(Lng_str)} of {{ok, Lat}, {ok, Lng}} -> {location_input, Lat, Lng}; {_, _} -> {data_callback, <<"location:"/utf8, Raw/binary>>} end; _ -> {data_callback, <<"location:"/utf8, Raw/binary>>} end. -file("src/telega/flow/instance.gleam", 439). -spec parse_wait_result(binary()) -> telega@flow@types:wait_result(). parse_wait_result(Raw) -> case Raw of <<"bool:true"/utf8>> -> {bool_callback, true}; <<"bool:false"/utf8>> -> {bool_callback, false}; <<"photo:"/utf8, Rest/binary>> -> {photo_input, gleam@string:split(Rest, <<","/utf8>>)}; <<"video:"/utf8, Rest@1/binary>> -> {video_input, Rest@1}; <<"voice:"/utf8, Rest@2/binary>> -> {voice_input, Rest@2}; <<"audio:"/utf8, Rest@3/binary>> -> {audio_input, Rest@3}; <<"location:"/utf8, Rest@4/binary>> -> parse_location_result(Rest@4); <<"command:"/utf8, Rest@5/binary>> -> parse_command_result(Rest@5); <<"text:"/utf8, Rest@6/binary>> -> {text_input, Rest@6}; <<"data:"/utf8, Rest@7/binary>> -> {data_callback, Rest@7}; Other -> {data_callback, Other} end. -file("src/telega/flow/instance.gleam", 180). ?DOC(" Get the result of waiting for user input or callback\n"). -spec get_wait_result(telega@flow@types:flow_instance()) -> telega@flow@types:wait_result(). get_wait_result(Instance) -> case get_step_data(Instance, <<"__wait_result"/utf8>>) of none -> pending; {some, Raw} -> parse_wait_result(Raw) end. -file("src/telega/flow/instance.gleam", 190). ?DOC(false). -spec clear_wait_result(telega@flow@types:flow_instance()) -> telega@flow@types:flow_instance(). clear_wait_result(Instance) -> clear_step_data_key(Instance, <<"__wait_result"/utf8>>). -file("src/telega/flow/instance.gleam", 195). ?DOC(" Convert a FlowInstance to a flat row for database storage\n"). -spec instance_to_row(telega@flow@types:flow_instance()) -> telega@flow@types:flow_instance_row(). instance_to_row(Instance) -> {flow_instance_row, erlang:element(2, Instance), erlang:element(3, Instance), erlang:element(4, Instance), erlang:element(5, Instance), erlang:element(2, erlang:element(6, Instance)), erlang:element(3, erlang:element(6, Instance)), erlang:element(7, Instance), erlang:element(8, Instance), erlang:element(9, Instance), erlang:element(10, Instance), erlang:element(11, Instance)}. -file("src/telega/flow/instance.gleam", 212). ?DOC(" Construct a FlowInstance from a flat row\n"). -spec instance_from_row(telega@flow@types:flow_instance_row()) -> telega@flow@types:flow_instance(). instance_from_row(Row) -> {flow_instance, erlang:element(2, Row), erlang:element(3, Row), erlang:element(4, Row), erlang:element(5, Row), {flow_state, erlang:element(6, Row), erlang:element(7, Row), [erlang:element(6, Row)], [], none}, erlang:element(8, Row), erlang:element(9, Row), erlang:element(10, Row), erlang:element(11, Row), erlang:element(12, Row)}. -file("src/telega/flow/instance.gleam", 239). -spec encode_string_dict(gleam@dict:dict(binary(), binary())) -> gleam@json:json(). encode_string_dict(D) -> gleam@json:object( gleam@list:map( maps:to_list(D), fun(Kv) -> {erlang:element(1, Kv), gleam@json:string(erlang:element(2, Kv))} end ) ). -file("src/telega/flow/instance.gleam", 243). -spec string_dict_decoder() -> gleam@dynamic@decode:decoder(gleam@dict:dict(binary(), binary())). string_dict_decoder() -> gleam@dynamic@decode:dict( {decoder, fun gleam@dynamic@decode:decode_string/1}, {decoder, fun gleam@dynamic@decode:decode_string/1} ). -file("src/telega/flow/instance.gleam", 247). -spec encode_nested_dict( gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary())) ) -> gleam@json:json(). encode_nested_dict(D) -> gleam@json:object( gleam@list:map( maps:to_list(D), fun(Kv) -> {erlang:element(1, Kv), encode_string_dict(erlang:element(2, Kv))} end ) ). -file("src/telega/flow/instance.gleam", 253). -spec nested_dict_decoder() -> gleam@dynamic@decode:decoder(gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary()))). nested_dict_decoder() -> gleam@dynamic@decode:dict( {decoder, fun gleam@dynamic@decode:decode_string/1}, string_dict_decoder() ). -file("src/telega/flow/instance.gleam", 259). -spec encode_parallel_state(telega@flow@types:parallel_state()) -> gleam@json:json(). encode_parallel_state(Ps) -> gleam@json:object( [{<<"pending_steps"/utf8>>, gleam@json:array(erlang:element(2, Ps), fun gleam@json:string/1)}, {<<"completed_steps"/utf8>>, gleam@json:array(erlang:element(3, Ps), fun gleam@json:string/1)}, {<<"results"/utf8>>, encode_nested_dict(erlang:element(4, Ps))}, {<<"join_step"/utf8>>, gleam@json:string(erlang:element(5, Ps))}] ). -file("src/telega/flow/instance.gleam", 268). -spec parallel_state_decoder() -> gleam@dynamic@decode:decoder(telega@flow@types:parallel_state()). parallel_state_decoder() -> gleam@dynamic@decode:field( <<"pending_steps"/utf8>>, gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_string/1} ), fun(Pending_steps) -> gleam@dynamic@decode:field( <<"completed_steps"/utf8>>, gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_string/1} ), fun(Completed_steps) -> gleam@dynamic@decode:field( <<"results"/utf8>>, nested_dict_decoder(), fun(Results) -> gleam@dynamic@decode:field( <<"join_step"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Join_step) -> gleam@dynamic@decode:success( {parallel_state, Pending_steps, Completed_steps, Results, Join_step} ) end ) end ) end ) end ). -file("src/telega/flow/instance.gleam", 284). -spec encode_stack_frame(telega@flow@types:flow_stack_frame()) -> gleam@json:json(). encode_stack_frame(Frame) -> gleam@json:object( [{<<"flow_name"/utf8>>, gleam@json:string(erlang:element(2, Frame))}, {<<"return_step"/utf8>>, gleam@json:string(erlang:element(3, Frame))}, {<<"saved_data"/utf8>>, encode_string_dict(erlang:element(4, Frame))}] ). -file("src/telega/flow/instance.gleam", 292). -spec stack_frame_decoder() -> gleam@dynamic@decode:decoder(telega@flow@types:flow_stack_frame()). stack_frame_decoder() -> gleam@dynamic@decode:field( <<"flow_name"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Flow_name) -> gleam@dynamic@decode:field( <<"return_step"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Return_step) -> gleam@dynamic@decode:field( <<"saved_data"/utf8>>, string_dict_decoder(), fun(Saved_data) -> gleam@dynamic@decode:success( {flow_stack_frame, Flow_name, Return_step, Saved_data} ) end ) end ) end ). -file("src/telega/flow/instance.gleam", 299). -spec encode_state(telega@flow@types:flow_state()) -> gleam@json:json(). encode_state(State) -> gleam@json:object( [{<<"current_step"/utf8>>, gleam@json:string(erlang:element(2, State))}, {<<"data"/utf8>>, encode_string_dict(erlang:element(3, State))}, {<<"history"/utf8>>, gleam@json:array( erlang:element(4, State), fun gleam@json:string/1 )}, {<<"flow_stack"/utf8>>, gleam@json:array( erlang:element(5, State), fun encode_stack_frame/1 )}, {<<"parallel_state"/utf8>>, gleam@json:nullable( erlang:element(6, State), fun encode_parallel_state/1 )}] ). -file("src/telega/flow/instance.gleam", 312). -spec state_decoder() -> gleam@dynamic@decode:decoder(telega@flow@types:flow_state()). state_decoder() -> gleam@dynamic@decode:field( <<"current_step"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Current_step) -> gleam@dynamic@decode:field( <<"data"/utf8>>, string_dict_decoder(), fun(Data) -> gleam@dynamic@decode:field( <<"history"/utf8>>, gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_string/1} ), fun(History) -> gleam@dynamic@decode:field( <<"flow_stack"/utf8>>, gleam@dynamic@decode:list(stack_frame_decoder()), fun(Flow_stack) -> gleam@dynamic@decode:field( <<"parallel_state"/utf8>>, gleam@dynamic@decode:optional( parallel_state_decoder() ), fun(Parallel_state) -> gleam@dynamic@decode:success( {flow_state, Current_step, Data, History, Flow_stack, Parallel_state} ) end ) end ) end ) end ) end ). -file("src/telega/flow/instance.gleam", 334). ?DOC(" Encode a complete `FlowInstance` to JSON.\n"). -spec to_json(telega@flow@types:flow_instance()) -> gleam@json:json(). to_json(Instance) -> gleam@json:object( [{<<"id"/utf8>>, gleam@json:string(erlang:element(2, Instance))}, {<<"flow_name"/utf8>>, gleam@json:string(erlang:element(3, Instance))}, {<<"user_id"/utf8>>, gleam@json:int(erlang:element(4, Instance))}, {<<"chat_id"/utf8>>, gleam@json:int(erlang:element(5, Instance))}, {<<"state"/utf8>>, encode_state(erlang:element(6, Instance))}, {<<"step_data"/utf8>>, encode_string_dict(erlang:element(7, Instance))}, {<<"wait_token"/utf8>>, gleam@json:nullable( erlang:element(8, Instance), fun gleam@json:string/1 )}, {<<"wait_timeout_at"/utf8>>, gleam@json:nullable( erlang:element(9, Instance), fun gleam@json:int/1 )}, {<<"created_at"/utf8>>, gleam@json:int(erlang:element(10, Instance))}, {<<"updated_at"/utf8>>, gleam@json:int(erlang:element(11, Instance))}] ). -file("src/telega/flow/instance.gleam", 350). ?DOC(" Decoder for a complete `FlowInstance`.\n"). -spec instance_decoder() -> gleam@dynamic@decode:decoder(telega@flow@types:flow_instance()). instance_decoder() -> gleam@dynamic@decode:field( <<"id"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Id) -> gleam@dynamic@decode:field( <<"flow_name"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Flow_name) -> gleam@dynamic@decode:field( <<"user_id"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(User_id) -> gleam@dynamic@decode:field( <<"chat_id"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Chat_id) -> gleam@dynamic@decode:field( <<"state"/utf8>>, state_decoder(), fun(State) -> gleam@dynamic@decode:field( <<"step_data"/utf8>>, string_dict_decoder(), fun(Step_data) -> gleam@dynamic@decode:field( <<"wait_token"/utf8>>, gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_string/1} ), fun(Wait_token) -> gleam@dynamic@decode:field( <<"wait_timeout_at"/utf8>>, gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_int/1} ), fun( Wait_timeout_at ) -> gleam@dynamic@decode:field( <<"created_at"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun( Created_at ) -> gleam@dynamic@decode:field( <<"updated_at"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun( Updated_at ) -> gleam@dynamic@decode:success( {flow_instance, Id, Flow_name, User_id, Chat_id, State, Step_data, Wait_token, Wait_timeout_at, Created_at, Updated_at} ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/telega/flow/instance.gleam", 379). ?DOC(" Serialize a `FlowInstance` to a JSON string (for string-based storage).\n"). -spec to_json_string(telega@flow@types:flow_instance()) -> binary(). to_json_string(Instance) -> _pipe = Instance, _pipe@1 = to_json(_pipe), gleam@json:to_string(_pipe@1). -file("src/telega/flow/instance.gleam", 384). ?DOC(" Deserialize a `FlowInstance` from a JSON string.\n"). -spec from_json_string(binary()) -> {ok, telega@flow@types:flow_instance()} | {error, gleam@json:decode_error()}. from_json_string(Raw) -> gleam@json:parse(Raw, instance_decoder()). -file("src/telega/flow/instance.gleam", 389). ?DOC(" Check if an instance is expired based on TTL or wait timeout\n"). -spec is_expired( telega@flow@types:flow_instance(), gleam@option:option(integer()) ) -> boolean(). is_expired(Instance, Ttl_ms) -> Now = telega@internal@utils:current_time_ms(), Ttl_expired = case Ttl_ms of {some, Ttl} -> (Now - erlang:element(10, Instance)) > Ttl; none -> false end, Wait_expired = case erlang:element(9, Instance) of {some, Timeout_at} -> Now > Timeout_at; none -> false end, Ttl_expired orelse Wait_expired. -file("src/telega/flow/instance.gleam", 403). ?DOC(" Update instance data and continue to next step\n"). -spec next_with_data( telega@bot:context(BAHX, BAHY, BAHZ), telega@flow@types:flow_instance(), BAID, binary(), binary() ) -> {ok, {telega@bot:context(BAHX, BAHY, BAHZ), telega@flow@types:flow_action(BAID), telega@flow@types:flow_instance()}} | {error, BAHY}. next_with_data(Ctx, Instance, Step, Key, Value) -> Updated_instance = store_data(Instance, Key, Value), {ok, {Ctx, {next, Step}, Updated_instance}}. -file("src/telega/flow/instance.gleam", 415). ?DOC(" Get current step as typed value\n"). -spec get_current_step( telega@flow@types:flow(BAII, any(), any(), any()), telega@flow@types:flow_instance() ) -> {ok, BAII} | {error, nil}. get_current_step(Flow, Instance) -> (erlang:element(6, Flow))(erlang:element(2, erlang:element(6, Instance))). -file("src/telega/flow/instance.gleam", 424). ?DOC(false). -spec encode_text_wait_result(binary()) -> binary(). encode_text_wait_result(Text) -> <<"text:"/utf8, Text/binary>>. -file("src/telega/flow/instance.gleam", 430). ?DOC(false). -spec encode_callback_wait_result(binary()) -> binary(). encode_callback_wait_result(Data) -> case gleam@string:split(Data, <<":"/utf8>>) of [_, <<"true"/utf8>>] -> <<"bool:true"/utf8>>; [_, <<"false"/utf8>>] -> <<"bool:false"/utf8>>; _ -> <<"data:"/utf8, Data/binary>> end.