Current section

Files

Jump to
inlay src inlay@bluesky.erl
Raw

src/inlay@bluesky.erl

-module(inlay@bluesky).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/inlay/bluesky.gleam").
-export([detect/1, fallback_view/2, resolved_view/3, render/2, needs_resolution/1, did_decoder/0, resolve_effect/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/inlay/bluesky.gleam", 110).
-spec detect_bluesky(gleam@uri:uri()) -> gleam@option:option(inlay@embed:embed()).
detect_bluesky(Url) ->
case gleam@uri:path_segments(erlang:element(6, Url)) of
[<<"profile"/utf8>>, Handle, <<"post"/utf8>>, Rkey] ->
{some, {bluesky_post, Handle, Rkey}};
_ ->
none
end.
-file("src/inlay/bluesky.gleam", 12).
-spec detect(gleam@uri:uri()) -> gleam@option:option(inlay@embed:embed()).
detect(Url) ->
case erlang:element(4, Url) of
{some, <<"bsky.app"/utf8>>} ->
detect_bluesky(Url);
_ ->
none
end.
-file("src/inlay/bluesky.gleam", 94).
-spec post_url(binary(), binary()) -> binary().
post_url(Handle, Rkey) ->
<<<<<<"https://bsky.app/profile/"/utf8, Handle/binary>>/binary,
"/post/"/utf8>>/binary,
Rkey/binary>>.
-file("src/inlay/bluesky.gleam", 60).
?DOC(
" Render a plain link to a Bluesky post, used when the handle cannot be\n"
" resolved to a DID.\n"
).
-spec fallback_view(binary(), binary()) -> lustre@vdom@vnode:element(any()).
fallback_view(Handle, Rkey) ->
Post_url = post_url(Handle, Rkey),
lustre@element@html:'div'(
[],
[lustre@element@html:blockquote(
[lustre@attribute:class(<<"bluesky-embed"/utf8>>)],
[lustre@element@html:a(
[lustre@attribute:href(Post_url)],
[lustre@element:text(Post_url)]
)]
)]
).
-file("src/inlay/bluesky.gleam", 32).
?DOC(
" Render the rich Bluesky embed for a post whose handle has been resolved to a\n"
" DID. Includes the `embed.js` script that hydrates the blockquote.\n"
).
-spec resolved_view(binary(), binary(), binary()) -> lustre@vdom@vnode:element(any()).
resolved_view(Handle, Did, Rkey) ->
Post_url = post_url(Handle, Rkey),
At_uri = <<<<<<"at://"/utf8, Did/binary>>/binary,
"/app.bsky.feed.post/"/utf8>>/binary,
Rkey/binary>>,
lustre@element@html:'div'(
[],
[lustre@element@html:blockquote(
[lustre@attribute:class(<<"bluesky-embed"/utf8>>),
lustre@attribute:attribute(
<<"data-bluesky-uri"/utf8>>,
At_uri
)],
[lustre@element@html:a(
[lustre@attribute:href(Post_url)],
[lustre@element:text(Post_url)]
)]
),
lustre@element@html:script(
[lustre@attribute:src(
<<"https://embed.bsky.app/static/embed.js"/utf8>>
),
lustre@attribute:attribute(
<<"async"/utf8>>,
<<"true"/utf8>>
),
lustre@attribute:attribute(
<<"charset"/utf8>>,
<<"utf-8"/utf8>>
)],
<<""/utf8>>
)]
).
-file("src/inlay/bluesky.gleam", 98).
-spec resolve_handle(binary(), inlay@embed:config()) -> {ok, binary()} |
{error, nil}.
resolve_handle(Handle, Config) ->
case gleam_stdlib:string_starts_with(Handle, <<"did:"/utf8>>) of
true ->
{ok, Handle};
false ->
case erlang:element(7, Config) of
{some, {bluesky_config, {some, Resolver}, _}} ->
Resolver(Handle);
_ ->
{error, nil}
end
end.
-file("src/inlay/bluesky.gleam", 19).
-spec render(inlay@embed:embed(), inlay@embed:config()) -> {ok,
lustre@vdom@vnode:element(any())} |
{error, nil}.
render(Embed, Config) ->
case Embed of
{bluesky_post, Handle, Rkey} ->
case resolve_handle(Handle, Config) of
{ok, Did} ->
{ok, resolved_view(Handle, Did, Rkey)};
{error, _} ->
{ok, fallback_view(Handle, Rkey)}
end;
_ ->
{error, nil}
end.
-file("src/inlay/bluesky.gleam", 71).
?DOC(
" Whether a Bluesky handle needs a network round-trip to resolve to a DID. A\n"
" handle already in `did:` form renders synchronously and needs no resolution.\n"
).
-spec needs_resolution(binary()) -> boolean().
needs_resolution(Handle) ->
not gleam_stdlib:string_starts_with(Handle, <<"did:"/utf8>>).
-file("src/inlay/bluesky.gleam", 89).
?DOC(" Decode the `did` field from a Bluesky `resolveHandle` response.\n").
-spec did_decoder() -> gleam@dynamic@decode:decoder(binary()).
did_decoder() ->
gleam@dynamic@decode:field(
<<"did"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Did) -> gleam@dynamic@decode:success(Did) end
).
-file("src/inlay/bluesky.gleam", 78).
?DOC(
" Resolve a Bluesky handle to a DID over the network, turning the result into a\n"
" message with `to_msg`. Cross-target: uses `fetch` on JavaScript and `httpc`\n"
" on Erlang.\n"
).
-spec resolve_effect(
binary(),
fun(({ok, binary()} | {error, rsvp:error(binary())}) -> RIY)
) -> lustre@effect:effect(RIY).
resolve_effect(Handle, To_msg) ->
Url = <<"https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle="/utf8,
Handle/binary>>,
rsvp:get(Url, rsvp:expect_json(did_decoder(), To_msg)).