-module(illustrious@server). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([build_app/1, handle_request/5]). -export_type([server_app_builder/4, server_result/1, server_app/4, api_request/0]). -type server_app_builder(OTN, OTO, OTP, OTQ) :: {server_app_builder, fun((list(binary()), OTO) -> gleam@option:option(lustre@internals@vdom:element(illustrious@state:illustrious_action(OTP)))), OTO, fun((OTO, OTP) -> {OTO, lustre@effect:effect(illustrious@state:illustrious_action(OTP))}), fun((gleam@dynamic:dynamic_()) -> {ok, illustrious@state:illustrious_action(OTP)} | {error, list(gleam@dynamic:decode_error())}), fun((list(binary()), OTN) -> {ok, gleam@json:json()} | {error, OTQ}), fun((list(binary()), OTN) -> {ok, gleam@json:json()} | {error, OTQ}), fun((OTQ) -> binary())}. -type server_result(OTR) :: {view, lustre@internals@vdom:element(illustrious@state:illustrious_action(OTR))} | {data, gleam@json:json()} | {server_error, binary()} | no_result. -opaque server_app(OTS, OTT, OTU, OTV) :: {server_app, fun((list(binary()), OTT) -> gleam@option:option(lustre@internals@vdom:element(illustrious@state:illustrious_action(OTU)))), OTT, fun((illustrious@state:illustrious_model(OTT), illustrious@state:illustrious_action(OTU)) -> {illustrious@state:illustrious_model(OTT), lustre@effect:effect(illustrious@state:illustrious_action(OTU))}), fun((gleam@dynamic:dynamic_()) -> {ok, illustrious@state:illustrious_action(OTU)} | {error, list(gleam@dynamic:decode_error())}), fun((list(binary()), OTS) -> {ok, gleam@json:json()} | {error, OTV}), fun((list(binary()), OTS) -> {ok, gleam@json:json()} | {error, OTV}), fun((OTV) -> binary())}. -type api_request() :: {api_request, binary()}. -spec build_app(server_app_builder(OUE, OUF, OUG, OUH)) -> server_app(OUE, OUF, OUG, OUH). build_app(Builder) -> Updater = illustrious@internal@state_priv:wrap_updater( erlang:element(4, Builder), erlang:element(5, Builder) ), {server_app, erlang:element(2, Builder), erlang:element(3, Builder), Updater, erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder)}. -spec api_request_decoder(binary()) -> {ok, api_request()} | {error, gleam@json:decode_error()}. api_request_decoder(Json) -> gleam@json:decode( Json, gleam@dynamic:decode1( fun(Field@0) -> {api_request, Field@0} end, gleam@dynamic:field(<<"path"/utf8>>, fun gleam@dynamic:string/1) ) ). -spec serialize_json_decode_error(gleam@json:decode_error()) -> binary(). serialize_json_decode_error(_) -> <<"Failed to deserialize request"/utf8>>. -spec wrap_element( lustre@internals@vdom:element(illustrious@state:illustrious_action(OVC)), binary() ) -> lustre@internals@vdom:element(illustrious@state:illustrious_action(OVC)). wrap_element(Children, Baked_data) -> lustre@element@html:html( [], [lustre@element@html:head( [], [lustre@element@html:title([], <<"Illustrious"/utf8>>), lustre@element@html:link( [lustre@attribute:rel(<<"stylesheet"/utf8>>), lustre@attribute:type_(<<"text/css"/utf8>>), lustre@attribute:href(<<"/static/client.css"/utf8>>)] )] ), lustre@element@html:body( [], [lustre@element@html:'div'( [lustre@attribute:id(<<"app"/utf8>>)], [Children] ), lustre@element@html:script( [lustre@attribute:id(<<"illustrious_baked_data"/utf8>>), lustre@attribute:type_(<<"application/json"/utf8>>)], Baked_data ), lustre@element@html:script( [lustre@attribute:src(<<"/static/client.mjs"/utf8>>), lustre@attribute:type_(<<"module"/utf8>>)], <<""/utf8>> )] )] ). -spec handle_request( server_app(OUN, any(), OUP, any()), gleam@http:method(), list(binary()), binary(), OUN ) -> server_result(OUP). handle_request(App, Method, Path, Body, Context) -> case {Method, Path} of {post, [<<"illustrious_api"/utf8>>]} -> case api_request_decoder(Body) of {error, Decode_error} -> {server_error, serialize_json_decode_error(Decode_error)}; {ok, Req} -> Path@1 = illustrious@internal@router:parse_path( erlang:element(2, Req) ), case (erlang:element(7, App))(Path@1, Context) of {error, Err} -> {server_error, (erlang:element(8, App))(Err)}; {ok, Json} -> {data, Json} end end; {get, Path@2} -> Init_result = (erlang:element(6, App))(Path@2, Context), case Init_result of {error, Error} -> {server_error, (erlang:element(8, App))(Error)}; {ok, Json@1} -> gleam@io:print(<<"initializer"/utf8>>), Json_str = gleam@io:debug(gleam@json:to_string(Json@1)), Model@1 = case gleam@json:decode( Json_str, gleam@dynamic:list(erlang:element(5, App)) ) of {ok, Actions} -> gleam@list:fold( Actions, {illustrious_model, Path@2, erlang:element(3, App)}, fun(Model, Action) -> erlang:element( 1, (erlang:element(4, App))(Model, Action) ) end ); _ -> _assert_subject = gleam@json:decode( Json_str, erlang:element(5, App) ), {ok, Action@1} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"illustrious/server"/utf8>>, function => <<"handle_request"/utf8>>, line => 151}) end, erlang:element( 1, (erlang:element(4, App))( {illustrious_model, Path@2, erlang:element(3, App)}, Action@1 ) ) end, case (erlang:element(2, App))( erlang:element(2, Model@1), erlang:element(3, Model@1) ) of {some, Element} -> {view, wrap_element(Element, Json_str)}; none -> no_result end end; {_, _} -> no_result end.