Current section
Files
Jump to
Current section
Files
src/sprocket.erl
-module(sprocket).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/5, handle_ws/2, cleanup/1, render/2]).
-export_type([sprocket_opts/0, sprocket/1, payload/0, response/1, connect_error/0]).
-type sprocket_opts() :: {sprocket_opts, boolean()}.
-type sprocket(LEA) :: {sprocket,
fun((sprocket@context:context(), LEA) -> {sprocket@context:context(),
sprocket@context:element()}),
fun((gleam@option:option(list({binary(), binary()}))) -> LEA),
gleam@option:option(gleam@erlang@process:subject(sprocket@runtime:message())),
fun((binary()) -> {ok, nil} | {error, nil}),
fun((binary()) -> {ok, nil} | {error, nil}),
gleam@option:option(sprocket_opts())}.
-type payload() :: {join_payload,
binary(),
gleam@option:option(gleam@dict:dict(binary(), binary()))} |
{event_payload, binary(), binary(), gleam@dynamic:dynamic_()} |
{hook_event_payload,
binary(),
binary(),
binary(),
gleam@option:option(gleam@dynamic:dynamic_())} |
{empty_payload, gleam@option:option(binary())}.
-type response(LEB) :: {joined, sprocket(LEB)} | empty.
-type connect_error() :: connect_error |
preflight_not_found |
invalid_csrf_token.
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 40).
-spec new(
fun((sprocket@context:context(), LEH) -> {sprocket@context:context(),
sprocket@context:element()}),
fun((gleam@option:option(list({binary(), binary()}))) -> LEH),
fun((binary()) -> {ok, nil} | {error, nil}),
fun((binary()) -> {ok, nil} | {error, nil}),
gleam@option:option(sprocket_opts())
) -> sprocket(LEH).
new(Component, Initialize_props, Ws_send, Csrf_validator, Opts) ->
{sprocket, Component, Initialize_props, none, Ws_send, Csrf_validator, Opts}.
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 158).
-spec require_runtime(
sprocket(any()),
fun((gleam@erlang@process:subject(sprocket@runtime:message())) -> {ok, LET} |
{error, binary()})
) -> {ok, LET} | {error, binary()}.
require_runtime(Spkt, Cb) ->
case Spkt of
{sprocket, _, _, {some, Runtime}, _, _, _} ->
Cb(Runtime);
_ ->
{error,
<<"Sprocket runtime not found. Runtime must be started before handling messages"/utf8>>}
end.
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 212).
-spec decode_join(gleam@dynamic:dynamic_()) -> {ok, {binary(), payload()}} |
{error, list(gleam@dynamic:decode_error())}.
decode_join(Data) ->
_pipe = Data,
(gleam@dynamic:tuple2(
fun gleam@dynamic:string/1,
gleam@dynamic:decode2(
fun(Field@0, Field@1) -> {join_payload, Field@0, Field@1} end,
gleam@dynamic:field(<<"csrf"/utf8>>, fun gleam@dynamic:string/1),
gleam@dynamic:optional_field(
<<"initialProps"/utf8>>,
gleam@dynamic:dict(
fun gleam@dynamic:string/1,
fun gleam@dynamic:string/1
)
)
)
))(_pipe).
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 227).
-spec decode_event(gleam@dynamic:dynamic_()) -> {ok, {binary(), payload()}} |
{error, list(gleam@dynamic:decode_error())}.
decode_event(Data) ->
_pipe = Data,
(gleam@dynamic:tuple2(
fun gleam@dynamic:string/1,
gleam@dynamic:decode3(
fun(Field@0, Field@1, Field@2) -> {event_payload, Field@0, Field@1, Field@2} end,
gleam@dynamic:field(<<"id"/utf8>>, fun gleam@dynamic:string/1),
gleam@dynamic:field(<<"kind"/utf8>>, fun gleam@dynamic:string/1),
gleam@dynamic:field(<<"payload"/utf8>>, fun gleam@dynamic:dynamic/1)
)
))(_pipe).
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 240).
-spec decode_hook_event(gleam@dynamic:dynamic_()) -> {ok, {binary(), payload()}} |
{error, list(gleam@dynamic:decode_error())}.
decode_hook_event(Data) ->
_pipe = Data,
(gleam@dynamic:tuple2(
fun gleam@dynamic:string/1,
gleam@dynamic:decode4(
fun(Field@0, Field@1, Field@2, Field@3) -> {hook_event_payload, Field@0, Field@1, Field@2, Field@3} end,
gleam@dynamic:field(<<"id"/utf8>>, fun gleam@dynamic:string/1),
gleam@dynamic:field(<<"hook"/utf8>>, fun gleam@dynamic:string/1),
gleam@dynamic:field(<<"kind"/utf8>>, fun gleam@dynamic:string/1),
gleam@dynamic:optional_field(
<<"payload"/utf8>>,
fun gleam@dynamic:dynamic/1
)
)
))(_pipe).
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 254).
-spec decode_empty(gleam@dynamic:dynamic_()) -> {ok, {binary(), payload()}} |
{error, list(gleam@dynamic:decode_error())}.
decode_empty(Data) ->
_pipe = Data,
(gleam@dynamic:tuple2(
fun gleam@dynamic:string/1,
gleam@dynamic:decode1(
fun(Field@0) -> {empty_payload, Field@0} end,
gleam@dynamic:optional_field(
<<"nothing"/utf8>>,
fun gleam@dynamic:string/1
)
)
))(_pipe).
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 262).
-spec update_to_json(sprocket@runtime:rendered_update(), boolean()) -> gleam@json:json().
update_to_json(Update, Debug) ->
case Update of
{patch_update, P} ->
gleam@json:preprocessed_array(
[gleam@json:string(<<"update"/utf8>>),
sprocket@internal@patch:patch_to_json(P, Debug),
gleam@json:object(
[{<<"debug"/utf8>>, gleam@json:bool(Debug)}]
)]
);
{full_update, Update@1} ->
sprocket@render:renderer(
sprocket@renderers@json:json_renderer(),
fun(Render_json) ->
gleam@json:preprocessed_array(
[gleam@json:string(<<"ok"/utf8>>),
Render_json(Update@1)]
)
end
)
end.
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 279).
-spec hook_emit_to_json(
binary(),
binary(),
binary(),
gleam@option:option(binary())
) -> binary().
hook_emit_to_json(Id, Hook, Kind, Payload) ->
_pipe = gleam@json:preprocessed_array(
[gleam@json:string(<<"hook:emit"/utf8>>), case Payload of
{some, Payload@1} ->
gleam@json:object(
[{<<"id"/utf8>>, gleam@json:string(Id)},
{<<"hook"/utf8>>, gleam@json:string(Hook)},
{<<"kind"/utf8>>, gleam@json:string(Kind)},
{<<"payload"/utf8>>, gleam@json:string(Payload@1)}]
);
none ->
gleam@json:object(
[{<<"id"/utf8>>, gleam@json:string(Id)},
{<<"hook"/utf8>>, gleam@json:string(Hook)},
{<<"kind"/utf8>>, gleam@json:string(Kind)}]
)
end]
),
gleam@json:to_string(_pipe).
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 172).
-spec connect(sprocket(any()), gleam@option:option(list({binary(), binary()}))) -> {ok,
gleam@erlang@process:subject(sprocket@runtime:message())} |
{error, nil}.
connect(Spkt, Initial_props) ->
Debug = begin
_pipe = gleam@option:map(
erlang:element(7, Spkt),
fun(Opts) -> erlang:element(2, Opts) end
),
gleam@option:unwrap(_pipe, false)
end,
Updater = {updater, fun(Update) -> _pipe@1 = update_to_json(Update, Debug),
_pipe@2 = gleam@json:to_string(_pipe@1),
(erlang:element(5, Spkt))(_pipe@2) end},
Emitter = fun(Element_id, Hook, Kind, Payload) ->
_ = begin
_pipe@3 = hook_emit_to_json(Element_id, Hook, Kind, Payload),
(erlang:element(5, Spkt))(_pipe@3)
end,
{ok, nil}
end,
View = sprocket@component:component(
erlang:element(2, Spkt),
(erlang:element(3, Spkt))(Initial_props)
),
case sprocket@runtime:start(View, Updater, {some, Emitter}) of
{ok, R} ->
sprocket@runtime:render_update(R),
{ok, R};
{error, _} ->
sprocket@internal@logger:error(<<"Error starting runtime"/utf8>>),
{error, nil}
end.
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 312).
-spec error_to_json(connect_error()) -> binary().
error_to_json(Error) ->
_pipe = gleam@json:preprocessed_array(
[gleam@json:string(<<"error"/utf8>>), case Error of
connect_error ->
gleam@json:object(
[{<<"code"/utf8>>,
gleam@json:string(<<"connect_error"/utf8>>)},
{<<"msg"/utf8>>,
gleam@json:string(
<<"Unable to connect to session"/utf8>>
)}]
);
preflight_not_found ->
gleam@json:object(
[{<<"code"/utf8>>,
gleam@json:string(
<<"preflight_not_found"/utf8>>
)},
{<<"msg"/utf8>>,
gleam@json:string(<<"No preflight found"/utf8>>)}]
);
invalid_csrf_token ->
gleam@json:object(
[{<<"code"/utf8>>,
gleam@json:string(<<"invalid_csrf_token"/utf8>>)},
{<<"msg"/utf8>>,
gleam@json:string(<<"Invalid CSRF token"/utf8>>)}]
)
end]
),
gleam@json:to_string(_pipe).
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 81).
-spec handle_ws(sprocket(LEM), binary()) -> {ok, response(LEM)} |
{error, binary()}.
handle_ws(Spkt, Msg) ->
case gleam@json:decode(
Msg,
gleam@dynamic:any(
[fun decode_join/1,
fun decode_hook_event/1,
fun decode_event/1,
fun decode_empty/1]
)
) of
{ok, {<<"join"/utf8>>, {join_payload, Csrf, Initial_props}}} ->
case (erlang:element(6, Spkt))(Csrf) of
{ok, _} ->
case connect(
Spkt,
gleam@option:map(Initial_props, fun maps:to_list/1)
) of
{ok, Runtime} ->
{ok,
{joined,
erlang:setelement(4, Spkt, {some, Runtime})}};
{error, _} ->
{error, <<"Error connecting to runtime"/utf8>>}
end;
{error, _} ->
sprocket@internal@logger:error(
<<"Invalid CSRF token"/utf8>>
),
_ = begin
_pipe = invalid_csrf_token,
_pipe@1 = error_to_json(_pipe),
(erlang:element(5, Spkt))(_pipe@1)
end,
{error, <<"Invalid CSRF token"/utf8>>}
end;
{ok,
{<<"hook:event"/utf8>>,
{hook_event_payload, Element_id, Hook_name, Kind, Payload}}} ->
sprocket@internal@logger:debug(
<<<<<<<<<<"Hook Event: element "/utf8, Element_id/binary>>/binary,
" "/utf8>>/binary,
Hook_name/binary>>/binary,
" "/utf8>>/binary,
Kind/binary>>
),
require_runtime(
Spkt,
fun(Runtime@1) ->
Reply_emitter = fun(Kind@1, Payload@1) ->
_ = begin
_pipe@2 = hook_emit_to_json(
Element_id,
Hook_name,
Kind@1,
Payload@1
),
_pipe@3 = (erlang:element(5, Spkt))(_pipe@2),
gleam@result:map_error(
_pipe@3,
fun(E) ->
sprocket@internal@logger:error_meta(
<<"Error sending hook event reply"/utf8>>,
E
)
end
)
end,
nil
end,
sprocket@runtime:process_client_hook(
Runtime@1,
Element_id,
Hook_name,
Kind,
Payload,
Reply_emitter
),
{ok, empty}
end
);
{ok,
{<<"event"/utf8>>, {event_payload, Element_id@1, Kind@2, Payload@2}}} ->
sprocket@internal@logger:debug(
<<<<<<"Event: element "/utf8, Element_id@1/binary>>/binary,
" "/utf8>>/binary,
Kind@2/binary>>
),
require_runtime(
Spkt,
fun(Runtime@2) ->
sprocket@runtime:process_event(
Runtime@2,
Element_id@1,
Kind@2,
Payload@2
),
{ok, empty}
end
);
{error, _} ->
sprocket@internal@logger:error(
<<"Error decoding message: "/utf8, Msg/binary>>
),
{error, <<"Error decoding message"/utf8>>};
_ ->
sprocket@internal@logger:error(
<<"Unexpected payload type: "/utf8, Msg/binary>>
),
{error, <<"Unexpected payload type"/utf8>>}
end.
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 340).
-spec cleanup(sprocket(any())) -> gleam@option:option(nil).
cleanup(Spkt) ->
_pipe = erlang:element(4, Spkt),
gleam@option:map(_pipe, fun(R) -> sprocket@runtime:stop(R) end).
-file("/home/runner/work/sprocket/sprocket/src/sprocket.gleam", 346).
-spec render(sprocket@context:element(), sprocket@render:renderer(LFN)) -> LFN.
render(El, R) ->
sprocket@render:renderer(
R,
fun(Render) ->
_assert_subject = begin
_pipe = ids@cuid:start(),
gleam@result:map_error(
_pipe,
fun(Error) ->
sprocket@internal@logger:error(
<<"render.render: Failed to start cuid channel"/utf8>>
),
Error
end
)
end,
{ok, Cuid_channel} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"sprocket"/utf8>>,
function => <<"render"/utf8>>,
line => 351})
end,
Render_update = fun() -> nil end,
Update_hook = fun(_, _) -> nil end,
Ctx = sprocket@context:new(
El,
Cuid_channel,
none,
Render_update,
Update_hook
),
{reconciled_result, _, Reconciled} = sprocket@internal@reconcilers@recursive:reconcile(
Ctx,
El,
none,
none
),
Render(Reconciled)
end
).