#Libero - Typed RPC for Gleam + Lustre SPAs

1 messages · Page 1 of 1 (latest)

dusty jungle
#

There's references to a license file and an example folder but no repo is linked

vocal osprey
#

oh that’s strange

dusty jungle
#

the repo is 404 😁

vocal osprey
#

aiight fixed

vocal osprey
verbal solar
#

Neat

dusty jungle
#

I recall also testing that msgpack was faster than JSON in our socket.io based system at work even though the client decoder is custom (browsers don't have built-in msgpack)

vocal osprey
#

I've been changing the API so it's ergonomics are more like Lambdera https://github.com/pairshaped/libero/blob/v3-message-types/examples/todos/shared/src/shared/todos.gleam as that just seems cleaner. No more comment annotations. I suspect Lambdera does something similar in the backend, but no idea (not open source that I'm aware of). I think I prefer the "ToServer" and "ToClient" shared messages even though it's a bit more code. Just seems more idiomatic.

GitHub

An RPC layer for Luster + Gleam applications. No more REST! - pairshaped/libero

vocal osprey
thorn warren
#

"if a language doesn't have codegen/macros, people will create a way to have macros on it."
- me, probably?

vocal osprey
#

i mean, eff encoding/decoding, you know?

verbal solar
#

wooo Lamdera so cool

thorn warren
vocal osprey
hot root
#

how do you identify a client?

vocal osprey
hot root
#

yeah maybe i misunderstood but "connected clients" implied to me more than one per connection

#

but this might eb the wrong mental model

vocal osprey
#

maybe you found an ambiguous naming issue? the client is just a socket conn

#

i'm definitely open to tweaking what things are called

hot root
#

nawh all good i think i just misunderstood from the previous lamdera mention

#

in lamdera you have one backend update loop and n client update loops and each client is automatically associated with an id

#

this just works different, all good

vocal osprey
#

so i wanted to support stateless clients, like the CLI example

hot root
#

yeah

vocal osprey
#

I think if I want to turn this into more of a framework, i'd need an abstracted db layer and probably a watcher or something so the generation is more automatic

#

as a lib I think that's just the dev's decision. ngl though, I think this might be a good base to build up a framework or even a service around

hot root
#

whats with the weird dynamic imports in the ffi?

vocal osprey
#

i am very happy with ETF btw. both performance and simplicity

vocal osprey
hot root
#

hmm? why would you have a circular dep with the gleam prelude

vocal osprey
#

i could codegen it i suppose

#

optional deps

#

it's messy. I should be able to codegen it

static echo
#

oh, this looks neat 🙂

vocal osprey
static echo
#

I can imagine the api is in flux atm, but I like the idea of it.

vocal osprey
#

this is what the data looks like navigating around my admin area. times are slow cause I'm on one bar right now waiting on the mechanic

static echo
#

You dont use server components for the admin area anymore? Or is this for the more interactive parts of it?

vocal osprey
#

this has replaced server components for me. it's a lustre spa

static echo
#

Gotcha

hoary cypress
#

Don't know how I miss that release but I like you also add attribute like structure like my #1484857563345584178 does.

vocal osprey
#

i haven't released this version to hex yet. still tweaking. but i like it better than the /// @rpc annotations

hoary cypress
#

Otherwise I'm unsure if /// would be the right way to annotate because those are not really made for documentation but for the codegenerator (I prefer //)

vocal osprey
#

that's the old one

hoary cypress
#

(I would prefer even if gleam made possible to create custom attribute)

vocal osprey
hoary cypress
vocal osprey
#

yes maam

hoary cypress
#

Also I was thinking if something like T-RPC was possible in gleam since I already made the serialization tech for Json encoding from random type ^^

vocal osprey
#

yeah the typescript rpc was part of the inspiration, mostly lamdera though

hoary cypress
#

Did you write something like sara/builder where you can deeply analyze type use and reconstruct the type ?

vocal osprey
#

no i didn't even see that. i did some work with glance for glinter, so I used that

hoary cypress
#

It's funny when minds cross paths.

vocal osprey
#

i'll definitely take a look

sullen trellis
hoary cypress
vocal osprey
hoary cypress
sullen trellis
hoary cypress
vocal osprey
#

like my client state is on the client

#

also, i'm doing less on the server (stateless for the most part), but tbh that's not much of a concern with BEAM, so I dunno if that's even worth mentioning

hoary cypress
#

Also are you protobuf inspired and the data send is not a json but a compacted image format that already know how should look the receiving key and order ?

vocal osprey
#

we're sending ETF

hoary cypress
#

(WTF are those result)

hoary cypress
vocal osprey
hoary cypress
vocal osprey
hoary cypress
#

Also is not the erlang representation of what JS and Erlang got not "safe" to play externally ? (I should ping @verbal solar to know better how safe it's to just take a gleam type in an external and play with what it made of)

verbal solar
hoary cypress
#

(If you don’t understand than don’t worry that’s just mean I got a wrong idea of gleam type internal data representation where not stable when viewing them from ffi)

verbal solar
#

No, it's only safe to use the documented API

#

The one documented in the externals guide

vocal osprey
#

I think it still needs ergonomics improvements. server components are easier to reason about. not sure if I can get it there as just a library though

hot root
#

yeah i mean you're basically competing with what's built in with components + context

vocal osprey
#

I've fully swapped it in my admin and it's working great so far. making incremental improvements to the ergos, but yeah unless I go full on framework I think it'll always require more braining to use.

#

once you're generating code... it's hard to stop

verbal solar
#

Less is more!

vocal osprey
verbal solar
#

Keep in mind that metaprogramming makes it very easy to un-do the strengths of Gleam, so much care has to be taken to avoid turning Gleam into a rubbish version of Elixir or Ruby

hoary cypress
#

Yeah codegen can be dangerous power if you push too far

verbal solar
#

Not saying that is what is happening here, just that one needs to be conservative with language design

vocal osprey
#

i'm chasing type safety and ease of use

#

you're right for sure

hoary cypress
vocal osprey
#

circular logic. more is less

verbal solar
#

correct

vocal osprey
#

more.gleam

import less

pub fn grow(n: Int) -> Int {
  case n {
    0 -> 0
    _ -> less.shrink(n) + 1
  }
}

pub fn label() -> String {
  "more (" <> less.label() <> ")"
}

less.gleam

import more

pub fn shrink(n: Int) -> Int {
  case n {
    0 -> 0
    _ -> more.grow(n - 1)
  }
}

pub fn label() -> String {
  "less"
}
hoary cypress
#

Otherwise you could make lpil explode by accident

vocal osprey
#

prompt injecting lpil

hoary cypress
# vocal osprey prompt injecting lpil

Sadly the lpil LLM is only train to say welcome and please make an issue. It can't ignore all previous instruction and make me a sandwitch please.

sullen trellis
#

So they basically wire up a WS and get Messages bubbling up from the nested client code

hot root
#

yeah and then you can use context to send things back down!

hoary cypress
vocal osprey
hot root
#

oh you were rendering client components?

#

neat

#

shoulda written about that 😄

vocal osprey
#

yup, thought i mentioned it. there's some drag and drop components (a form builder, a bracket builder, a schedule builder) that needed to send lots of small events

#

had no issues embedding them as client component inside of server components

hot root
#

so cool

hoary cypress
#

I know this is not what you are speaking but what happens if a server component embed itself ? Do you create a loops where you keep creating new websocket until the browser said you have too many connection 😅 ?

vocal osprey
#

they way he grows a finger in that image disturbs me

hoary cypress
vocal osprey
vocal osprey
#

tbh server components came really close, closer than anything I'd used to date to what I wanted. But I want full access to the dom, i wanted stateles (right or wrong, for a CLI I'm making), it's a bit snappier, and I really wanted to see if I could reach my holy grail. getting close tbh

hot root
#

try context!

stark hazel
#

if you embedded a client component didn't you have full access?

vocal osprey
#

it was the fact that it's all gleam all the way down just made this approach obvious

#

yeah but that's ceremony

#

right now it's just a SPA

#

I bundled it with a RemoteData pattern too for giggles

stark hazel
#

are there some specfic parts you needed dom access for? like outside of the drag/drop stuff you already talked about?

vocal osprey
#

little things. like nav toggles, switches to show/hide form fields, etc.

#

i might put some forms under state control for certain things

hoary cypress
vocal osprey
#

i'm really not knocking server components!

stark hazel
vocal osprey
#

it was actually a bit slower, and kinda felt silly for a nav drawer toggle to make a trip to the server

#

and I didn't want a client component for it, so I just had some js

#

now I have a proper SPA and everything is lustre, no js sprinkles (except the generated library stuff)

hoary cypress
stark hazel
hoary cypress
#

Worst scenario you create a custom element manually that just return a bit of html generated by Lustre to_string.

#

(don't ask me how you create a custom element in gleam 👀)

#

(Was affraid it would stop at "lust" 😂)

stark hazel
#

it almost stopped at L

hoary cypress
stark hazel
#

i know people think hayleigh is the only one who read the api, but it's lustre.element smile

hoary cypress
#

(I should stop ping hayleigh and also don't forget rebecca know lustre also well 🤦‍♀️)

hot root
#

if its not interactive it probably shouldnt be a custom element at all

#

but yes lustre.element

hoary cypress
hoary cypress
stark hazel
#

you are literally in this thread

#

would be weird not thinking about it ^.^

hoary cypress
#

Let's pretend I got short memory issue even if it's not true 👀

sullen trellis
#

I need to check this lustre context thing. And for that matter, the elm store pattern. I want to do a experiment with those

hoary cypress
vocal osprey
#

i did a store pattern with redux and react before the elm store pattern was a thing. ended up costing us a ton because I ended up paying fastly for 100x the number of requests

#

seemed super clever at the time. i'm sure it could work for some scenarios. but it was horrible in my case

verbal solar
#

How come it made so many more requests?

vocal osprey
# verbal solar How come it made so many more requests?

so the scenario was a competition, with teams, schedules, round robins, brackets, and games. the game data was frequently being updated (could be up to 8 games being played at the same time / draw), so all of the content had different TTLs.

#

the game data was also used in the reports / stats (shooting percentage, rating, etc.)

#

so we had all of these micro end points in the big store that would resolve and refresh them as needed (when requested).

#

and they would get stale fast (no websockets, just REST polling)

#

so when you needed the data from a game, we check if stale, then fire off the request and cache it

#

or we pop it from cache, i can't remember

#

BUT, as we added more and more reports they were basically all needed big slices of game data

#

get the picture?

#

every refresh of game data, per client, for tousnads of clients, would send a request for it's json

#

it all got aggregated into the store, so you were only ever fetching data when youre copy was stale

#

so we optimized for bandwidth, completely ignoring number of requests (and the fast that requests have an outsized cost both due to the envelope but also from our CDN)

#

during the scotties i got a bill for thousands of dollars...

#

next season i scrapped the entire thing, lumped all competition data into one big json structure, gave it a micro TTL of like 15s

stark hazel
#

is fastly a thing where you pay per request?

vocal osprey
#

and my bill for the scotties was around $100

#

yeah both requests and bandwidth

#

pretty sure all CDNs are the same

#

but I tell you, the code was pretty damn fancy. we were very proud of it before reality hit

stark hazel
#

what's a cdn doing there though i thought that was dynamic data

vocal osprey
#

short lived cache. micro TTL of around 15s

#

for games

#

basically we give you the game json and set an expiry of 15s

stark hazel
#

wouldn't you just do that locally on the file system / with redis / etc

vocal osprey
#

fastly is just outsourced varnish

stark hazel
#

ah well 😅

vocal osprey
#

varnish is probably 100x the speed of redis

#

and you get a really OP thing called "grace" period

stark hazel
#

it's not they are fundamentally different things

#

anyways

#

one of the cooler features you can do with stores would be that you collect and batch all the requests, but i guess that also didn't apply since you did this cdn stuff in front of it

vocal osprey
#

i think redis was pretty new on the scene at the time

#

most ppl would use memcache for app layer caching

#

anyways, i'm sure stores can work, it was just really bad the way we did it at the time. mostly just being silly

#

one of the big drivers for this libero project was the public sites for clubs I'm planning for them to just be static sites that can be hosted anywhere. So either SPA or making REST calls. Libero will be able to server the admin, rest clients / SPAs, and even stuff like a CLI (also something we're building)

stark hazel
#

ye that's the great appeal

shadow dome
#

This is an interesting novel to read and too long for me

#

But one thought I’ve been carrying with me, which is related is the following

#

The dual target allows us to write isomorphic code, and I’m wondering about where to put the boundary

vocal osprey
shadow dome
#

I’ll take it as a compliment

vocal osprey
#

🙂

shadow dome
#

The zoomers have ageist cyberbullied me already

#

So I’ll take this

#

About the “boundary”

thorn warren
#

that's a gen alpha problem

shadow dome
#

I’m working on a project that has on sqlite per tenant - offline-first

#

So one extreme is all js, the other one is all beam with server components

#

All JS would have the advantage of shipping the whole thing as an spa with no downloads.

#

With a beam backend i get some more scalable processing, fs access, a server that can do things

vocal osprey
#

hmm, well with server components it just works. with libero you'd want an SSR render (lustre runs on server so this is easy) that makes the rpc call directly. should be striaghtforward

#

if what you're thinking about is that initial render / hydration

shadow dome
#

No sorry it’s slightly higher level

#

Libero is the fe/be boundary

vocal osprey
#

ok i see. you have fat js client already delivered

shadow dome
#

Well no in fact right now I have a fat beam app that i want to roll up using queso

vocal osprey
#

oh, well that should just work. I have an CLI example in the repo

shadow dome
#

Interesting

vocal osprey
#

which is basically just a basic anything type client

shadow dome
#

-> dm

vocal osprey
#

i’m publishing v3 tonight

vocal osprey
#

v3 is published. works most (all?) the bugs out. uses the Messages conventions (kind of like Lamdera) instead of /// @rpc and @inject annotations. Other QOL. I'm sure there's more improvement to be made, but I have it working solidly right now, so it's good enough the mess around with.

sullen trellis
#

Cool

sullen trellis
#

I really want to understand the pros and cons of using bare lustre vs. this

#

I guess this is more like a framework that gives you a lot of boilerplate and forces you to do things in a very specific way (which isn't necessarily bad)

white leaf
#

Great project, @vocal osprey. And here I was fussing around with making grpc work nicely. I'll definitively try this out tonight.

vocal osprey
vocal osprey
sullen trellis
#

Maybe they solve different cases

hoary cypress
# sullen trellis ☝️

I can think of a con where you are dependent of a project that generates codes for contacting the endpoint and serving the endpoint

#

Also if the code generator do things you don’t like you can’t change it’s way of doing things

#

But you get the pro of an automated thing that can be easily updated and maintained when new routes is needed

#

But yeah you are right to be careful and to always think of that

vocal osprey
#

so I've been scratching my own itch with this. server components were cool, but fell short of what I needed. (1) admin interface, server components are great, but also a little annoying for certian pieces, embedding client components, js sprinkles for stuff that belongs on the client, but that's nothing compared to what it gets you. (2) public interface, doesn't really work for me. My customers often have their own sites and need to integrate via APIs / widgets. This isn't something server components is designed for. Libero has an ETF decoder / encode to simplify SPA / widget RPC without writing decoders and stuff. (3) I have a CLI (maybe later an app) version of the admin interface so my customers can use their AI agents to act on their behalf without taking over their browser. No idea if this is something that I'll need in a year though tbh. Libero is my solution for all of this, but it could definitely be easier to wrap into it's own CLI and opinionated layout. That's not an itch I currently have, but it is interesting, so maybe...

hot root
vocal osprey
#

excactly. Libero is really just using ETF so that I could have compile time type safety for RPC with the server without needing to write encoders and decoders all of the time. That forced me into code generation... since then I've been trying to make that more intuitive, and likely failing...

#

I does work though, and I really like it. It simplifies a lot. However I'm struggling a bit to find the polish to make it easier for others to onboard. Kind of half assing it too tbh because I'm trying to complete my app rewrite 🙂

#

but I think there's some meat there that I'll keep mullling over. would love feedback / ideas that others have.

stark hazel
#

i think the most useful bit would be a library to do etf encoding/decoding

vocal osprey
#

good point though. could just go back to the lighter API or break it into 2 projects

#

To make the ETF work with the front-end in a typed way, I needed:

  • Message types so both sides agree on the contract (Lamdera inspired)
  • Codegen to produce dispatch tables, client stubs, type registration (Don't see an alternative)
  • Config flags to tell codegen where everything lives (with a convention default)
  • Three packages so shared types compile for both targets (honestly I would maybe simplify this if it was a framework)
hot root
#

i dont think any of it is lustre related tbh

vocal osprey
#

sry gleam

#

i'm just always going to use Lustre 🙂

stark hazel
#

i don't think having more code is ever a benefit

vocal osprey
#

it's less code

#

you need to consider the application it's used in

stark hazel
#

conversly, "it's literally just this" doesn't mean it's not important

#

code is just a little side effect of making a library

#

if it was about producing code the core team would spend all sponsorship money on tokens

vocal osprey
#

you've lost me. when did I say I wanted to produce code?

#

i have a big app, does lots of things, needs to talk to the server all the time, libero has significantly reduced / eliminated all of that glue code

stark hazel
#

your constraints and incentives for making an enterprise app are significantly different from building an open-source ecosystem

vocal osprey
#

I feel like we're having different conversations

#

I think you're just saying, the ETF portion shoulda been the library and not the codegen stuff?

#

I don't know how usefull it is without the contract though

stark hazel
#

yeah that would be the most useful part of this, it would be even if it was just a single ffi declaration ffi to binary_to_term
but in response you said it's "just" this one file where you linked me to some claude javascript sprawl
so both these things tell me that you value the final artifact more than the things that make a good library and ecosystem

#

so what i've been saying is we don't need more code, we could generate code ourselves!

#

the hard problem is making good libraries around it

shadow dome
stark hazel
#

enterprise code only cares about results, open source has very different incentives

hoary cypress
stark hazel
#

you sell a product, you don't sell "written in a functional style"

hoary cypress
#

Sadly…

shadow dome
# stark hazel you sell a product, you don't sell "written in a functional style"

I disagree. I think you are confusing early stage product companies that are more concerned with getting traction in the market and are okay with racking up technical debt with enterprises that have proven business models that they optimize and scale. In enterprise a 1% efficiency gain from carefully engineered tools or 1% tech debt / codebase reduction can have significant impact on the company's bottom line.

vocal osprey
#

Erlang literally came out of practical enterprise business needs

shadow dome
#

@vocal osprey has a big app here that seems to have traction and has written a solution that does reduce the codebase, tech debt and hence maintenance burden.

There is always a tradeoff in engineering, but I wouldn't conflate the work on libero with AI generated slop because of one particular FFI file.

stark hazel
hoary cypress
#

Tbh I don't think because of Enterprise or Open source the people behind writing a code and either carry about the end goal or the way it's done would changed.

shadow dome
#

I would say that the gleam ecosystem and the personalities might be more suited to enterprise because you clearly care about high-quality, reliable, reasonable code! (this is a compliment)

hoary cypress
#

Some people value more end result and other the way it has be done. Even if this could be weird for a library to not care how it work

shadow dome
#

Look at what is happening to amazon, github etc. their engineers are forced to AI-slop and their uptime is now below 90% at times!

#

gross management error. Better have people that write everything by hand here. Carefully crafted solutions that then go open-source (like erlang).

#

I think we need both end-result focussed people and those that care about the details. It's not black and white. And there is a use for ai-generated code also.

hoary cypress
#

Before LLM their was not distinction between end-result and the details to do it because it was the only way to do it (except if you bought someone else but in this case you are just a company talking to another). (yay LLM are like outsourcing work)

shadow dome
#

Anyways, I'm sorry for hijacking the thread, this shoudl be about @vocal osprey 's work, libero.

stark hazel
#

i think a good way to share end-result-oriented things is by making example apps

#

and again i do think having a way to encode/decode etfs is useful!
i don't even really care that much how the code was generated, but i do care about all the other things that go into making good libraries too
and unfortunately of the people that largely didn't write the code themselves only a minority so far has spent the time to make all the other bits good
even before ai was a thing people tended to over-value code, it's hard for me to find a good balance

#

anyways i think splitting things is good for folks who don't want to use all the generators!

shadow dome
#

The point of AI is to be able to focus on the important parts. This thing creates value. Humans can also produce garbage code, it's not unique to AI.

hoary cypress
stark hazel
#

it's a data format, like json

hoary cypress
#

Oh so you need a decode to create dynamic and a way to build it like gleam_json ?

stark hazel
hoary cypress
#

(thinking if in a future (don't ask me when) this could be relevant for #1484857563345584178 as an (another) alternative to json)

#

(but if it's like json I would need first to find a gleam_etf or made a library for this since sara is for generating code for encoding / decoding into a format not specifically adding a format)

shadow dome
vocal osprey
stark hazel
#

hmm why do you think that ^.^

hoary cypress
#

Well is not a library just a bunch of code you just reuse in your project ? So knowing this code was taken from a stranger is something you need to be sure it's of a higher quality you could do. Otherwise you would just skip the library and do it yourself for your own tailor needs

vocal osprey
hoary cypress
#

But yeah I'm myself biased in the craftsmanship AmityBlush

hoary cypress
shadow dome
#

One piece of feedback on the actual use cases - I did check examples after @stark hazel mentioned it and I think that it would be cool if the RPC protocol had request and response types.

#

I think that could reduce some wiring in the app.gleam

sullen trellis
#

And I end up burned out and quit xD

vocal osprey
#

managed to mangle this post, but for anyone interested v4 now has CLI args to setup / onboard your project. I'm considering a --database sqlite flag too, to fill in the final piece usually needed. Also considering hydrate / ssr / spa options too now that I've got that working. https://hexdocs.pm/libero/

verbal solar
#

If you add NIFs please have them in a second package, they are rarely a good choice and have many disadvantages which make them unusable for most

crisp viper
#

I am the one who created GH issue
Used cli to scaffold app yesterday and it works nice - I have my own app I can now play with

two remarks

  • examples are still not runnable out of the box, or at least I am not doing the right thing, so it would be great if that could be polished (ssr_hydration is not buildable, for example)
  • gleam run -m libero -- new my_app
    I ran this within libero GH project after I cloned it. After scaffolding my_app, I copied whole folder to another location. Will this pattern of usage remain, is this how you envisioned it?
#

Overall, I am impressed. Libero takes over all "boring parts" and now I can concentrate just on business logic

#

btw what place sqllite will take?

verbal solar
#

Natively implemented functions. aka code written in languages like C, C++, Rust, etc that you compile to a shared object and dynamically link to the virtual machine.

#

The native code has to work within the BEAM scheduler and memory system so they're very challenging to write well, and it's easy for them to introduce performance issues and can undermind the BEAM's fault tolerance

#

They also make the build process a lot slower and more complicated as this native code has to be compiled, so if a package has a NIF you have to manage that even if you don't use it

#

Because of this it's better to have optional NIF usage in another package

#

(Good question, thank you)

crisp viper
#

before asking you I asked Claude.ai, and I did not get anything useful, despite offering me 5+ acronyms 🙂

#

it was somehow clear right away that it is not
National Ignition Facility — the laser-based nuclear fusion research facility at Lawrence Livermore National Laboratory in the US
nor
Neutron Imaging Facility

hoary cypress
hoary cypress
vocal osprey
vocal osprey
crisp viper
vocal osprey
crisp viper
#

e.g. manifest.toml was referencing libero 3.0.0

vocal osprey
#

oh well that'll do it

crisp viper
#

will create PRs from now on 🙂

verbal solar
vocal osprey
vocal osprey
verbal solar
#

Fab

vocal osprey
# verbal solar Fab

is sqlite the most common NIF you're seeing in the wild, or does it come up often for other reasons? Maybe image processing (we shell out)

verbal solar
#

NIFs are quite rare. The only one commonly seen in my experience is password hashing algorithms, but password authentication is becoming less common

#

It's no longer the default in Phoenix, for example

#

There once was a JSON NIF that got used a bit but the new BEAM json module has similar performance so not much reason to use it now

vocal osprey
#

nice. sqlite has definitely caused me a bit of deployment headaches, but they got resolved. still worth it though, just a minor annoyance. I would imagine it creates a windows tax (thankfully M$ is doing there best to alieanate windows users themselves).

hoary cypress
#

(I should try to see how passkey works. They look cool as an alternative)

vocal osprey
# hoary cypress But I do love my password 🥺

we do login links w/ codes. dunno if it's the best option, but def better than passwords IMO for a general audience (for a more technical audience that is more likely to use password managers, maybe not): https://curling.io/blog/passwordless-auth-done-right

Curling IO has been passwordless since Version 2. No passwords to remember, no passwords to steal, no password reset flows. You enter your email, we send you a short-lived login code, and you're in. It's been working well for over a decade, and for Version 3 we're keeping the same approach while fixing some rough edges and adding multi-email sup...

hoary cypress
vocal osprey
#

makes sense. you don't need pwd recovery?

hoary cypress
#

However I agree if it’s was a public service where anybody could create an account publicly. I would need a way to password reset ^^

hoary cypress
vocal osprey
crisp viper
vocal osprey
#

same with marmot and glinter

vocal osprey
#

New Libero published. I think that's it for churn. My use case for this library is about 95% done and I think the non-generated user code has been minimized as much as it can be with this core idea. May have gone a bit too magical with the handler signature detection, but it's working very well for us. Multiple clients supported and tested, js, websocket, gleam, REST, etc. Getting started guide from zero to hero, part 2 adds sqlite. Might post a part 3 once our CLI app is done, maybe a part 4 if we ever do a mobile app. https://hexdocs.pm/libero/

shadow dome
#

Link to step 2 is dead

vocal osprey