Something fun | Observable Flutter #78
By Flutter
Summary
Topics Covered
- Serverpod's Anonymous Auth: A Deep Dive
- Dart's Full Stack Potential: Beyond Flutter
- Navigating Serverpod Migrations: Friction and Solutions
- End-to-End Type Safety: Serverpod vs. Django/Express
- The Nuances of Anonymous Account Merging
Full Transcript
Hello everyone and welcome to another episode of Observable Flutter. My name
is Craig Lebenz and I'm trying to launch this stream for the second time and I'm checking over on the dashboards and okay, I think we are in fact streaming.
Great. Well, it's so lovely to see you all again in 2026. I hope you had as restorative of holidays as I had. I'm
very excited to be back. I'm very
excited to be working on some Flutter stuff together. So, yeah, great to see
stuff together. So, yeah, great to see you all. And I have
you all. And I have not not going through Streamyard today, but I have the chat app that we all made
together. It was a team effort ready to
together. It was a team effort ready to go. So, uh let's see. Oh, wait. I have
go. So, uh let's see. Oh, wait. I have
to switch to the correct window for this to appear because it's not in this OBS overlay. There's always more shuffling
overlay. There's always more shuffling to be done.
Here we are.
Randall wonders what I'm going to be working on today and expects that I too wonder what I'm working on today. And
that is typically correct. But after I made the ambiguous thumbnail, I came up with an idea of what I'm pretty sure I want to work on. and I'll I'll take some
suggestions or ideas from folks. But
what I'm thinking about is I've been working on adding anonymous off to server pod's new O module and
I could basically do that for about an hour and a half kind of proceed on where I've been. So, let me know if anyone has
I've been. So, let me know if anyone has strong feelings for or against seeing a little contribution to server pod. I've
had the good fortune of working with the server pod team a bit to kind of get up and running and figure out how to, you know, how to think about CI and the tests and server pod tests are fairly
complicated.
Um, yeah. So, barring any strong votes against uh I will go with that.
So, as this happens, I'm going to bring this up and um we'll see what we got.
See what we got.
Where's OBS?
Oh, I clicked the wrong button. That's
why what I thought was going to happen didn't happen.
All right.
So, is my chat app something?
Where's that? Oh, yeah. It's the Flutter logo. There it is. There it is. Make an
logo. There it is. There it is. Make an
editing app.
A what editing app? One wonders.
L Creations says that. Oh, do I not have the uh overlay in this one? Oh, no, it does. Okay. All right. So, I'm going to
does. Okay. All right. So, I'm going to pull this up and kind of get situated, but there's still a window for anyone to
come up with a better idea, but absent a better idea. I'm going to contribute to
better idea. I'm going to contribute to Serverbot today and I'll walk folks through what I've done to start us off, if in fact that is
what we go with. And uh and then we'll see and we'll be up and running.
OBS is powerful and with great power comes great responsibility.
That is that is true. OBS is
I I love OBS. Honestly, it's just amazing that something as powerful as OBS exists for free. That's so
incredible.
Uh looking at some of these chat messages. Let's see. So, I vibecoded
messages. Let's see. So, I vibecoded Flutter for terminal applications in Dart.
Um, awesome. What did they do? I'd love
to hear more about that. I have made some terminal commands like organize the raw files of my uh very very very
amateur photography to like delete the raw files of photos that I don't keep.
So, um, I've also dabbled a bit in that world.
Future of Dart outside of Flutter. Well,
we're constantly Oh, wow. Look at this.
Look at the um I just saw that the overlay for that last image was totally not scoped
correctly which was remains one of the big problems in my app and why it's not quite production ready. Um yeah so future of Dart outside of Flutter well
serverside Dart. So, that's a that's an
serverside Dart. So, that's a that's an extremely timely and appropriate question because I'm thinking about doing some uh
some full stack Dart right here. See,
continuing to read some of these chats.
Let's make a mindmap building app. Well,
I basically don't know anything about mind map building uh mind map apps at all. So boy would I not be ready to
all. So boy would I not be ready to build one yet. But I probably should learn. People love mind mapping apps. So
learn. People love mind mapping apps. So
maybe I should get into them. Something
wrong with chats appear on the screen just showing half it. Yeah. Well, that's
something is that the the that is a utility that um
why am I blanking on their name?
Streamyard does quite well is their their logic for the overlay situation is much better.
Mine not not so good. So short messages will render much better when I go straight to Streamyard. Maybe one day we'll have to
Streamyard. Maybe one day we'll have to fix that. Uh all right, looking at more
fix that. Uh all right, looking at more chats. Waiting for Craig to play
chats. Waiting for Craig to play Minecraft on stream and using the redstone dart made by Norbert. Yeah, I'd
love to have Norbert on and talk about that because that's super duper cool.
The Flutter team was sharing around that link. I think it was yesterday.
link. I think it was yesterday.
So, we're also pretty amazed.
Um, all right. So, I think it's time to
all right. So, I think it's time to begin. I'm just going to check a few
begin. I'm just going to check a few things. Make sure I'm not getting any
things. Make sure I'm not getting any chats from backstage folks saying, "You sound terrible. What's wrong with you?"
sound terrible. What's wrong with you?"
But no such chats exist. Okay.
So, and will we see macros and flutter?
Probably not. Not not soon, sadly. Okay.
Make sure I go to the correct screen here. I think I'm going to be on
screen here. I think I'm going to be on the right one. confirming. Yeah. Okay.
So, this is my extremely janky overlay window that you may recall from previous. Oh, chess. That would be fun.
previous. Oh, chess. That would be fun.
Chess would be good.
Uh, I made I I I did make a chess app in Flutter a long time ago. It would be it would be fun to make that more serious.
Like, there's no AI in it. You just play against another person. kind of like hot seat and you can't make illegal moves.
That that was it. And it detects checkmate and fun stuff like that.
There's no no playing against CPU.
All right.
So, first let me pull up the the pull request on server pod. So,
a little backstory here. Server pod is full stack Dart. They have shared server and client side generation so that the
transport layer when your flutter app or your CLI or any whatever your Dart front end is talks to your server, you just call a local function that is magically
routed to the endpoint on the server that you want to invoke and then you return something from that server side uh function and again the transport
layer in reverse is also hidden and back in your front-end Dart code, you're awaiting the result of this function.
Whatever was returned on the server appears magically for you on the client.
Super cool. They have an authorization module because any serious app of course needs to be able to know who is logging in. And that app or sorry, that module
in. And that app or sorry, that module is broken up into multiple different what they call IDPs, identity providers.
Apple, Google, and email being the most common ones. I think they also have a
common ones. I think they also have a pass key one, though I've not really looked at that at all.
Well, what I want to do is add anonymous off, which is obviously a feature in Firebase off, but what I so I could lean on Firebase off for that functionality,
but then I have two O systems and I have to sync users between them and it's unbelievably painful. So I want
unbelievably painful. So I want anonymous off in serverbot and because when so many of you ask for
different features in Flutter, I often will give the somewhat cheeky response of like, well, you can always open a PR, you can always file an issue and work on it. I'm putting my money where my mouth
it. I'm putting my money where my mouth is and I'm doing that with Serverpod.
So let us now uh proceed. So I have made a design document which I believe is open for anyone to look at and yeah so this
is just all of what I'm imagining. I
think a design the design document step here was extremely useful because it allowed everyone to get on the same page about the end state of this feature like
you know where is it going to ultimately go um how do we kind of build with the future in mind and not paint ourselves into corners and all those idioms. So
this is the design document and the currently open PR is basically just phase one and then I have a different PR that begins to work on phase two but
there's lots more that will have to happen for phase two.
So the PR for phase one is nearly complete but I need to rebase some migrations which is currently a source of moderate
friction in server pod but we can do that together and you'll all get to see a little bit of how
to uh you know work with and really massage a server pod project. So that
that's today.
All right.
So, if we look at the files changed of this PR, the diffs are huge, of course, because there's a lot of generated code in here. I did not write 17,000 lines of code.
But if we scroll, nope, I'm actually not. I don't need to look at this tab.
not. I don't need to look at this tab.
Do I know how GitHub works? Have I
developed? Have I developered before? If
we don't leave the default tab at all because why would anybody do that? When
we scroll to the bottom, we'll see that there are some conflicts that have to be resolved because I added migrations, but then I also filed a bug for an enhancement to a different module and
someone on the server pod team fixed that and that added migrations. And now
I have a conflict on migrations. So
that's the first step is to solve that.
Now I'm going to check chat because I haven't looked at it in forever and we'll see what you've all been blaming about. chess would take an hour to just
about. chess would take an hour to just set up. Yeah, it would. But it was super
set up. Yeah, it would. But it was super fun.
Oh, wait. Le chess is written in Flutter and Lotus Chess. I'm not familiar with Lotus Chess. That's interesting. Uh I
Lotus Chess. That's interesting. Uh I
didn't know that my chest was written in Flutter. Yeah, SMS as a IDP is a valid
Flutter. Yeah, SMS as a IDP is a valid IDP not currently in the module.
Okay.
Howdy Egypt. Good to see you.
All right. All right. So, I have the code up and let's look at how migrations in Server Pod work. And admittedly, for
the first few minutes here, Server Pod's not going to look the best because there's, like I said, a little friction around migrations, especially when you need to roll a migration back, which I
have to do to resolve this rebase. If
you don't roll migrations back then there's no friction right. So the first thing is
right. So the first thing is let's see in the server pod off IDP project that's where basically all of
the code that I have been adding is uh has lived and then also in a project specifically to run uh integration tests
against that. So those are the two
against that. So those are the two places. So tests server pod off test and
places. So tests server pod off test and in modules server pod off and then for both of them ultimately in a project
that is like the underscore server part of a server pod situation. So let's do it.
Um I forget. Let's make this big enough.
Is this big enough yet? Should I go a little bigger even? I think I will go bigger. Go bigger or go home. Say the
bigger. Go bigger or go home. Say the
streamers.
So here is that's interesting. What do I not see?
that's interesting. What do I not see?
Oh, resolve in merge editor. I'm not
seeing the actual like big in-your-face conflicts though, so that's interesting.
Uh I see I'm in the middle of a merge.
Yeah, I guess I started thinking about this the other day.
Yeah. Okay. Where did I even leave myself? I think I'm
myself? I think I'm aha.
So, what's going on with this one?
Surprised that I don't have the same issue here, but in the test, we definitely see it. So, my change is the
older one, I believe, which can I read?
Yeah. So, incoming is mine.
Is that right? Was I rebasing? I guess I was rebasing. And this is the
was rebasing. And this is the one that needs to sit below my migration. So if we look at but this is
migration. So if we look at but this is in the test. Why am I not seeing the same thing here? Did I like change something myself? Oh, I did start to
something myself? Oh, I did start to muck with it. But that was invalid, right? Ah, there we go. This makes a lot
right? Ah, there we go. This makes a lot more sense.
So I actually What do I want to do? I
think I want to abort this whole merge. I need to do like a git merge or whatever it is. Get merge
abort or something. Um,
why am I in this directory?
Here we go. Okay, so get merge abort merged files.
Yeah. So, get rebate support.
What's my situation?
I really shouldn't have started mcking with this three days ago and then stopped. Uh, looking at chat again a
stopped. Uh, looking at chat again a little bit here. Oh, get rebase d-upport. Get rebase-up.
d-upport. Get rebase-up.
No rebates in progress.
Where it's like, do you know what you're doing? There we go. Wonderful.
doing? There we go. Wonderful.
Okay. Okay. Okay. So now I'm going to un I deleted this migration which I'm going to ultimately have to do but I'm going to undo that for now. So I'm going to restore these files. Okay. Now I am
ready to delete my migration and then I should be able to merge in uh the real one, the one that needs to
exist before me. So in the server pod repo, we've got this modules directory and then server pod off is where we live. And there's different modules in
live. And there's different modules in here. There's a bridge if you're coming
here. There's a bridge if you're coming from the old O situation core. Pretty
clear what that is. And then IDP is where all the different IDPs live. So if
you don't if you didn't use the old server pod off module, you don't care about migration or bridge. You would
just use core and IDP. So this is where I I have been spending my time and I'm in the underscore server directory in the migrations directory and I added
this migration and if we look at that migration we'll see that it has a V7 uh UU ID function and there is an anonymous
account table and a constraint and you know enters itself into the migrations table all that good stuff.
So, I need to manually back this out, which for my purposes um only means like deleting stuff from my local database
that I'm using because I want to keep using that database. And then uh I will also need to delete these files. And the reason we
have to delete the files is these definition files which I also filed a proposal to basically get rid of because they are the source of this friction.
Shall we now pull up post as one does and look at where am I using this?
I guess it's basically just in the server pod test app. Is this right?
What is my What are my connection credentials here? No, that's not it. Oh,
credentials here? No, that's not it. Oh,
right. I've only set this up on my personal computer. I downloaded I I get
personal computer. I downloaded I I get cloned all of this on my work computer, so I don't have a connection to this yet. All right. Well, that'll be worth
yet. All right. Well, that'll be worth um visiting as well. Well, I'll see.
Okay. So,
um I am going to add a new connection to the local Oh, this means I don't have to delete the table because I'm not on my computer
where I've even added the table. Aha.
Nice. Although I will have to do it later when I return to my personal computer. All right. So, actually this
computer. All right. So, actually this just got easier. So, I can merely delete this whole directory
like this.
And then I need to go into the test directory and get the off test server
migration.
Get the same directory here. Delete it.
And then I was surprised that I didn't see an error in the examples because there's an o examples directory as well.
I think that the bug fixer of the other thing just didn't add their migration to this. So I look at migrations here.
this. So I look at migrations here.
Yeah, they just didn't add it. So that's
okay. I'll fix that, too.
So now I am maybe ready to merge. What
do I What are my open things here? I've
gotten rid of this migration. That is
correct. I'm going to say removes migration in favor of rebased migration.
Love it. I'll now switch back over to um the main branch and make sure I grab everything. Oops. Get checkout main and
everything. Oops. Get checkout main and I'll do a get poll.
And lovely. So now I'll say get checkout add anonymous IDP
that's not what it was called.
Oh goodness.
Okay, back to GitHub we go. What is this branch called?
Anonymous O IDP. I mean, who could have remembered that?
I'll look at some chat real quick here.
Uh tried server pod but it's overkill for you. Hog dominance. Good to see you
for you. Hog dominance. Good to see you hog. Um interesting. I wonder what was
hog. Um interesting. I wonder what was overkill about it for you. I mean if you're not talking to Postgress I think the the value proposition drops off because the OM is really really good.
There's there are definitely other value propositions to server pod like no doubt but to me talking to Postgress is the main one. So, I wonder
main one. So, I wonder um this may clip. I apology. I
apologize. I love Dart, but I'd like to know a good reason to use Serpod over a solution like Django or ExpressJS.
That's an awesome question. I love
Django. I used it for about a decade.
It's awesome. Uh as Randall says, he doesn't want to learn Django or Express.JS. That's a great reason. So if
Express.JS. That's a great reason. So if
you already know Django, then you've got a fair cliff that something else has to exceed before you would stop using, you
know, whatever other tool that you like.
Out of the gate, the shared client generation I was talking about earlier is a huge thing.
Like server pod offers you type safety from a random function in your Flutter app all the way to the database. So
that's type safety over the wire and then type safety on the query.
And you know you get like pseudo type safety with Django as well on the query.
But unless you use kind of a gRPC module and generate some Python bindings and then generate Dart on the front end and like get type safety over the wire that way you won't you just there aren't
really many other ways that I'm aware of to get end to end type safety. So, super
super super cool. Um, server pod, you know, at the risk of talking about their paid product as well, they're also adding like one-click deployments, and that's super awesome. That's kind of in
an alpha beta state right now. Other
folks talking about how yeah, server pod works together cohesively, all that kind of stuff.
Um, continuing to scroll down some chat here.
All right.
Oh, what theme I'm using? Yeah, I love this new theme. It's
Catpuchin. Catpuchin. I'm not really sure how to pronounce it. I like
macchiato and Mocha. I'm currently using Mocha and I really love it. I've been
using Synth Wave for like years, years, and years and years and I recently switched and it's been fun. Okay, so I have pulled and now I'm ready to get
merge main.
I wasn't expecting to still have those conflicts. What are we talking about? I
conflicts. What are we talking about? I
got rid of that. Oh, I didn't delete.
That was the other thing I had to do.
Abort. Sorry. Sorry. Sorry. From the
migration directories. I have to actually delete.
Wait, that's interesting. Wait, what is this migration? Am I like misremembering
this migration? Am I like misremembering something? Oh no. Okay. Wait, wait,
something? Oh no. Okay. Wait, wait,
wait. Yeah. What are you? What are you?
Who are you? What is this?
Another anonymous Hoth.
It existed twice.
Well, that's embarrassing.
Goodbye.
What?
Uh, okay. So,
now let me think. Weird. Don't know what error I made to do that, but I'm sure that was me.
So, okay, I had to deleted that row, which I had to do. So, now I'll go back into the test directory. And
this is probably going to be the same thing. Oh, challenge tracker. No, this
thing. Oh, challenge tracker. No, this
is a real one. This one will definitely not be getting deleted. Did I delete a real thing before? Did I like hallucinate something? I'm really
hallucinate something? I'm really surprised. Okay, so this ends in um
surprised. Okay, so this ends in um 41265.
And if I look at my git history, the folder there is not 401265.
So that was just total user error. Okay,
weird.
But anyway, so in um the tests migration registry, this is where I just delete this line.
Cool. surprised this challenge migration isn't up here, but whatever.
All right, so now I'm going to commit that again and say um more better
migration rebase prep.
Much more better.
Now we should be able to conflict free merge main.
Okay good.
Close that.
All right.
Will Dart ever get better tooling on exceptions, especially in regards to public API documentation on what exception could possibly thrown be thrown from a function method? That is
such a good question and such a uh like big topic in language design. And
right after Randall says, "I hope Dart never requires all exceptions to be listed." Um
listed." Um I know folks who come from languages where exceptions are listed really miss that about Dart, but it is it isn't
going to happen. Now, interestingly,
serverpod wraps everything in an outermost try catch. And when you throw exceptions, which are like registered exceptions with server pod, those
classes get returned and reinstantiated on the front end and get thrown again on the front end. So, you can throw server side exceptions and catch them on the
front end. And that's kind of a nice way
front end. And that's kind of a nice way to use exceptions like again cohesively end to end.
But uh I personally because Dart doesn't lean into exceptions. I try to return union types
exceptions. I try to return union types of like ex success or failure and each function that might throw an exception like contains that exception and doesn't
make it the calling codes problem to try and catch. Now, if you return a union
and catch. Now, if you return a union type, it's still the trying codes problem to unpack that union type and evaluate, you know, which one it is. But
like that's the Dart way to do this. If
you're going to throw if you know that a an exception might be thrown in a certain function, catch it there and convert it into some return type that says like, hey, I failed for this reason. And then your calling code
reason. And then your calling code doesn't, you know, you don't have to like try catches everywhere. You do have unpacking of union types everywhere, though. But in some sense, uh, if you
though. But in some sense, uh, if you don't want every exception to crash your app, you're going to have to do one of those. And that's the dark way.
those. And that's the dark way.
All right, back to serverbot. So, now
that I have done that, and I'm not working with a database here that was muddied up by my migration because that database only exists on my
personal laptop.
I can now uh I'm surprised that merge didn't get squashed. Oh no, I guess there there was
squashed. Oh no, I guess there there was just a lot of commits that I pulled in.
Okay, that's fine. Anyway, um now I can regenerate the migrations and then I'll I'll actually kind of play with the test app and we'll see that it's working
before I submit everything again. Okay,
so I'm going to switch. What's this
directory for? What do you do? What do
you do?
This is the actual thing itself. So here
I should be able to say server pod create migration and we'll get a new folder that'll look a lot like the one I deleted, but it will have the correct definition files.
So server pod create-ash migration and I will now just press enter.
Excellent. So this is right now's time stamp forever immortalized unless this gets deleted again. And if I look in the migrationsql
thing um oh this is a surprise.
I was not expecting that. This is the previous one.
Oh, I'm actually in the test folder. I
thought I was not in the test folder.
I'm in the test folder.
I'm still confused.
I'm not in the test folder.
And yet, what?
Ah. Ah. Ah. Okay. I'm just really, really dumb is the problem. This is the one that was just generated. This is not the one that was generated. So, this is exactly what I should have expected to see if I had a bigger brain. So, okay.
This was what was just generated. And
this migration is going to be my UU ID v7 function again and the anonymous account table. Great. And the one before
account table. Great. And the one before it is the index change. Right. That's
correct.
Great.
And now the migration registry has both of them in the correct order with the right time stamps and all the definition files are valid. Awesome. So now I will
switch over to the test folder which I'll open in a different terminal. So
this will go into test uh off nice server
nice and here I will say server pod create migration.
Awesome.
Is there anything else I need to do? Oh,
yeah. The the off example. I'll make a new terminal for that as well because they're cheap. So, now I'm going to say
they're cheap. So, now I'm going to say example off server.
Yep.
And create migration again.
And that should make some migrations.
Lovely. So, what's this new migration?
This. Yes. Has both.
No, it only has the other one.
Why does this not have the anonymous table?
Why do you not have the anonymous table?
Okay.
H.
What's in here again?
Oh, because this was here and it's out of order.
The funny thing is it actually I don't think this order.
Oh, no. This is like a way earlier thing where I had way more. Is it? Who added
this? Did I add this or did someone else add this? Where's my like get lens?
add this? Where's my like get lens?
What is the date on this? 12:21.
This feels like a day that I was working on this. Did I generate this?
on this. Did I generate this?
Uh, why is git lens not doing anything?
Because it's not installed.
Really increases the difficulty for a extension to do its job.
Who would have thought?
me two weeks ago. Great. That's why it's wrong. You can always tell why
wrong. You can always tell why something's wrong if I made it.
Those things correlate. All right.
Great. So, what I'm going to do now is delete both the old migration I made that is wrong, wrong, wrong, and this new migration that is uh
that I just generated and it's wrong.
And I'm going to delete both of these rows. And now I'm going to create
rows. And now I'm going to create migration again.
And this seems to have bundled them in the same thing.
Oh, there's a lot here.
There's more than I was expecting here.
Not going to lie.
Maybe I didn't do something wrong. Maybe
someone else did something wrong.
Wouldn't that be a change of pace? So,
server pod anonymous ID account. If this
is Oh, wait. No, that I added. So, here
we go. Apple account.
If this is not does not appear here, then we're correct. Oh, and it doesn't.
Interesting. I don't know how this off module worked.
I'm fairly confused, but that's okay.
All right.
So, now I'm going to actually launch the O module and we're going to watch it run.
Looking back in at some chat, people continuing to talk about exceptions.
Is it all handled by Riverpod or server pot or some other other tool? Can you
talk about migrations and how you handle them? Ah yeah yeah yeah okay so um and
them? Ah yeah yeah yeah okay so um and then is are migrations handled by server pod or some other tool? Yeah so that it's all it's all server pod you can see
some answers here in the chat actually all server pod CLI does it. Yep. Yep.
Yep. Yep. So great. Um, and then when you, you know, you have to apply the migrations when you run your app at some point, which of course like if you're deploying to Cloud Run, you don't want
to have d-apply migrations on every wake up because they can kind of get in each other's way. Uh, so there's actually a
other's way. Uh, so there's actually a little bit of thinking about like when you apply the migrations versus you deploy the code versus you have like all your new servers wake up. Always a
little tricky.
So what's the next thing I need to do? I
need to launch the off example app and see it work. That's what I need to do.
So in docker compose I can see here the connection to the development
uh database and this is what I need. So
first I'm going to actually launch this database by saying podman compose.
Podman is just like an open source version of docker up and disconnect or detach or whatever.
So while it thinks I can switch back to Postico and add a new server, which I said I was
going to do earlier, never did. So this
will be server pod off example and the host is localhost and the port we can see right there is 8090 being mapped internally to the typical
Postgress port. And then these are the
Postgress port. And then these are the other values I need. So I'll grab this hot password and the host is definitely localized.
The database is off and the user is Postgress. So I will test that
Postgress. So I will test that connection and it works. Wonderful.
Connect empty database as expected.
So now that all of the Docker containers are running, I can finally say, and what I just warned against as a bad idea in
production is just fine in development.
So I will say dart bin main.dart dash
apply migrations.
And this should wake up and make all of our tables.
which it didn't do. So, password is missing for database. Okay, let me grab this password and that would be in config.
Oh, why don't I have passwords?
Yeah, there it is. Interesting.
Oh, I've made that change locally.
So I will copy uh this is config template to passwords.myl.
Okay. And now we try again.
Still broken. Missing a password for database. So we are
database. So we are Oh, I'm so silly. Oh, that's so silly. I
look at my look at my copy command. Copy
config slash to no config. No config.
So, move passwords to config. And then
it'll keep the file name.
This time, this time it's going to work.
I can feel it.
Okay. It broke for a different reason which is kind of like oh Google client J. Yeah, I don't actually want to do
J. Yeah, I don't actually want to do this. I'm only going to going to not do
this. I'm only going to going to not do that. So that's fine
that. So that's fine because the off example is set up to have configured
Apple and Google login. But I don't really want to go through those trouble that trouble right now because I'm not doing that.
So, is this file?
Whoa.
I'm unfamiliar with what is different about this file.
Okay. Wait, what's in main dart?
And this one. Yeah, it's not using the passwords file. Okay, I won't either
passwords file. Okay, I won't either then.
All right. All right. So, what I need to do here is basically just comment out Google and Apple because I'm not going to configure them and then they are going to rightly complain.
So, there we go. And email, that's fine.
Password. Oh, pass key IDP config.
That's probably fine.
Anonymous config. There we go. That's
what's up. That's new. Now, we have to get rid of this. This is Apple.
All right, that sounds better.
All right, we try again.
Try again.
Look at that. Applied the migrations.
Can't be stopped, folks. Can't stop him.
Can only hope to contain him.
So uh yeah, let's look at this in postco tables and they should include you know there's no app specific tables here because the only thing in this app is
the framework and the off module. So
they're all server pod tables but we have anonymous account.
Boom.
Okay. Now, now for my fourth trick, I will open a new terminal and in this I
can go into examples of flutter and say flutter rund chrome and this
is going to uh I'll think of the words. Yeah, launch
the app and we'll be able to create anonymous accounts and refresh the page and continue to be logged in as those anonymous accounts
and we will see the expected records in the database.
Isn't it fun?
Scanning. Oh, there it is. I was about to say scanning for where the window pops up and it was right in my face.
So, here we go. We've got a new continue without account button at the bottom. So
this whole widget here is the uh what am I thinking? This whole widget is the like signin widget that server pod
provides and you can incrementally turn off things if you like don't use them.
actually a little surprised that Apple and Google didn't get hidden when I removed those things from the server, but it's possible that they
I needed to like run server pod generate again or something. I'm not really sure, but that's not today's headache. So,
when I click this button, nothing happens. Awesome.
nothing happens. Awesome.
What's going on?
Literally nothing happened. Hello.
Wow. It's just totally silent.
So, here's the server running with no output, right? Yeah. No. Okay. Good. And
right? Yeah. No. Okay. Good. And
nothing. Uh.
Huh.
Wasn't expecting that. Um, lib
main.
All right, let's check this out.
Be pretty embarrassing to submit an off PR. try to merge an offbr where the
PR. try to merge an offbr where the button in the main off-the-shelf widget doesn't work.
Okay, so nothing crazy going on here. So
this signin widget is over in the off IDP thing in the Flutter portion. So if
I look here, we've got, you know, yeah, disable is is not set for anonymous, which makes sense because we saw the button. So has anonymous.
button. So has anonymous.
So, if has anonymous, this is our thing.
So, we get into the anonymous sign-in widget and the anonymous sign-in widget should have a button.
Yeah, here it is. So, on pressed controller login. So, let's check out
controller login. So, let's check out the anonymous off controller.
And in the login method, we see I wonder if there's a problem with like this guarded wrapper.
Interesting. Uh
oh, I was Oh, yeah. Okay, this is probably the problem. This is why we test things.
This was a very recent code review that I don't think I actually executed. So
to one day guard against abuse on this, we're planning on adding like app attestation, which you could typically get from Firebase app check,
but you wouldn't want to have Firebase as a dependency just for app check. So
we want to be able to have app attestation in server pod directly. So
that's this anonymous token call thing.
But this bang is giving me some hebiejibbies because I'm not configuring that yet. So now I'm wondering is there like a default noop
function.
So create anonymous is nullable and yeah okay I don't know what on earth anyone was thinking when they had this. So token now could be yeah
had this. So token now could be yeah it's a nullable string. Wonderful. This
is probably better.
So, let's restart the the front end app.
Let's try this again. Continue. Look at
that. Look at that. So, now we go to the database.
Excuse me. Probably should have turned my head in the anonymous table. We have
a record and it points to a user. And critically,
if I refresh the page, we stay logged in.
Nice.
And this button is poorly set up. It someone
who added this to the example would like assumed you were signing in with Google or something. It's like this doesn't
or something. It's like this doesn't make sense for us. And if you uh yeah, sign out, that account is basically gone. So, it does still exist in the
gone. So, it does still exist in the database. It doesn't get deleted, but
database. It doesn't get deleted, but there's no way to recover it. That's the
nature of an anonymous account. So I'll
sign in again. We have a new anonymous account which is extremely exciting. And
if I look at yeah core user, we see that two users have been made. They each had a very exciting empty profile.
I always like to drag the created at time stamp in my database viewer all the way to the right. They each had a token
which is one of these things. Uh,
where's the token table? I don't know.
Oh, session. That's it. Oh, there's only one session. Maybe when I logged out
one session. Maybe when I logged out that session did get deleted. Let's try
that again. Sign out. Yes, that makes sense. Boy, does that actually make
sense. Boy, does that actually make sense.
Okay, so um can we show what guarded does?
Somebody asks. Yeah. So this is honestly a really really really well engineered um
thing this whole off module and there's like no repeated code anywhere. So guarded
is a little closure wrapper down here that uh catches errors and converts them to userfacing errors.
So you might throw you know your server might not understand what server oh like what is a userf facing error uh or it needs to be localized or you know
there's just something exception problems that are not the server's problem and so uh this kind of manages state updates and catches errors and converts them to userfacing errors.
That's what guarded does. Just a custom little thing, but it's all over this app module and and this big widget and it it's a it's a definitely a good pattern.
Um, so yeah, there we are. Now, this is funny. When I look at the stream, I have
funny. When I look at the stream, I have YouTube open so I can just look at chat easily. Um, I'm seeing a video feed
easily. Um, I'm seeing a video feed that's very, very old. So, I don't actually know how the world works. That
is for sure.
Uh F12 for logs. No me says I don't I've never pressed F12 for logs.
Where where would I press that? In what
window?
Uh someone asked is this cure editor?
No, it's anti-gravity which is absolutely my new favorite.
Although somebody's saying anti-gravity slows down my Apple silicon Mac while doing native iOS dev uh Google team please fix interesting. Um so in anti-gravity there
interesting. Um so in anti-gravity there is a way to submit feedback which is where uh settings no maybe
anti-gravity user settings there's a place to submit feedback. Oh here it is bottom left here. So,
open anti-gravity person who's having this problem.
Click this gear. Go into open anti-gravity settings. A new window pops
anti-gravity settings. A new window pops up. Bottom left of that window. Provide
up. Bottom left of that window. Provide
feedback. Here is where you write this slows down my silicon Mac when I do native development. And then uh provide
native development. And then uh provide any other information you can. And
that'll be great. And then attach your logs. I guess this is not a real bug
logs. I guess this is not a real bug because I'm not doing native development. This is not slowing down my
development. This is not slowing down my computer. So, I'm not going to click
computer. So, I'm not going to click submit, but you should.
All right. So, I now think that this is ready to submit. I don't think anything that I
to submit. I don't think anything that I just changed should impact any of the tests that exist for this library or this PR. So, I am going to commit all of
this PR. So, I am going to commit all of this goblygook and push. No, I am not going to commit commenting out
um Apple in Google from server.dart
and I think here I can just revert.
Yeah, I'm going to check out this file.
So revert.
Okay. Yeah, we don't want to commit that uh scanning. This is mostly migration
uh scanning. This is mostly migration nonsense and my one little change here.
So I'm going to commit And now I'm going to say uh rebases migrations commit and push.
Exciting, huh? Exciting stuff.
Do you like well structured software like server pod, spring boot or uh write the whole workflow by yourself? Oh boy,
well ststructured code for sure. There's
Django before similar. Um
it's you got to use you got to use a good framework for sure. You don't want to write it all yourself. You'll be here all day reinventing the wheel. Totally.
Especially with open source things where if you do discover a limitation, you could, you know, fork it or submit a PR or whatever.
Like I've been doing a fair amount of work to add anonymous off to serverbot, but it ain't nothing compared to reinventing Serverbot.
So I'm still way way ahead even though it had a limitation for my purposes.
Okay. So now let's go back to this PR. So this I think these are good.
this PR. So this I think these are good.
Add a new test. Yeah, that's true.
Existing tests. Well, they were before.
We'll see. Uh updated docs. I've not
updated the docs.
All right. So this should have no git.
What? There's another one. Oh, I
needed to run server pod generate.
Yeah. Yeah, I needed to run server pod generate. So, I'll do that and then
generate. So, I'll do that and then push.
Is that right?
Is that the problem? That's probably the problem.
Where is this directory? This is in a test. Didn't have the issue there.
test. Didn't have the issue there.
Surprisingly, why didn't it have the issue there?
Justin off and the example. Interesting.
Okay. So, in the server, I'm going to this is in the example of the server.
I'll say server pod generate.
And then I'm going to do the same in the project itself.
CD modules off IDP server
server pod generate. Oh, the last one didn't even make any changes.
This one did.
Okay. Okay.
Interesting.
Ran server pod generate get push.
Let's see here now. What do we get? It
should presumably still have the mer.
Why?
Wait, why would that be the case? I
wonder if somebody else forgot to run generate. Now, I think they have CI to
generate. Now, I think they have CI to make sure that generate doesn't change anything. All right, I'm going to leave
anything. All right, I'm going to leave this alone for now.
I'll talk with Server Pod team later about figuring out what's going on here.
I don't think that's going to make the best television.
So, instead, let's look at the next PR and the next feature, the next part of phase two. So, we got like phase 2.1
phase two. So, we got like phase 2.1 already in flight and then uh it'll be
time to think about phase 2.2, which is not really spelled out.
What did I even write? I should make sure this is updated. Okay, so new methods will be added to durable IDPS.
That's like not anonymous. A durable IDP is one that you can just log out of and back into, which will attach new providers to the existing O user record.
This user may or may not be anonymous.
Yeah. So this is the part two. That's
what's upcoming next. So before writing new blah blah blah records, the linking flow must first check. Right. So this is all stuff to come next. So I'm going to
call this phase 2.2.
And I'll indent it. Maybe that seems like a thing someone might do. And then
we'll have phase 2.1.
And this is going to add new methods to durable IDPS to look up whether or not a given uh no just the active user whether
or not the active user currently has accounts uh add new methods
to look up whether or not the active user currently has accounts with durable IDPS.
This is required for the front end to conditionally
render like add apple off buttons etc. because of course you don't want to show that button if the user already has Apple and an anonymous user is going to
need to add like one of these things eventually. But even somebody who like
eventually. But even somebody who like maybe came in from email and password off they might one day want to add a pass key or they might want to add Apple or Google uh off. So like I think everybody is going to need this
regardless of whether or not somebody cares about anonymous off. So that is phase 2.1 and I'll add a link to the PR
for that which is somewhere.
Uh it's this one add connected IDPs lookup.
So let's see here. This is um PR.
I guess I'll add this PR for phase one.
I'm not normally this organized.
You should uh not mistake me for this.
You should instead know that I'm a conjurer of cheap tricks.
Oh, wait. Oh, can Oh, yeah. Yeah. Yeah.
Okay. Yeah. This feature is a component of phase 2, right? Okay. Sorry, I
thought I had the wrong tab for a second. Which relates linking IDPs to
second. Which relates linking IDPs to existing accounts.
And there's some maybe bold changes that I'm proposing in this PR, including
adding uh actually let's start to look at how some of the server pod code works and then this will make a little more sense. So
I'm not checking out this PR yet. We're
still on the kind of old PR for just adding anonymous off. and let's look at how this works.
So in IDP server pod um we have
let's close some of these other files in IDP server pod or sorry um underscore server there are in the lib directory this providers folder
which just has these are like barrel files actually so I'll get rid of that and then under source there's There's a providers directory with similar looking
folders and I've added anonymous. So
let's check this out. So to start in server pod you write an endpoint but endpoints are not you know
endpoints are like attached to network stuff and for testing you basically want to pretend the network layer doesn't exist. So kind of the idiomatic thing to
exist. So kind of the idiomatic thing to do in server pod is to immediately delegate to a different function.
And it's kind of funny because you pass this session in. So you know you're only like so separated from HTTP things but
um anyway that's the pattern. So there's
an anonymous IDP class that the endpoint makes use of and the anonymous endpoint merely extends
like generic endpoint. So now let's look at the anonymous IDP class and the anonymous IDP class does not subclass anything which is part of what
I'm proposing to change which is of course a thing that needs to be considered carefully before it's just adopted.
And because there was only one method.
You know, other ones have like a lot of methods and so their classes are more advanced. Anonymous is very simple. You
advanced. Anonymous is very simple. You
just create something. So here we have the login method and it uh you know calls any like
um con functions you configure. So this
one would check for app att testation if you have it and then it ultimately creates an account and you know you're kind of using these other classes that uh again get you kind of further and
further away from the network layer so you can just have isolated unit tests later on or even like isolated integration tests because with server side stuff you want to talk to a database and it's not that useful to
prove to yourself that your code worked absent a database anyway uh create a user profile blah blah blah issue a token. Everything's
exciting. So, this is like how this works. Just for some
works. Just for some or just to kind of close this loop a little bit more, look at email, which is probably the most complicated one
because you got to like get a um verification token sent to your email.
Then you grab that and you put enter the thing in and there's all kinds of security around that. Anyway, so the endpoint for email has more functions.
It ultimately has login, same as the other one. Start registration,
other one. Start registration, verify that code, finish registration, a password reset. Obviously, that's, you know, annoying. Verify the password
know, annoying. Verify the password reset code. It's like this one's way
reset code. It's like this one's way more complicated and it's IDP class has similarly more functions. So, anyway,
that's that. So what I'm proposing in the other PR is that each IDP needs to be able to
answer the question, does a user have an account with this provider? And
what I think makes sense to do is to have an abstract IDP class. Again, this
might be a bad idea. I'm talking about this server pod folks might be like, "Dude, never." and that'll be fine. But
"Dude, never." and that'll be fine. But
my initial naive proposal here is that we have an abstract IDP class that forces all IDPS to a to implement this function has account
and yeah get method was like used for someone else somewhere which is that that part's super simple but anyway because like this would
return the string apple or Google or email or something so dead simple. Um, I
think it was just a limitation of like static methods on abstract classes or static properties on Yeah. Yeah, that's
what it said. Great. Anyway, so if all IDPs are required to have this function which has the exact same signature, then a configured like there could be one
endpoint that loops over all of your configured IDPS and it just calls this method for a given user and is able to return to the front end in one network call. It's like, you know, because you
call. It's like, you know, because you as a server pod developer might add your own IDP. You know, maybe you do want a
own IDP. You know, maybe you do want a password link or SMS or something and that's really important to you and so you add it and you'd probably kind of like this functionality that we're talking
about to be like wired into the O packages single network request to answer the question does which IDPs does the user already have something configured with.
So the only way that you external server pod developer or like me in the future could get your custom IDPS
included in that is if they participate in this contract. So anyway, it's a proposal and then uh you get an endpoint here that basically just figures out what the
accounts are. It's kind of different
accounts are. It's kind of different from anything else. And here we can see that it's going to loop over all of the identity providers. And if any of the
identity providers. And if any of the providers aren't subclassing the IDP, then we'll just kind of note, hey, they're not going to be able to answer this question. But for the other ones,
this question. But for the other ones, we're going to call their has account method and then we can return the answer to that, which I'm apparently having as
a set of strings. So you'd return like Apple, Google, blah blah blah. I don't
think you really want to return more data about those accounts. don't want to like accidentally leak something.
So there's that. And then uh Apple IDP is made to extend it and it implements this method uh has account and it
ultimately just delegates to another thing like we were seeing.
Um so what does have a has account or get account sorry looks like? Oh yeah.
Yeah. So has account is the external facing thing but internally like get account I think makes more sense because internally you'd want to actually see data about it. So get account
merely looks up in the Apple account table like is there something for the authenticated user easy and if you're not authenticated then you don't have an
account.
Uh same for email and same for Google and I I think I added it for pass key as well if I scroll down. Yeah, pass key. I
don't even really know how pass keys work, but that doesn't it's not important because it's consistently abstracted. So, this is the PR that is
abstracted. So, this is the PR that is waiting in the wings.
And now I'm going to look at chat because I haven't done that in forever.
Um, yeah, Randall says, let me get Randall says, "It's hard to know when to delete an anonymous user account." Yeah,
indeed. Um, I mean, I think you probably wouldn't delete the account when someone logs out because like maybe they could call your customer support and rattle off every action they ever took and prove that they were that
account and then you might have some backend process to like restore it for them. But
them. But short of that workflow, you could delete like everything, but then you you would be deleting any work that they did on that account. It would be totally
that account. It would be totally unreoverable. So, be could feel a little
unreoverable. So, be could feel a little harsh.
I'm gonna bring this here. Can everybody
uh look at it while I'm Oh, wow. This
got stuck.
All right. Well, then I'll just uh look at it from YouTube itself and talk about chats, but they won't be able to go up on the screen.
All right. Scrolling up.
Did I take part in the serverbot hackathon? I thought about it, but I was
hackathon? I thought about it, but I was working on this and I have a game that I've been working on, which is like not really hackathon stuff because it's a for real project. So, I didn't want to take on a new thing, but I absolutely
thought about it. I kind of thought about streaming some of it during the holiday break, but instead I played video games. I've gotten into Boulders
video games. I've gotten into Boulders Skate 3.
Whoa, why didn't anyone tell me about this? What a fun game.
this? What a fun game.
Uh, let's see. What else are folks talking about?
Oh yeah. So, deleting users, you mostly Randall says, "You mostly just have to write a job repeating somewhere to delete everything every 10 days or so."
Yeah, especially like if it hasn't logged in in a while or something. Um,
Estidiani says, "Do you have some use cases?" I
don't know what I was talking about when you wrote that. What were the use cases you were asking about?
Or maybe you were talking with Randall.
Uh, Rand says, "Or however long a session makes sense because when a session is gone, it'll never use again."
Yep, makes sense.
Says, "Didn't upgrade to Mac OS Tahoe."
Oh, wait. I thought I had to upgrade. I
think I did. I don't know. I'm not sure if you're talking about me or somebody else, but I was forced to upgrade. I do
regret updating my phone, though. That
I'm I'm on Sequoia. Am I really on Sequoia?
Oh, maybe I was a whole year behind when I had to update.
uh about this Mac.
Sequoa, you guys are right.
I didn't even realize I was behind. It's
not good. You guys, the Do you folks recommend it? I don't like the new iOS
recommend it? I don't like the new iOS version.
I try not to make disliking stuff part of my personality. I I don't run around hating on things very often. Um the
trees, right? Actually, I think I got I was a year behind because I had to update recently. I was on whatever was
update recently. I was on whatever was before Sequoia because I used to have the Flutter background and then the update I got this background and I just didn't think about changing it. Anyway,
I do not like the new iOS version and I had to update that to connect to work things.
I'm so sad about it. I haven't disliked anything that much in a long time.
It is not my thing. Um
anyway, all right. What uh
all right. What uh what what makes sense to do next?
I could begin adding the linking code. So if we go back to the plan, you
code. So if we go back to the plan, you got to stick to the plan of course. New
methods will be added to durable IDPs which attach new O providers to an existing O user record. This may or not may or may not be anonymous. Yeah, this
user may or may not be anonymous.
So before writing and then there's merge conflict and like that's a whole ball of uh wax as well. So let me read what I wrote here. See if it still makes sense.
wrote here. See if it still makes sense.
Before writing these new records, the linking flow must first check for those unique user identifiers in the appropriate database tables. If they
exist, the standard linking flow is aborted and a merge flow is triggered again. And this is why anonymous
again. And this is why anonymous accounts are so painful is this sentence right here. It's actually two sentences.
right here. It's actually two sentences.
If I put on my counting hat, which I was instructed not to do, they say don't don't do the do math on stream. This
merging flow will call a new and optional merge accounts method which a developer would configure and that's how you as a serverod developer would like if the anonymous account took some
actions and you want to persist those and merge them into their other account um you know you handle that here. So the
the user journey that this merge checking is accounting for is let's say like on one device you have an account a proper
email Apple google whatever pass key account with some app using server pod and then on a different device you re you know either redownload the app or
you go to the website or whatever and you take some action before you realize you're not logged in you like take some action that creates It's an anonymous account probably transparently in the background. It's generally how that
background. It's generally how that works. And then you're like, "Oh, wait.
works. And then you're like, "Oh, wait.
Where's all my other stuff? Oh, I'm not logged in." But you like did something
logged in." But you like did something that's important. You know, maybe what
that's important. You know, maybe what you did is throw away, but like maybe it's not. Maybe it was, you know, maybe
it's not. Maybe it was, you know, maybe you like wrote a long document or something and you want it persisted.
So then you're like, "Oh gosh, I got to log in to my account." So you try to log
in to your email account and what basically happens there is during the login flow it realizes like wait a logged in user
is trying to loged in is trying to log in and uh actually you'd probably just see like add I'm not really sure what makes the most sense here because right
you're logged in and the user's mental model is that they're not logged and like they just created an anonymous account on accident and so they're seeing that their other user data isn't present is why anonymous accounts are
such a pain to build but they're very actually user friendly in my opinion.
So, I'm a user. I don't know that I've just created a session. I want to restore my email session.
If I see, you know, I got two buttons that the app could show me. Could say
login with email and password, which would probably make more sense to me, the user, or it could say add email
and passwords to your account, like link email and passwords. And
if I saw that, I would probably think like, well, something's wrong. I don't I wouldn't I don't want to link email and password to my account. I want to go
back to my main account. So, I think probably this is like a thing that an app using anonymous accounts would need to handle. And I don't think it's the
to handle. And I don't think it's the off module's job to figure out kind of which of these buttons to show. But
anyway, obviously comp complexity abounds and then in either rate at some point you're going to
like try to log in again or whatever and you're going to be if you're logging in to email but you're already authenticated and you're anonymous then
like the merge flow kicks in. Or
probably more likely is like Apple and Google because they don't really have a create versus login distinction. and you
just like click the sign in with Google not Apple button and it's just this kind of opaque flow and at the end you're logged in and so that
if I'm a user that's created an an anonymous account I click the button I'm probably less thrown off because the text doesn't seem wrong it just says sign in with Google or Apple or whatever and I'm like yeah that's what I want to
do so I click the button and then the server really has to say like whoa you're logged And so we have one user account, but the Google or Apple
credential that we just received is definitely attached to a different account. So now it's merge time.
account. So now it's merge time.
So it's fun.
Uh Randall says linking doesn't solve the data merge problem. H what uh what are you thinking in that direction,
Randall? What makes that true?
Randall? What makes that true?
So, a lot of things will just not let you say, "I wonder how Reddit has this anonymous off system." A lot of things don't let you take actions until you log
in. So, like if you're anonymous in
in. So, like if you're anonymous in Reddit, can you like a post? Can you
like download a post? Probably not. You
know, normally you are required to um log in before you can take those actions.
I have not visited Reddit unauthenticated in a very long time. So
I don't know what it does.
Uh Sy says, "Is there an option in Surfpopod to convert an anonymous account to a normal one with any of the providers?" So that is exactly what I am
providers?" So that is exactly what I am looking to add because they didn't have anonymous provider so they don't have the conversion thing.
Um let's see.
Uh Randall says, "I realize you'd need data merge anyway, so it would have to be solved already."
I think we're probably both thinking about this clearly, but I'm I'm not quite following the statements you're making.
Do you have any source recommendation for animation in Flutter other than the official videos docs? Uh well, there's probably really darn good third party
explanations of animations. There's also
the Flutter animate package. That's
really good. And there used to be some package that was used to daisy chain animations, but I can't remember what it was called. And last time I looked for
was called. And last time I looked for it, I couldn't find it.
Actually, someone here right now probably knows. Oh, hey. Um, we got
probably knows. Oh, hey. Um, we got actual server pod team members in the chat. So, we're going to have Firebase
chat. So, we're going to have Firebase soon. Nice. There's probably a PR for
soon. Nice. There's probably a PR for that that we could look at and track the progress of.
I would click your message, but my message clicker froze.
Um, let me go back to this.
Let's see if there's a PR for adding Firebase.
All right. may be going by a different name or may not be on the first page of oh I'm on issues.
Never underestimate my ability to do something stupid.
I had Firebase IDP. Look at that. There
it is. This probably a huge project.
Anyway, yeah, this will be uh Oh, I wonder we should maybe make sure our wires are not crossing on
anonymous accounts because Firebase has anonymous accounts as well. And
depending on how this is being implemented, it's probably not going to conflict. I would guess an anonymous
conflict. I would guess an anonymous Firebase account or like an Apple or Google Firebase account. If they look the same to Server Pod, then we'd be
fine.
So, yeah, we should talk about that.
All right. Um,
I don't know if I really think it makes sense to work on this new like the next phase. Right now, it's a
phase. Right now, it's a I like sit down and think very slowly about this.
So, I'm not even sure what I would type.
Randomly said, "So, if I do something as anonymous while I'm still logged in, I'd want to link. There'd be a data merge."
Yeah, I still I think we're probably saying the same thing.
Uh, Predic says, "Hi, I'm Predic. I'm a
Flutter developer. Can you answer a few of my questions?"
Um, well, if you ask them, maybe. And
yeah, as Rand says, there's a Discord and also just yesterday, you missed it, hump day Q&A, but in six more days there'll be another episode probably. So
that's a great place to ask questions.
But if you don't want to wait six days, you can either ask them here or go to the Discord.
Uh it shouldn't conflict since we're using ID tokens to log in. So it's just another provider. Yeah. So that makes
another provider. Yeah. So that makes sense. Doesn't really care about how you
sense. Doesn't really care about how you logged in with Firebase. Yeah, makes
sense. Good. Awesome.
So it's like once you come from Firebase, great. However Firebase
Firebase, great. However Firebase figured out who you are, you know, that was Firebase's problem.
That that that seems good. All right. Uh
well, folks, I think I am going to call it here because way more like slow thinking is required to figure out what I would even type next than I think
would make again like I said earlier, it would make good television. So, I going to call it for now. I do expect to be back next week. I have a couple guests
starting to get lined up into later January, early February, so we'll have some fun topics. Um, let me know what you thought about this episode kind of contributing to an open source
library. I didn't really write a lot of
library. I didn't really write a lot of code. We mostly just talked and I fixed
code. We mostly just talked and I fixed a couple things and like ran some CLI commands. So, it was a different kind of
commands. So, it was a different kind of episode than other ones. But yeah, let me know what you all thought and that'll impact the extent to which I do the same
in the future.
So, uh, thanks everybody and until next time, happy fluttering.
Loading video analysis...