src/rally.erl

-module(rally).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/rally.gleam").
-export([main/0]).
-export_type([rally_error/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(
    " CLI entry point for Rally codegen. Reads [[tools.rally.clients]]\n"
    " from gleam.toml and runs one codegen pipeline per client namespace:\n"
    " scan routes, parse pages, discover handlers via libero, generate\n"
    " server and client code, tree-shake, resolve dependencies, write output.\n"
).

-type rally_error() :: {rally_error, binary()}.

-file("src/rally.gleam", 1151).
-spec dirname(binary()) -> binary().
dirname(Path) ->
    case begin
        _pipe = gleam@string:split(Path, <<"/"/utf8>>),
        lists:reverse(_pipe)
    end of
        [_ | Rest] ->
            gleam@string:join(lists:reverse(Rest), <<"/"/utf8>>);

        [] ->
            <<"."/utf8>>
    end.

-file("src/rally.gleam", 1130).
-spec write_if_changed(binary(), binary()) -> {ok, nil} | {error, binary()}.
write_if_changed(Path, Content) ->
    case simplifile:read(Path) of
        {ok, Existing} when Existing =:= Content ->
            {ok, nil};

        _ ->
            gleam@result:'try'(
                begin
                    _pipe = simplifile:create_directory_all(dirname(Path)),
                    gleam@result:map_error(
                        _pipe,
                        fun(E) ->
                            <<<<<<"Failed to create directory for "/utf8,
                                        Path/binary>>/binary,
                                    ": "/utf8>>/binary,
                                (simplifile:describe_error(E))/binary>>
                        end
                    )
                end,
                fun(_) -> _pipe@1 = simplifile:write(Path, Content),
                    gleam@result:map_error(
                        _pipe@1,
                        fun(E@1) ->
                            <<<<<<"Failed to write "/utf8, Path/binary>>/binary,
                                    ": "/utf8>>/binary,
                                (simplifile:describe_error(E@1))/binary>>
                        end
                    ) end
            )
    end.

-file("src/rally.gleam", 1118).
-spec write_generated_files(list(rally@generator@client:generated_file())) -> {ok,
        nil} |
    {error, binary()}.
write_generated_files(Files) ->
    gleam@list:try_fold(
        Files,
        nil,
        fun(_, File) ->
            Formatted = case gleam_stdlib:string_ends_with(
                erlang:element(2, File),
                <<".gleam"/utf8>>
            ) of
                true ->
                    rally@format:format_gleam(erlang:element(3, File));

                false ->
                    erlang:element(3, File)
            end,
            write_if_changed(erlang:element(2, File), Formatted)
        end
    ).

-file("src/rally.gleam", 1098).
-spec reset_generated_client_src(binary()) -> nil.
reset_generated_client_src(Client_root) ->
    _ = simplifile:delete_all([<<Client_root/binary, "/src"/utf8>>]),
    nil.

-file("src/rally.gleam", 1199).
-spec take_through_src(list(binary()), list(binary())) -> {ok, list(binary())} |
    {error, nil}.
take_through_src(Parts, Acc) ->
    case Parts of
        [] ->
            {error, nil};

        [<<"src"/utf8>> | _] ->
            {ok, lists:append(Acc, [<<"src"/utf8>>])};

        [Part | Rest] ->
            take_through_src(Rest, lists:append(Acc, [Part]))
    end.

-file("src/rally.gleam", 1188).
-spec split_before_pages(list(binary()), list(binary())) -> {ok, list(binary())} |
    {error, nil}.
split_before_pages(Parts, Acc) ->
    case Parts of
        [] ->
            {error, nil};

        [<<"pages"/utf8>> | _] ->
            {ok, Acc};

        [Part | Rest] ->
            split_before_pages(Rest, lists:append(Acc, [Part]))
    end.

-file("src/rally.gleam", 1176).
-spec source_root_for_pages(binary()) -> binary().
source_root_for_pages(Pages_root) ->
    Parts = gleam@string:split(Pages_root, <<"/"/utf8>>),
    case split_before_pages(Parts, []) of
        {ok, Prefix_parts} ->
            case take_through_src(Prefix_parts, []) of
                {ok, Src_parts} ->
                    gleam@string:join(Src_parts, <<"/"/utf8>>);

                _ ->
                    dirname(Pages_root)
            end;

        _ ->
            dirname(Pages_root)
    end.

-file("src/rally.gleam", 1103).
-spec last_module_segment(binary()) -> binary().
last_module_segment(Module_path) ->
    case gleam@string:split_once(Module_path, <<"pages/"/utf8>>) of
        {ok, {_, Rest}} ->
            Rest;

        _ ->
            Module_path
    end.

-file("src/rally.gleam", 1210).
-spec copy_layout_modules(
    list(rally@types:scanned_route()),
    rally@types:scan_config(),
    list(binary())
) -> list(rally@generator@client:generated_file()).
copy_layout_modules(Routes, Config, Server_symbols) ->
    _pipe = Routes,
    _pipe@1 = gleam@list:filter_map(
        _pipe,
        fun(Route) -> case erlang:element(6, Route) of
                {some, Layout_module} ->
                    {ok, Layout_module};

                none ->
                    {error, nil}
            end end
    ),
    _pipe@2 = gleam@list:unique(_pipe@1),
    gleam@list:filter_map(
        _pipe@2,
        fun(Layout_module@1) ->
            File_path = <<<<<<(erlang:element(2, Config))/binary, "/"/utf8>>/binary,
                    (last_module_segment(Layout_module@1))/binary>>/binary,
                ".gleam"/utf8>>,
            case simplifile:read(File_path) of
                {ok, Source} ->
                    Shaken = rally@tree_shaker:shake(Source, Server_symbols),
                    Dest = <<<<<<(erlang:element(13, Config))/binary,
                                "/src/"/utf8>>/binary,
                            Layout_module@1/binary>>/binary,
                        ".gleam"/utf8>>,
                    {ok, {generated_file, Dest, Shaken}};

                _ ->
                    {error, nil}
            end
        end
    ).

-file("src/rally.gleam", 1059).
?DOC(" Tree-shake client_context.gleam and collect its FFI file if present.\n").
-spec generate_client_context_files(
    rally@types:scan_config(),
    binary(),
    binary(),
    list(binary())
) -> list(rally@generator@client:generated_file()).
generate_client_context_files(
    Config,
    Client_context_path,
    Client_context_module,
    Server_symbols
) ->
    case begin
        _pipe = simplifile_erl:is_file(Client_context_path),
        gleam@result:unwrap(_pipe, false)
    end of
        true ->
            case simplifile:read(Client_context_path) of
                {ok, Cc_source} ->
                    Shaken = rally@tree_shaker:shake(Cc_source, Server_symbols),
                    Ffi_path = <<(dirname(erlang:element(2, Config)))/binary,
                        "/client_context_ffi.mjs"/utf8>>,
                    Ffi_files = case simplifile:read(Ffi_path) of
                        {ok, Ffi_content} ->
                            [{generated_file,
                                    <<<<<<(erlang:element(13, Config))/binary,
                                                "/src/"/utf8>>/binary,
                                            Client_context_module/binary>>/binary,
                                        "_ffi.mjs"/utf8>>,
                                    Ffi_content}];

                        _ ->
                            []
                    end,
                    [{generated_file,
                            <<<<<<(erlang:element(13, Config))/binary,
                                        "/src/"/utf8>>/binary,
                                    Client_context_module/binary>>/binary,
                                ".gleam"/utf8>>,
                            Shaken} |
                        Ffi_files];

                _ ->
                    []
            end;

        false ->
            []
    end.

-file("src/rally.gleam", 1110).
-spec write_file(binary(), binary()) -> {ok, nil} | {error, binary()}.
write_file(Path, Content) ->
    Formatted = case gleam_stdlib:string_ends_with(Path, <<".gleam"/utf8>>) of
        true ->
            rally@format:format_gleam(Content);

        false ->
            Content
    end,
    write_if_changed(Path, Formatted).

-file("src/rally.gleam", 1248).
-spec collect_server_symbols(list(libero@scanner:handler_endpoint())) -> list(binary()).
collect_server_symbols(Endpoints) ->
    Handler_type_names = gleam@list:filter_map(
        Endpoints,
        fun(E) -> case erlang:element(8, E) of
                {some, {_, Name}} ->
                    {ok, Name};

                none ->
                    {error, nil}
            end end
    ),
    [<<"ServerContext"/utf8>> | Handler_type_names].

-file("src/rally.gleam", 974).
?DOC(
    " Generate the Erlang atoms module source. For JSON protocol, extends the\n"
    " base module with push dispatch functions and persistent_term registrations.\n"
).
-spec generate_atoms_erl_source(
    list(libero@scanner:handler_endpoint()),
    list(libero@walker:discovered_type()),
    rally@types:scan_config(),
    list({binary(), binary()})
) -> binary().
generate_atoms_erl_source(
    Ns_endpoints,
    Discovered,
    Config,
    Json_push_dispatches
) ->
    Atoms_erl = libero:generate_atoms(
        Ns_endpoints,
        Discovered,
        erlang:element(7, Config),
        {some, erlang:element(9, Config)}
    ),
    case erlang:element(18, Config) of
        <<"json"/utf8>> ->
            Json_codec_mod = gleam@string:replace(
                erlang:element(7, Config),
                <<"@rpc_atoms"/utf8>>,
                <<"@json_codecs"/utf8>>
            ),
            Protocol_wire_mod = gleam@string:replace(
                erlang:element(7, Config),
                <<"@rpc_atoms"/utf8>>,
                <<"@protocol_wire"/utf8>>
            ),
            Push_arms = case Json_push_dispatches of
                [] ->
                    <<"    _Page -> error({no_json_push_encoder, Page})\n"/utf8>>;

                _ ->
                    _pipe = gleam@list:map(
                        Json_push_dispatches,
                        fun(D) ->
                            {Page_tag, Type_atom} = D,
                            <<<<<<<<<<<<"    <<\""/utf8, Page_tag/binary>>/binary,
                                                "\">> -> '"/utf8>>/binary,
                                            Json_codec_mod/binary>>/binary,
                                        "':'json_encode_"/utf8>>/binary,
                                    Type_atom/binary>>/binary,
                                "'(Msg);\n"/utf8>>
                        end
                    ),
                    _pipe@1 = gleam@string:join(_pipe, <<""/utf8>>),
                    (fun(Arms) ->
                        <<Arms/binary,
                            "    Page -> error({no_json_push_encoder, Page})\n"/utf8>>
                    end)(_pipe@1)
            end,
            Atoms_erl@1 = gleam@string:replace(
                Atoms_erl,
                <<"-export([ensure/0])."/utf8>>,
                <<"-export([ensure/0, encode_push_frame/2, json_encode_push_value/2])."/utf8>>
            ),
            Atoms_erl@2 = case gleam@string:split_once(
                Atoms_erl@1,
                <<"persistent_term:put({?MODULE, done}, true),"/utf8>>
            ) of
                {ok, {Before, After}} ->
                    <<<<<<<<<<<<<<<<Before/binary,
                                                    "    persistent_term:put({libero, push_frame_module}, '"/utf8>>/binary,
                                                (erlang:element(7, Config))/binary>>/binary,
                                            "'),\n"/utf8>>/binary,
                                        "    persistent_term:put({libero, json_wire_module}, '"/utf8>>/binary,
                                    Protocol_wire_mod/binary>>/binary,
                                "'),\n"/utf8>>/binary,
                            "    persistent_term:put({?MODULE, done}, true),"/utf8>>/binary,
                        After/binary>>;

                {error, nil} ->
                    Atoms_erl@1
            end,
            <<<<<<<<<<<<<<<<<<<<<<<<Atoms_erl@2/binary, "\n\n"/utf8>>/binary,
                                                        "%% Push dispatch: route page tag to the correct typed encoder.\n"/utf8>>/binary,
                                                    "json_encode_push_value(Page, Msg) ->\n"/utf8>>/binary,
                                                "    case Page of\n"/utf8>>/binary,
                                            Push_arms/binary>>/binary,
                                        "    end.\n"/utf8>>/binary,
                                    "\n"/utf8>>/binary,
                                "%% Single push-frame facade called by rally_runtime_ffi.\n"/utf8>>/binary,
                            "encode_push_frame(Page, Msg) ->\n"/utf8>>/binary,
                        "    JsonValue = json_encode_push_value(Page, Msg),\n"/utf8>>/binary,
                    "    JsonWireMod = persistent_term:get({libero, json_wire_module}),\n"/utf8>>/binary,
                "    JsonWireMod:encode_push(Page, JsonValue).\n"/utf8>>;

        _ ->
            Atoms_erl
    end.

-file("src/rally.gleam", 601).
-spec do_write_files(
    rally@types:scan_config(),
    binary(),
    binary(),
    binary(),
    binary(),
    list({rally@types:scanned_route(), rally@types:page_contract()}),
    list(libero@scanner:handler_endpoint()),
    binary(),
    gleam@option:option(rally@types:auth_config()),
    binary(),
    binary(),
    binary()
) -> {ok, nil} | {error, rally_error()}.
do_write_files(
    Config,
    Route_source,
    Dispatch_source,
    Sd_source,
    Ssr_source,
    Contracts,
    Ns_endpoints,
    Rpc_dispatch_module,
    Auth_config,
    From_session_module,
    Protocol_wire_module,
    Contract_hash
) ->
    Ws_source = rally@generator@ws_handler:generate(
        Contracts,
        erlang:element(7, Config),
        Rpc_dispatch_module,
        Auth_config,
        From_session_module,
        Ns_endpoints,
        Protocol_wire_module,
        erlang:element(18, Config)
    ),
    gleam@result:'try'(
        begin
            _pipe = write_file(erlang:element(3, Config), Route_source),
            gleam@result:map_error(
                _pipe,
                fun(Msg) ->
                    {rally_error, <<"write error: "/utf8, Msg/binary>>}
                end
            )
        end,
        fun(_) ->
            gleam@result:'try'(
                begin
                    _pipe@1 = write_file(
                        erlang:element(4, Config),
                        Dispatch_source
                    ),
                    gleam@result:map_error(
                        _pipe@1,
                        fun(Msg@1) ->
                            {rally_error,
                                <<"write error: "/utf8, Msg@1/binary>>}
                        end
                    )
                end,
                fun(_) ->
                    gleam@result:'try'(
                        begin
                            _pipe@2 = write_file(
                                erlang:element(5, Config),
                                Sd_source
                            ),
                            gleam@result:map_error(
                                _pipe@2,
                                fun(Msg@2) ->
                                    {rally_error,
                                        <<"write error: "/utf8, Msg@2/binary>>}
                                end
                            )
                        end,
                        fun(_) ->
                            gleam@result:'try'(
                                begin
                                    _pipe@3 = write_file(
                                        erlang:element(10, Config),
                                        Ssr_source
                                    ),
                                    gleam@result:map_error(
                                        _pipe@3,
                                        fun(Msg@3) ->
                                            {rally_error,
                                                <<"write error: "/utf8,
                                                    Msg@3/binary>>}
                                        end
                                    )
                                end,
                                fun(_) ->
                                    gleam@result:'try'(
                                        begin
                                            _pipe@4 = write_file(
                                                erlang:element(11, Config),
                                                Ws_source
                                            ),
                                            gleam@result:map_error(
                                                _pipe@4,
                                                fun(Msg@4) ->
                                                    {rally_error,
                                                        <<"write error: "/utf8,
                                                            Msg@4/binary>>}
                                                end
                                            )
                                        end,
                                        fun(_) ->
                                            gleam@result:'try'(
                                                case Ns_endpoints of
                                                    [] ->
                                                        {ok, nil};

                                                    _ ->
                                                        Http_source = rally@generator@http_handler:generate(
                                                            Ns_endpoints,
                                                            Rpc_dispatch_module,
                                                            Auth_config,
                                                            Contracts,
                                                            From_session_module,
                                                            Protocol_wire_module,
                                                            erlang:element(
                                                                18,
                                                                Config
                                                            )
                                                        ),
                                                        _pipe@5 = write_file(
                                                            erlang:element(
                                                                12,
                                                                Config
                                                            ),
                                                            Http_source
                                                        ),
                                                        gleam@result:map_error(
                                                            _pipe@5,
                                                            fun(Msg@5) ->
                                                                {rally_error,
                                                                    <<"write error: "/utf8,
                                                                        Msg@5/binary>>}
                                                            end
                                                        )
                                                end,
                                                fun(_) ->
                                                    Protocol_wire_output = gleam@string:replace(
                                                        erlang:element(
                                                            11,
                                                            Config
                                                        ),
                                                        <<"ws_handler.gleam"/utf8>>,
                                                        <<"protocol_wire.gleam"/utf8>>
                                                    ),
                                                    Protocol_wire_source = rally@generator:generate_protocol_wire(
                                                        erlang:element(
                                                            18,
                                                            Config
                                                        ),
                                                        erlang:element(
                                                            7,
                                                            Config
                                                        ),
                                                        Contract_hash,
                                                        Rpc_dispatch_module,
                                                        Ns_endpoints,
                                                        Auth_config,
                                                        Protocol_wire_module
                                                    ),
                                                    gleam@result:'try'(
                                                        begin
                                                            _pipe@6 = write_file(
                                                                Protocol_wire_output,
                                                                Protocol_wire_source
                                                            ),
                                                            gleam@result:map_error(
                                                                _pipe@6,
                                                                fun(Msg@6) ->
                                                                    {rally_error,
                                                                        <<"write error: "/utf8,
                                                                            Msg@6/binary>>}
                                                                end
                                                            )
                                                        end,
                                                        fun(_) -> {ok, nil} end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/rally.gleam", 1261).
-spec has_to_client_type(
    rally@types:scanned_route(),
    rally@types:page_contract()
) -> boolean().
has_to_client_type(Route, Contract) ->
    gleam@list:any(
        erlang:element(3, Contract),
        fun(Variant) -> case erlang:element(3, Variant) of
                [Field] ->
                    case erlang:element(3, Field) of
                        {user_type, Module_path, <<"ToClient"/utf8>>, []} when Module_path =:= erlang:element(
                            5,
                            Route
                        ) ->
                            true;

                        _ ->
                            false
                    end;

                _ ->
                    false
            end end
    ).

-file("src/rally.gleam", 927).
?DOC(
    " Compute the JSON contract hash for cache busting. Returns \"\" for\n"
    " non-JSON protocols.\n"
).
-spec compute_contract_hash(
    list({rally@types:scanned_route(), rally@types:page_contract()}),
    list(libero@scanner:handler_endpoint()),
    list(libero@walker:discovered_type()),
    rally@types:scan_config()
) -> binary().
compute_contract_hash(Contracts, Ns_endpoints, Discovered, Config) ->
    case erlang:element(18, Config) of
        <<"json"/utf8>> ->
            Push_contracts = gleam@list:filter_map(
                Contracts,
                fun(Pair) ->
                    {Route, Contract} = Pair,
                    case has_to_client_type(Route, Contract) of
                        true ->
                            {ok,
                                {push_contract,
                                    erlang:element(5, Route),
                                    erlang:element(5, Route),
                                    <<"ToClient"/utf8>>}};

                        false ->
                            {error, nil}
                    end
                end
            ),
            Ssr_model_contracts = gleam@list:filter_map(
                Contracts,
                fun(Pair@1) ->
                    {Route@1, Contract@1} = Pair@1,
                    case erlang:element(4, Contract@1) andalso erlang:element(
                        7,
                        Contract@1
                    ) of
                        true ->
                            {ok,
                                {ssr_model_contract,
                                    erlang:element(5, Route@1),
                                    erlang:element(5, Route@1),
                                    <<"Model"/utf8>>}};

                        false ->
                            {error, nil}
                    end
                end
            ),
            libero@json@contract:generate_hash(
                Ns_endpoints,
                Discovered,
                Push_contracts,
                Ssr_model_contracts
            );

        _ ->
            <<""/utf8>>
    end.

-file("src/rally.gleam", 882).
?DOC(
    " Build push dispatch entries for pages with ToClient types and for\n"
    " ClientContextMsg when client context is present.\n"
).
-spec build_push_dispatches(
    list({rally@types:scanned_route(), rally@types:page_contract()}),
    boolean(),
    gleam@option:option(binary()),
    binary()
) -> list(libero@etf@codegen_erl:push_dispatch()).
build_push_dispatches(
    Contracts,
    Has_client_context,
    Client_context_source,
    Client_context_module
) ->
    Page_dispatches = gleam@list:filter_map(
        Contracts,
        fun(Pair) ->
            {Route, Contract} = Pair,
            case has_to_client_type(Route, Contract) of
                true ->
                    Type_atom = libero:qualified_atom_name(
                        erlang:element(5, Route),
                        <<"ToClient"/utf8>>
                    ),
                    {ok, {push_dispatch, erlang:element(3, Route), Type_atom}};

                false ->
                    {error, nil}
            end
        end
    ),
    Cc_dispatch = case {Has_client_context, Client_context_source} of
        {true, {some, _}} ->
            Type_atom@1 = libero:qualified_atom_name(
                Client_context_module,
                <<"ClientContextMsg"/utf8>>
            ),
            [{push_dispatch, <<"__ClientContext__"/utf8>>, Type_atom@1}];

        {_, _} ->
            []
    end,
    lists:append(Page_dispatches, Cc_dispatch).

-file("src/rally.gleam", 841).
?DOC(
    " Collect type seeds from handlers, client context, page models, and\n"
    " ToClient types, then walk the type graph via libero.\n"
).
-spec walk_discovered_types(
    list(libero@scanner:handler_endpoint()),
    list({rally@types:scanned_route(), rally@types:page_contract()}),
    gleam@option:option(binary()),
    binary()
) -> list(libero@walker:discovered_type()).
walk_discovered_types(
    Ns_endpoints,
    Contracts,
    Client_context_source,
    Client_context_module
) ->
    Handler_seeds = libero:collect_seeds(Ns_endpoints),
    Cc_seeds = case Client_context_source of
        {some, Source} ->
            rally@generator@codec:client_context_seeds(
                Source,
                Client_context_module
            );

        none ->
            []
    end,
    Page_model_seeds = gleam@list:filter_map(
        Contracts,
        fun(Pair) ->
            {Route, Contract} = Pair,
            case erlang:element(7, Contract) of
                true ->
                    {ok, {erlang:element(5, Route), <<"Model"/utf8>>}};

                false ->
                    {error, nil}
            end
        end
    ),
    To_client_seeds = gleam@list:filter_map(
        Contracts,
        fun(Pair@1) ->
            {Route@1, Contract@1} = Pair@1,
            case has_to_client_type(Route@1, Contract@1) of
                true ->
                    {ok, {erlang:element(5, Route@1), <<"ToClient"/utf8>>}};

                false ->
                    {error, nil}
            end
        end
    ),
    Seeds = lists:append(
        [Handler_seeds, Cc_seeds, Page_model_seeds, To_client_seeds]
    ),
    case libero:walk(Seeds) of
        {ok, Types} ->
            Types;

        {error, Errors} ->
            gleam@list:each(Errors, fun libero@gen_error:print_error/1),
            []
    end.

-file("src/rally.gleam", 1162).
-spec last_segment(binary()) -> binary().
last_segment(Module_path) ->
    case begin
        _pipe = gleam@string:split(Module_path, <<"/"/utf8>>),
        gleam@list:last(_pipe)
    end of
        {ok, Seg} ->
            Seg;

        {error, nil} ->
            Module_path
    end.

-file("src/rally.gleam", 1169).
-spec import_as_string(binary(), binary()) -> binary().
import_as_string(Module_path, Alias) ->
    case last_segment(Module_path) =:= Alias of
        true ->
            <<"import "/utf8, Module_path/binary>>;

        false ->
            <<<<<<"import "/utf8, Module_path/binary>>/binary, " as "/utf8>>/binary,
                Alias/binary>>
    end.

-file("src/rally.gleam", 793).
?DOC(
    " Generate the RPC dispatch source via libero, with auth identity threading\n"
    " when auth is configured.\n"
).
-spec generate_rpc_dispatch_source(
    list(libero@scanner:handler_endpoint()),
    rally@types:scan_config(),
    gleam@option:option(rally@types:auth_config())
) -> binary().
generate_rpc_dispatch_source(Ns_endpoints, Config, Auth_config) ->
    Extra_dispatch_params = case Auth_config of
        {some, {auth_config, Auth_module}} ->
            Auth_ref = last_segment(Auth_module),
            [{extra_param,
                    <<"identity"/utf8>>,
                    <<Auth_ref/binary, ".Identity"/utf8>>,
                    import_as_string(Auth_module, Auth_ref)}];

        none ->
            []
    end,
    Source = case Ns_endpoints of
        [] ->
            rally@generator:generate_empty_rpc_dispatch(
                erlang:element(7, Config),
                Extra_dispatch_params
            );

        _ ->
            case Extra_dispatch_params of
                [] ->
                    libero:generate_dispatch(
                        Ns_endpoints,
                        {some, erlang:element(7, Config)},
                        {some, erlang:element(9, Config)}
                    );

                Params ->
                    libero:generate_dispatch_with_extra_params(
                        Ns_endpoints,
                        {some, erlang:element(7, Config)},
                        {some, erlang:element(9, Config)},
                        Params
                    )
            end
    end,
    _pipe = Source,
    _pipe@1 = rally@generator:normalize_rpc_dispatch_context_import(_pipe),
    rally@generator:normalize_rpc_dispatch_unused_fields(_pipe@1).

-file("src/rally.gleam", 1158).
-spec module_from_src_path(binary()) -> binary().
module_from_src_path(Path) ->
    _pipe = Path,
    _pipe@1 = gleam@string:drop_start(_pipe, 4),
    gleam@string:drop_end(_pipe@1, 6).

-file("src/rally.gleam", 1237).
-spec check_server_context_from_session(binary()) -> {boolean(), binary()}.
check_server_context_from_session(Path) ->
    case simplifile:read(Path) of
        {ok, Source} ->
            case gleam_stdlib:contains_string(
                Source,
                <<"pub fn from_session"/utf8>>
            ) of
                true ->
                    {true, <<"server_context"/utf8>>};

                false ->
                    {false, <<"server_context"/utf8>>}
            end;

        _ ->
            {false, <<"server_context"/utf8>>}
    end.

-file("src/rally.gleam", 775).
?DOC(
    " Find from_session: check client_context_server.gleam first, fall back\n"
    " to server_context.gleam.\n"
).
-spec resolve_from_session(binary()) -> {boolean(), binary()}.
resolve_from_session(Pages_root) ->
    Server_context_path = <<"src/server_context.gleam"/utf8>>,
    Client_context_server_path = <<(dirname(Pages_root))/binary,
        "/client_context_server.gleam"/utf8>>,
    Client_context_server_module = module_from_src_path(
        Client_context_server_path
    ),
    case simplifile:read(Client_context_server_path) of
        {ok, Source} ->
            case gleam_stdlib:contains_string(
                Source,
                <<"pub fn from_session"/utf8>>
            ) of
                true ->
                    {true, Client_context_server_module};

                false ->
                    check_server_context_from_session(Server_context_path)
            end;

        _ ->
            check_server_context_from_session(Server_context_path)
    end.

-file("src/rally.gleam", 746).
?DOC(" Read and parse each page module's source to extract its contract.\n").
-spec parse_page_contracts(list(rally@types:scanned_route()), binary()) -> list({rally@types:scanned_route(),
    rally@types:page_contract()}).
parse_page_contracts(Routes, Pages_root) ->
    gleam@list:filter_map(
        Routes,
        fun(Route) ->
            File_path = <<<<<<Pages_root/binary, "/"/utf8>>/binary,
                    (last_module_segment(erlang:element(5, Route)))/binary>>/binary,
                ".gleam"/utf8>>,
            case simplifile:read(File_path) of
                {ok, Source} ->
                    case rally@parser:parse_page(
                        Source,
                        erlang:element(5, Route)
                    ) of
                        {ok, Contract} ->
                            {ok, {Route, Contract}};

                        _ ->
                            gleam_stdlib:println_error(
                                <<<<"warning: failed to parse "/utf8,
                                        File_path/binary>>/binary,
                                    ", skipping"/utf8>>
                            ),
                            {error, nil}
                    end;

                _ ->
                    gleam_stdlib:println_error(
                        <<<<"warning: cannot read "/utf8, File_path/binary>>/binary,
                            ", skipping"/utf8>>
                    ),
                    {error, nil}
            end
        end
    ).

-file("src/rally.gleam", 718).
?DOC(
    " Scan for server_* handler endpoints via libero. When auth is configured,\n"
    " excludes Identity params from the wire contract.\n"
).
-spec discover_endpoints(gleam@option:option(rally@types:auth_config())) -> list(libero@scanner:handler_endpoint()).
discover_endpoints(Auth_config) ->
    Exclude_param_types = case Auth_config of
        {some, {auth_config, Auth_module}} ->
            [{Auth_module, <<"Identity"/utf8>>}];

        none ->
            []
    end,
    case libero:scan_excluding(Exclude_param_types) of
        {ok, Endpoints} ->
            case Endpoints of
                [] ->
                    nil;

                _ ->
                    gleam_stdlib:println(
                        <<<<"rally: discovered "/utf8,
                                (erlang:integer_to_binary(
                                    erlang:length(Endpoints)
                                ))/binary>>/binary,
                            " handler endpoints via libero"/utf8>>
                    )
            end,
            Endpoints;

        {error, Errors} ->
            gleam@list:each(Errors, fun libero@gen_error:print_error/1),
            []
    end.

-file("src/rally.gleam", 690).
?DOC(" Check for an auth.gleam with the required exports alongside the pages dir.\n").
-spec detect_auth(rally@types:scan_config()) -> gleam@option:option(rally@types:auth_config()).
detect_auth(Config) ->
    Auth_path = <<(dirname(erlang:element(2, Config)))/binary,
        "/auth.gleam"/utf8>>,
    case simplifile:read(Auth_path) of
        {ok, Source} ->
            Auth_module = module_from_src_path(Auth_path),
            case ((gleam_stdlib:contains_string(
                Source,
                <<"pub type Identity"/utf8>>
            )
            andalso gleam_stdlib:contains_string(
                Source,
                <<"pub fn resolve"/utf8>>
            ))
            andalso gleam_stdlib:contains_string(
                Source,
                <<"pub fn is_authenticated"/utf8>>
            ))
            andalso gleam_stdlib:contains_string(
                Source,
                <<"pub const redirect_url"/utf8>>
            ) of
                true ->
                    {some, {auth_config, Auth_module}};

                false ->
                    gleam_stdlib:println_error(
                        <<<<"rally: auth.gleam found at "/utf8,
                                Auth_path/binary>>/binary,
                            " but missing required exports (Identity, resolve, is_authenticated, redirect_url)"/utf8>>
                    ),
                    none
            end;

        _ ->
            none
    end.

-file("src/rally.gleam", 258).
-spec generate_for_config(rally@types:scan_config()) -> {ok, nil} |
    {error, rally_error()}.
generate_for_config(Config) ->
    gleam@result:'try'(
        begin
            _pipe = rally@scanner:scan(Config),
            gleam@result:map_error(
                _pipe,
                fun(Msg) ->
                    {rally_error, <<"scan error: "/utf8, Msg/binary>>}
                end
            )
        end,
        fun(Routes) ->
            Auth_config = detect_auth(Config),
            Handler_endpoints = discover_endpoints(Auth_config),
            Contracts = parse_page_contracts(Routes, erlang:element(2, Config)),
            Client_context_path = <<(dirname(erlang:element(2, Config)))/binary,
                "/client_context.gleam"/utf8>>,
            Client_context_module = module_from_src_path(Client_context_path),
            Has_client_context = begin
                _pipe@1 = simplifile_erl:is_file(Client_context_path),
                gleam@result:unwrap(_pipe@1, false)
            end,
            {Has_from_session, From_session_module} = resolve_from_session(
                erlang:element(2, Config)
            ),
            Router_module = module_from_src_path(erlang:element(3, Config)),
            Rpc_dispatch_module = module_from_src_path(
                erlang:element(5, Config)
            ),
            Route_source = rally@generator:generate(Routes),
            Dispatch_source = rally@generator:generate_dispatch(
                Routes,
                Contracts,
                Has_client_context,
                Router_module,
                Client_context_module
            ),
            Namespace_prefix = begin
                _pipe@2 = erlang:element(2, Config),
                _pipe@3 = gleam@string:drop_start(_pipe@2, 4),
                (fun(P) ->
                    gleam@string:replace(P, <<"/pages"/utf8>>, <<""/utf8>>)
                end)(_pipe@3)
            end,
            Ns_endpoints = gleam@list:filter(
                Handler_endpoints,
                fun(Ep) ->
                    gleam_stdlib:string_starts_with(
                        erlang:element(2, Ep),
                        <<Namespace_prefix/binary, "/"/utf8>>
                    )
                end
            ),
            Sd_source = generate_rpc_dispatch_source(
                Ns_endpoints,
                Config,
                Auth_config
            ),
            Shell_html = case simplifile:read(erlang:element(16, Config)) of
                {ok, Html} ->
                    Html;

                _ ->
                    <<"<!DOCTYPE html>\n<html>\n<head><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'></head>\n<body><div id='app'></div><script type='module' src='/client.js'></script></body>\n</html>"/utf8>>
            end,
            Client_context_source = case Has_client_context of
                true ->
                    case simplifile:read(Client_context_path) of
                        {ok, Source} ->
                            {some, Source};

                        _ ->
                            none
                    end;

                false ->
                    none
            end,
            Discovered = walk_discovered_types(
                Ns_endpoints,
                Contracts,
                Client_context_source,
                Client_context_module
            ),
            Push_dispatches = build_push_dispatches(
                Contracts,
                Has_client_context,
                Client_context_source,
                Client_context_module
            ),
            Json_push_dispatches = gleam@list:map(
                Push_dispatches,
                fun(D) -> {erlang:element(2, D), erlang:element(3, D)} end
            ),
            Contract_hash = compute_contract_hash(
                Contracts,
                Ns_endpoints,
                Discovered,
                Config
            ),
            Protocol_wire_output = gleam@string:replace(
                erlang:element(11, Config),
                <<"ws_handler.gleam"/utf8>>,
                <<"protocol_wire.gleam"/utf8>>
            ),
            Protocol_wire_module = begin
                _pipe@4 = Protocol_wire_output,
                _pipe@5 = gleam@string:drop_start(_pipe@4, 4),
                gleam@string:drop_end(_pipe@5, 6)
            end,
            Ssr_source = rally@generator@ssr_handler:generate(
                Contracts,
                Has_client_context,
                Has_from_session,
                From_session_module,
                Router_module,
                Shell_html,
                erlang:element(7, Config),
                {some, erlang:element(9, Config)},
                case Has_client_context of
                    true ->
                        {some, Client_context_module};

                    false ->
                        none
                end,
                Auth_config,
                Protocol_wire_module,
                erlang:element(18, Config)
            ),
            Result = do_write_files(
                Config,
                Route_source,
                Dispatch_source,
                Sd_source,
                Ssr_source,
                Contracts,
                Ns_endpoints,
                Rpc_dispatch_module,
                Auth_config,
                From_session_module,
                Protocol_wire_module,
                Contract_hash
            ),
            gleam@result:'try'(
                Result,
                fun(_) ->
                    Transport_ffi_path = <<(erlang:element(15, Config))/binary,
                        "/src/rally_runtime/transport_ffi.mjs"/utf8>>,
                    gleam@result:'try'(
                        begin
                            _pipe@6 = simplifile:read(Transport_ffi_path),
                            gleam@result:map_error(
                                _pipe@6,
                                fun(E) ->
                                    {rally_error,
                                        <<<<<<"Cannot read transport_ffi.mjs from rally package at "/utf8,
                                                    Transport_ffi_path/binary>>/binary,
                                                ": "/utf8>>/binary,
                                            (simplifile:describe_error(E))/binary>>}
                                end
                            )
                        end,
                        fun(Transport_ffi_content) ->
                            Atoms_erl = generate_atoms_erl_source(
                                Ns_endpoints,
                                Discovered,
                                Config,
                                Json_push_dispatches
                            ),
                            gleam@result:'try'(
                                begin
                                    _pipe@7 = write_file(
                                        erlang:element(6, Config),
                                        Atoms_erl
                                    ),
                                    gleam@result:map_error(
                                        _pipe@7,
                                        fun(Msg@1) ->
                                            {rally_error,
                                                <<"write error: "/utf8,
                                                    Msg@1/binary>>}
                                        end
                                    )
                                end,
                                fun(_) ->
                                    Wire_erl = case libero:generate_wire_erl(
                                        Discovered,
                                        erlang:element(9, Config),
                                        Ns_endpoints,
                                        Push_dispatches
                                    ) of
                                        {ok, Src} ->
                                            Src;

                                        {error, Err} ->
                                            libero@gen_error:print_error(Err),
                                            <<""/utf8>>
                                    end,
                                    gleam@result:'try'(
                                        begin
                                            _pipe@8 = write_file(
                                                erlang:element(8, Config),
                                                Wire_erl
                                            ),
                                            gleam@result:map_error(
                                                _pipe@8,
                                                fun(Msg@2) ->
                                                    {rally_error,
                                                        <<"write error: "/utf8,
                                                            Msg@2/binary>>}
                                                end
                                            )
                                        end,
                                        fun(_) ->
                                            Server_symbols = collect_server_symbols(
                                                Ns_endpoints
                                            ),
                                            gleam@result:'try'(
                                                case Client_context_source of
                                                    {some, Source@1} ->
                                                        _pipe@9 = rally@parser:parse_client_context(
                                                            Source@1
                                                        ),
                                                        _pipe@10 = gleam@result:map(
                                                            _pipe@9,
                                                            fun(Field@0) -> {some, Field@0} end
                                                        ),
                                                        gleam@result:map_error(
                                                            _pipe@10,
                                                            fun(Error) ->
                                                                {rally_error,
                                                                    <<"Cannot parse client_context.gleam: "/utf8,
                                                                        Error/binary>>}
                                                            end
                                                        );

                                                    none ->
                                                        {ok, none}
                                                end,
                                                fun(Client_context_contract) ->
                                                    Raw_codec_files = rally@generator@codec:generate(
                                                        Contracts,
                                                        Discovered,
                                                        Ns_endpoints,
                                                        Server_symbols,
                                                        erlang:element(
                                                            18,
                                                            Config
                                                        )
                                                    ),
                                                    Codec_files = gleam@list:map(
                                                        Raw_codec_files,
                                                        fun(F) ->
                                                            {generated_file,
                                                                <<<<(erlang:element(
                                                                            13,
                                                                            Config
                                                                        ))/binary,
                                                                        "/"/utf8>>/binary,
                                                                    (erlang:element(
                                                                        2,
                                                                        F
                                                                    ))/binary>>,
                                                                erlang:element(
                                                                    3,
                                                                    F
                                                                )}
                                                        end
                                                    ),
                                                    gleam@result:'try'(
                                                        case erlang:element(
                                                            18,
                                                            Config
                                                        ) of
                                                            <<"json"/utf8>> ->
                                                                Files = rally@generator@codec:generate_json_codecs(
                                                                    Discovered,
                                                                    Ns_endpoints
                                                                ),
                                                                case Files of
                                                                    [] ->
                                                                        {error,
                                                                            {rally_error,
                                                                                <<"JSON codec generation failed - no codec files produced"/utf8>>}};

                                                                    _ ->
                                                                        {ok,
                                                                            Files}
                                                                end;

                                                            _ ->
                                                                {ok, []}
                                                        end,
                                                        fun(Json_codec_files) ->
                                                            gleam@result:'try'(
                                                                case erlang:element(
                                                                    18,
                                                                    Config
                                                                ) of
                                                                    <<"json"/utf8>> ->
                                                                        case Json_codec_files of
                                                                            [] ->
                                                                                {ok,
                                                                                    nil};

                                                                            [First |
                                                                                _] ->
                                                                                Server_path = gleam@string:replace(
                                                                                    erlang:element(
                                                                                        10,
                                                                                        Config
                                                                                    ),
                                                                                    <<"ssr_handler.gleam"/utf8>>,
                                                                                    <<"json_codecs.gleam"/utf8>>
                                                                                ),
                                                                                _pipe@11 = write_file(
                                                                                    Server_path,
                                                                                    erlang:element(
                                                                                        3,
                                                                                        First
                                                                                    )
                                                                                ),
                                                                                gleam@result:map_error(
                                                                                    _pipe@11,
                                                                                    fun(
                                                                                        Msg@3
                                                                                    ) ->
                                                                                        {rally_error,
                                                                                            <<"write error: "/utf8,
                                                                                                Msg@3/binary>>}
                                                                                    end
                                                                                )
                                                                        end;

                                                                    _ ->
                                                                        {ok,
                                                                            nil}
                                                                end,
                                                                fun(_) ->
                                                                    Client_files = begin
                                                                        _pipe@12 = rally@generator@client:generate_package_with_client_context_contract(
                                                                            Routes,
                                                                            Contracts,
                                                                            Config,
                                                                            erlang:element(
                                                                                17,
                                                                                Config
                                                                            ),
                                                                            Transport_ffi_content,
                                                                            Client_context_contract,
                                                                            Client_context_module,
                                                                            erlang:element(
                                                                                18,
                                                                                Config
                                                                            )
                                                                        ),
                                                                        _pipe@13 = lists:append(
                                                                            _pipe@12,
                                                                            [{generated_file,
                                                                                    <<(erlang:element(
                                                                                            13,
                                                                                            Config
                                                                                        ))/binary,
                                                                                        "/src/generated/protocol_wire.mjs"/utf8>>,
                                                                                    rally@generator:generate_protocol_wire_js(
                                                                                        erlang:element(
                                                                                            18,
                                                                                            Config
                                                                                        ),
                                                                                        Contract_hash
                                                                                    )}]
                                                                        ),
                                                                        lists:append(
                                                                            _pipe@13,
                                                                            gleam@list:filter_map(
                                                                                Json_codec_files,
                                                                                fun(
                                                                                    F@1
                                                                                ) ->
                                                                                    case erlang:element(
                                                                                        2,
                                                                                        F@1
                                                                                    )
                                                                                    =:= <<"src/generated/type_registry.mjs"/utf8>> of
                                                                                        true ->
                                                                                            {ok,
                                                                                                {generated_file,
                                                                                                    <<(erlang:element(
                                                                                                            13,
                                                                                                            Config
                                                                                                        ))/binary,
                                                                                                        "/src/generated/type_registry.mjs"/utf8>>,
                                                                                                    erlang:element(
                                                                                                        3,
                                                                                                        F@1
                                                                                                    )}};

                                                                                        false ->
                                                                                            {error,
                                                                                                nil}
                                                                                    end
                                                                                end
                                                                            )
                                                                        )
                                                                    end,
                                                                    Client_context_files = generate_client_context_files(
                                                                        Config,
                                                                        Client_context_path,
                                                                        Client_context_module,
                                                                        Server_symbols
                                                                    ),
                                                                    Layout_files = copy_layout_modules(
                                                                        Routes,
                                                                        Config,
                                                                        Server_symbols
                                                                    ),
                                                                    Seed_sources = lists:append(
                                                                        [begin
                                                                                _pipe@14 = Raw_codec_files,
                                                                                _pipe@15 = gleam@list:filter(
                                                                                    _pipe@14,
                                                                                    fun(
                                                                                        F@2
                                                                                    ) ->
                                                                                        (gleam_stdlib:string_ends_with(
                                                                                            erlang:element(
                                                                                                2,
                                                                                                F@2
                                                                                            ),
                                                                                            <<".gleam"/utf8>>
                                                                                        )
                                                                                        andalso gleam_stdlib:string_starts_with(
                                                                                            erlang:element(
                                                                                                2,
                                                                                                F@2
                                                                                            ),
                                                                                            <<"src/"/utf8>>
                                                                                        ))
                                                                                        andalso gleam_stdlib:contains_string(
                                                                                            erlang:element(
                                                                                                2,
                                                                                                F@2
                                                                                            ),
                                                                                            <<"/pages/"/utf8>>
                                                                                        )
                                                                                    end
                                                                                ),
                                                                                gleam@list:map(
                                                                                    _pipe@15,
                                                                                    fun(
                                                                                        F@3
                                                                                    ) ->
                                                                                        Module_path = begin
                                                                                            _pipe@16 = erlang:element(
                                                                                                2,
                                                                                                F@3
                                                                                            ),
                                                                                            _pipe@17 = gleam@string:drop_start(
                                                                                                _pipe@16,
                                                                                                4
                                                                                            ),
                                                                                            gleam@string:drop_end(
                                                                                                _pipe@17,
                                                                                                6
                                                                                            )
                                                                                        end,
                                                                                        {Module_path,
                                                                                            erlang:element(
                                                                                                3,
                                                                                                F@3
                                                                                            )}
                                                                                    end
                                                                                )
                                                                            end,
                                                                            begin
                                                                                _pipe@18 = Layout_files,
                                                                                _pipe@19 = gleam@list:filter(
                                                                                    _pipe@18,
                                                                                    fun(
                                                                                        F@4
                                                                                    ) ->
                                                                                        gleam_stdlib:string_ends_with(
                                                                                            erlang:element(
                                                                                                2,
                                                                                                F@4
                                                                                            ),
                                                                                            <<".gleam"/utf8>>
                                                                                        )
                                                                                    end
                                                                                ),
                                                                                gleam@list:map(
                                                                                    _pipe@19,
                                                                                    fun(
                                                                                        F@5
                                                                                    ) ->
                                                                                        Module_path@1 = begin
                                                                                            _pipe@20 = erlang:element(
                                                                                                2,
                                                                                                F@5
                                                                                            ),
                                                                                            _pipe@21 = gleam@string:replace(
                                                                                                _pipe@20,
                                                                                                <<(erlang:element(
                                                                                                        13,
                                                                                                        Config
                                                                                                    ))/binary,
                                                                                                    "/src/"/utf8>>,
                                                                                                <<""/utf8>>
                                                                                            ),
                                                                                            gleam@string:drop_end(
                                                                                                _pipe@21,
                                                                                                6
                                                                                            )
                                                                                        end,
                                                                                        {Module_path@1,
                                                                                            erlang:element(
                                                                                                3,
                                                                                                F@5
                                                                                            )}
                                                                                    end
                                                                                )
                                                                            end,
                                                                            begin
                                                                                _pipe@22 = Client_context_files,
                                                                                gleam@list:map(
                                                                                    _pipe@22,
                                                                                    fun(
                                                                                        F@6
                                                                                    ) ->
                                                                                        {Client_context_module,
                                                                                            erlang:element(
                                                                                                3,
                                                                                                F@6
                                                                                            )}
                                                                                    end
                                                                                )
                                                                            end]
                                                                    ),
                                                                    gleam@result:'try'(
                                                                        begin
                                                                            _pipe@23 = rally@dependency_resolver:resolve(
                                                                                Seed_sources,
                                                                                source_root_for_pages(
                                                                                    erlang:element(
                                                                                        2,
                                                                                        Config
                                                                                    )
                                                                                ),
                                                                                erlang:element(
                                                                                    13,
                                                                                    Config
                                                                                )
                                                                            ),
                                                                            gleam@result:map_error(
                                                                                _pipe@23,
                                                                                fun(
                                                                                    Msg@4
                                                                                ) ->
                                                                                    {rally_error,
                                                                                        <<"dependency resolution error: "/utf8,
                                                                                            Msg@4/binary>>}
                                                                                end
                                                                            )
                                                                        end,
                                                                        fun(
                                                                            Dependency_files
                                                                        ) ->
                                                                            reset_generated_client_src(
                                                                                erlang:element(
                                                                                    13,
                                                                                    Config
                                                                                )
                                                                            ),
                                                                            gleam@result:'try'(
                                                                                begin
                                                                                    _pipe@24 = write_generated_files(
                                                                                        lists:append(
                                                                                            [Codec_files,
                                                                                                Client_files,
                                                                                                Client_context_files,
                                                                                                Layout_files,
                                                                                                Dependency_files]
                                                                                        )
                                                                                    ),
                                                                                    gleam@result:map_error(
                                                                                        _pipe@24,
                                                                                        fun(
                                                                                            Msg@5
                                                                                        ) ->
                                                                                            {rally_error,
                                                                                                <<"write error: "/utf8,
                                                                                                    Msg@5/binary>>}
                                                                                        end
                                                                                    )
                                                                                end,
                                                                                fun(
                                                                                    _
                                                                                ) ->
                                                                                    _ = case simplifile:read(
                                                                                        erlang:element(
                                                                                            4,
                                                                                            Config
                                                                                        )
                                                                                    ) of
                                                                                        {ok,
                                                                                            Content} ->
                                                                                            case (not gleam_stdlib:contains_string(
                                                                                                Content,
                                                                                                <<"pub fn"/utf8>>
                                                                                            )
                                                                                            andalso not gleam_stdlib:contains_string(
                                                                                                Content,
                                                                                                <<"pub type"/utf8>>
                                                                                            ))
                                                                                            andalso not gleam_stdlib:contains_string(
                                                                                                Content,
                                                                                                <<"pub const"/utf8>>
                                                                                            ) of
                                                                                                true ->
                                                                                                    simplifile_erl:delete(
                                                                                                        erlang:element(
                                                                                                            4,
                                                                                                            Config
                                                                                                        )
                                                                                                    );

                                                                                                false ->
                                                                                                    {ok,
                                                                                                        nil}
                                                                                            end;

                                                                                        _ ->
                                                                                            {ok,
                                                                                                nil}
                                                                                    end,
                                                                                    {ok,
                                                                                        nil}
                                                                                end
                                                                            )
                                                                        end
                                                                    )
                                                                end
                                                            )
                                                        end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/rally.gleam", 174).
-spec read_legacy_config(
    gleam@dict:dict(binary(), tom:toml()),
    gleam@dict:dict(binary(), tom:toml()),
    binary()
) -> rally@types:scan_config().
read_legacy_config(Rally_config, Server_deps, Rally_package_path) ->
    Pages_root = begin
        _pipe = tom:get_string(Rally_config, [<<"pages_root"/utf8>>]),
        gleam@result:unwrap(_pipe, <<"src/pages"/utf8>>)
    end,
    Output_route = begin
        _pipe@1 = tom:get_string(Rally_config, [<<"output_route"/utf8>>]),
        gleam@result:unwrap(_pipe@1, <<"src/generated/router.gleam"/utf8>>)
    end,
    Output_dispatch = begin
        _pipe@2 = tom:get_string(Rally_config, [<<"output_dispatch"/utf8>>]),
        gleam@result:unwrap(
            _pipe@2,
            <<"src/generated/page_dispatch.gleam"/utf8>>
        )
    end,
    Output_server_dispatch = begin
        _pipe@3 = tom:get_string(
            Rally_config,
            [<<"output_server_dispatch"/utf8>>]
        ),
        gleam@result:unwrap(
            _pipe@3,
            <<"src/generated/rpc_dispatch.gleam"/utf8>>
        )
    end,
    Output_server_atoms = begin
        _pipe@4 = tom:get_string(Rally_config, [<<"output_server_atoms"/utf8>>]),
        gleam@result:unwrap(_pipe@4, <<"src/generated@rpc_atoms.erl"/utf8>>)
    end,
    Atoms_module = <<"generated@rpc_atoms"/utf8>>,
    Wire_module = <<"generated@rpc_wire"/utf8>>,
    Output_ssr = begin
        _pipe@5 = tom:get_string(Rally_config, [<<"output_ssr"/utf8>>]),
        gleam@result:unwrap(_pipe@5, <<"src/generated/ssr_handler.gleam"/utf8>>)
    end,
    Output_ws = begin
        _pipe@6 = tom:get_string(Rally_config, [<<"output_ws"/utf8>>]),
        gleam@result:unwrap(_pipe@6, <<"src/generated/ws_handler.gleam"/utf8>>)
    end,
    Output_http = begin
        _pipe@7 = tom:get_string(Rally_config, [<<"output_http"/utf8>>]),
        gleam@result:unwrap(
            _pipe@7,
            <<"src/generated/http_handler.gleam"/utf8>>
        )
    end,
    Client_root = begin
        _pipe@8 = tom:get_string(Rally_config, [<<"client_root"/utf8>>]),
        gleam@result:unwrap(_pipe@8, <<".generated_clients"/utf8>>)
    end,
    Route_root = begin
        _pipe@9 = tom:get_string(Rally_config, [<<"route_root"/utf8>>]),
        gleam@result:unwrap(_pipe@9, <<"/"/utf8>>)
    end,
    Shell_file = begin
        _pipe@10 = tom:get_string(Rally_config, [<<"shell_file"/utf8>>]),
        gleam@result:unwrap(_pipe@10, <<"src/shell.html"/utf8>>)
    end,
    Protocol = <<"etf"/utf8>>,
    {scan_config,
        Pages_root,
        Output_route,
        Output_dispatch,
        Output_server_dispatch,
        Output_server_atoms,
        Atoms_module,
        <<"src/generated@rpc_wire.erl"/utf8>>,
        Wire_module,
        Output_ssr,
        Output_ws,
        Output_http,
        Client_root,
        Route_root,
        Rally_package_path,
        Shell_file,
        Server_deps,
        Protocol}.

-file("src/rally.gleam", 1287).
-spec tom_get_error_to_string(tom:get_error()) -> binary().
tom_get_error_to_string(E) ->
    case E of
        {not_found, Key} ->
            <<"key not found: "/utf8,
                (gleam@string:join(Key, <<"."/utf8>>))/binary>>;

        {wrong_type, Key@1, Expected, Got} ->
            <<<<<<<<<<"expected "/utf8, Expected/binary>>/binary,
                            ", got "/utf8>>/binary,
                        Got/binary>>/binary,
                    " at "/utf8>>/binary,
                (gleam@string:join(Key@1, <<"."/utf8>>))/binary>>
    end.

-file("src/rally.gleam", 119).
-spec read_client_config(
    gleam@dict:dict(binary(), tom:toml()),
    gleam@dict:dict(binary(), tom:toml()),
    binary()
) -> {ok, rally@types:scan_config()} | {error, rally_error()}.
read_client_config(Client_config, Server_deps, Rally_package_path) ->
    gleam@result:'try'(
        begin
            _pipe = tom:get_string(Client_config, [<<"namespace"/utf8>>]),
            gleam@result:map_error(
                _pipe,
                fun(E) ->
                    {rally_error,
                        <<"Each [[tools.rally.clients]] entry needs namespace = \"...\": "/utf8,
                            (tom_get_error_to_string(E))/binary>>}
                end
            )
        end,
        fun(Namespace) ->
            Route_root = begin
                _pipe@1 = tom:get_string(Client_config, [<<"route_root"/utf8>>]),
                gleam@result:unwrap(_pipe@1, <<"/"/utf8, Namespace/binary>>)
            end,
            Protocol = begin
                _pipe@2 = tom:get_string(Client_config, [<<"protocol"/utf8>>]),
                gleam@result:unwrap(_pipe@2, <<"etf"/utf8>>)
            end,
            Protocol@1 = case Protocol of
                <<"etf"/utf8>> ->
                    Protocol;

                <<"json"/utf8>> ->
                    Protocol;

                Other ->
                    gleam_stdlib:println_error(
                        <<<<"warning: unknown protocol \""/utf8, Other/binary>>/binary,
                            "\" in [[tools.rally.clients]], defaulting to \"etf\""/utf8>>
                    ),
                    <<"etf"/utf8>>
            end,
            {ok,
                {scan_config,
                    <<<<"src/"/utf8, Namespace/binary>>/binary, "/pages"/utf8>>,
                    <<<<"src/generated/"/utf8, Namespace/binary>>/binary,
                        "/router.gleam"/utf8>>,
                    <<<<"src/generated/"/utf8, Namespace/binary>>/binary,
                        "/page_dispatch.gleam"/utf8>>,
                    <<<<"src/generated/"/utf8, Namespace/binary>>/binary,
                        "/rpc_dispatch.gleam"/utf8>>,
                    <<<<"src/generated@"/utf8, Namespace/binary>>/binary,
                        "@rpc_atoms.erl"/utf8>>,
                    <<<<"generated@"/utf8, Namespace/binary>>/binary,
                        "@rpc_atoms"/utf8>>,
                    <<<<"src/generated@"/utf8, Namespace/binary>>/binary,
                        "@rpc_wire.erl"/utf8>>,
                    <<<<"generated@"/utf8, Namespace/binary>>/binary,
                        "@rpc_wire"/utf8>>,
                    <<<<"src/generated/"/utf8, Namespace/binary>>/binary,
                        "/ssr_handler.gleam"/utf8>>,
                    <<<<"src/generated/"/utf8, Namespace/binary>>/binary,
                        "/ws_handler.gleam"/utf8>>,
                    <<<<"src/generated/"/utf8, Namespace/binary>>/binary,
                        "/http_handler.gleam"/utf8>>,
                    <<".generated_clients/"/utf8, Namespace/binary>>,
                    Route_root,
                    Rally_package_path,
                    <<<<"src/"/utf8, Namespace/binary>>/binary,
                        "/shell.html"/utf8>>,
                    Server_deps,
                    Protocol@1}}
        end
    ).

-file("src/rally.gleam", 1279).
-spec tom_error_to_string(tom:parse_error()) -> binary().
tom_error_to_string(E) ->
    case E of
        {unexpected, Got, Expected} ->
            <<<<<<"unexpected character '"/utf8, Got/binary>>/binary,
                    "', expected "/utf8>>/binary,
                Expected/binary>>;

        {key_already_in_use, Key} ->
            <<"duplicate key: "/utf8,
                (gleam@string:join(Key, <<"."/utf8>>))/binary>>
    end.

-file("src/rally.gleam", 55).
-spec read_configs() -> {ok, list(rally@types:scan_config())} |
    {error, rally_error()}.
read_configs() ->
    gleam@result:'try'(
        begin
            _pipe = simplifile:read(<<"gleam.toml"/utf8>>),
            gleam@result:map_error(
                _pipe,
                fun(E) ->
                    {rally_error,
                        <<"Cannot read gleam.toml: "/utf8,
                            (simplifile:describe_error(E))/binary>>}
                end
            )
        end,
        fun(Toml_str) ->
            gleam@result:'try'(
                begin
                    _pipe@1 = tom:parse(Toml_str),
                    gleam@result:map_error(
                        _pipe@1,
                        fun(E@1) ->
                            {rally_error,
                                <<"Invalid gleam.toml: "/utf8,
                                    (tom_error_to_string(E@1))/binary>>}
                        end
                    )
                end,
                fun(Toml_map) ->
                    Rally_config = begin
                        _pipe@2 = tom:get_table(
                            Toml_map,
                            [<<"tools"/utf8>>, <<"rally"/utf8>>]
                        ),
                        gleam@result:unwrap(_pipe@2, maps:new())
                    end,
                    Server_deps = begin
                        _pipe@3 = tom:get_table(
                            Toml_map,
                            [<<"dependencies"/utf8>>]
                        ),
                        gleam@result:unwrap(_pipe@3, maps:new())
                    end,
                    Rally_package_path = (case gleam_stdlib:map_get(
                        Server_deps,
                        <<"rally"/utf8>>
                    ) of
                        {ok, {inline_table, Rally_dep}} ->
                            case gleam_stdlib:map_get(
                                Rally_dep,
                                <<"path"/utf8>>
                            ) of
                                {ok, {string, Path}} ->
                                    Path;

                                _ ->
                                    <<".."/utf8>>
                            end;

                        {ok, {table, Rally_dep}} ->
                            case gleam_stdlib:map_get(
                                Rally_dep,
                                <<"path"/utf8>>
                            ) of
                                {ok, {string, Path}} ->
                                    Path;

                                _ ->
                                    <<".."/utf8>>
                            end;

                        _ ->
                            <<".."/utf8>>
                    end),
                    case tom:get_array(Rally_config, [<<"clients"/utf8>>]) of
                        {ok, Clients} ->
                            gleam@result:'try'(
                                gleam@list:try_map(
                                    Clients,
                                    fun(Client) -> case Client of
                                            {table, Cfg} ->
                                                read_client_config(
                                                    Cfg,
                                                    Server_deps,
                                                    Rally_package_path
                                                );

                                            {inline_table, Cfg} ->
                                                read_client_config(
                                                    Cfg,
                                                    Server_deps,
                                                    Rally_package_path
                                                );

                                            _ ->
                                                {error,
                                                    {rally_error,
                                                        <<"Each [[tools.rally.clients]] entry must be a table"/utf8>>}}
                                        end end
                                ),
                                fun(Configs) -> case Configs of
                                        [] ->
                                            {ok,
                                                [read_legacy_config(
                                                        Rally_config,
                                                        Server_deps,
                                                        Rally_package_path
                                                    )]};

                                        _ ->
                                            {ok, Configs}
                                    end end
                            );

                        _ ->
                            {ok,
                                [read_legacy_config(
                                        Rally_config,
                                        Server_deps,
                                        Rally_package_path
                                    )]}
                    end
                end
            )
        end
    ).

-file("src/rally.gleam", 237).
-spec run(list(binary())) -> {ok, binary()} | {error, rally_error()}.
run(Args) ->
    case Args of
        [<<"init"/utf8>>] ->
            gleam@result:'try'(
                begin
                    _pipe = rally@init:init_project(<<"."/utf8>>),
                    gleam@result:map_error(
                        _pipe,
                        fun(Msg) ->
                            {rally_error, <<"init error: "/utf8, Msg/binary>>}
                        end
                    )
                end,
                fun(_use0) ->
                    nil = _use0,
                    {ok, <<"initialized project"/utf8>>}
                end
            );

        [] ->
            gleam@result:'try'(
                read_configs(),
                fun(Configs) ->
                    gleam@result:'try'(
                        gleam@list:try_each(Configs, fun generate_for_config/1),
                        fun(_use0@1) ->
                            nil = _use0@1,
                            {ok,
                                <<(erlang:integer_to_binary(
                                        erlang:length(Configs)
                                    ))/binary,
                                    " client(s)"/utf8>>}
                        end
                    )
                end
            );

        [<<"gen"/utf8>>] ->
            gleam@result:'try'(
                read_configs(),
                fun(Configs) ->
                    gleam@result:'try'(
                        gleam@list:try_each(Configs, fun generate_for_config/1),
                        fun(_use0@1) ->
                            nil = _use0@1,
                            {ok,
                                <<(erlang:integer_to_binary(
                                        erlang:length(Configs)
                                    ))/binary,
                                    " client(s)"/utf8>>}
                        end
                    )
                end
            );

        _ ->
            {error,
                {rally_error,
                    <<"Unknown command. Run `gleam run -m rally` for codegen or `gleam run -m rally init` to scaffold the current project."/utf8>>}}
    end.

-file("src/rally.gleam", 41).
-spec main() -> nil.
main() ->
    Args = erlang:element(4, argv:load()),
    case run(Args) of
        {ok, Msg} ->
            gleam_stdlib:println(<<"rally: "/utf8, Msg/binary>>);

        {error, {rally_error, Msg@1}} ->
            gleam_stdlib:println_error(<<"rally error: "/utf8, Msg@1/binary>>),
            erlang:halt(1)
    end.